diff --git a/chrome-session-dump.go b/chrome-session-dump.go index 0bcc369..9e4f7c6 100644 --- a/chrome-session-dump.go +++ b/chrome-session-dump.go @@ -48,6 +48,7 @@ const ( kCommandSetTabGroup = 25 kCommandSetTabGroupMetadata2 = 27 kCommandSetSelectedNavigationIndex = 7 + kCommandSetWindowUserTitle = 31 kCommandTabClosed = 16 kCommandWindowClosed = 17 kCommandSetTabIndexInWindow = 2 @@ -56,9 +57,12 @@ const ( ) type group struct { - high uint64 - low uint64 - name string + + high uint64 + low uint64 + name string + color uint32 + collapsed bool } type window struct { @@ -66,6 +70,8 @@ type window struct { id uint32 deleted bool tabs []*tab + tabGroups map[string]*group + userTitle string } type histItem struct { @@ -91,16 +97,20 @@ var groups = map[string]*group{} func getWindow(id uint32) *window { if _, ok := windows[id]; !ok { - windows[id] = &window{id: id} + windows[id] = &window{id: id, tabGroups: map[string]*group{}} } return windows[id] } +func getGroupKey(high uint64, low uint64) string { + return fmt.Sprintf("%x%x", high, low) +} + func getGroup(high uint64, low uint64) *group { - key := fmt.Sprintf("%x%x", high, low) + key := getGroupKey(high, low) if _, ok := groups[key]; !ok { - groups[key] = &group{high, low, ""} + groups[key] = &group{high, low, "", 0, false} } return groups[key] @@ -114,6 +124,21 @@ func getTab(id uint32) *tab { return tabs[id] } +func readBool(r io.Reader) bool { + var b [1]byte + if n, err := r.Read(b[:]); err != nil || n != 1 { + if err != nil { + panic(err) + } + if uint8(b[0]) > 1 { + panic(fmt.Errorf("Failed to read bool as 0 or 1.")) + } + panic(fmt.Errorf("Failed to read int8.")) + } + + return uint8(b[0]) == 1 +} + func readUint8(r io.Reader) uint8 { var b [1]byte if n, err := r.Read(b[:]); err != nil || n != 1 { @@ -223,18 +248,29 @@ type Result struct { } type Tab struct { - Active bool `json:"active"` - History []*HistoryItem `json:"history"` - Url string `json:"url"` - Title string `json:"title"` - Deleted bool `json:"deleted"` - Group string `json:"group"` + Active bool `json:"active"` + History []*HistoryItem `json:"history"` + Url string `json:"url"` + Title string `json:"title"` + Deleted bool `json:"deleted"` + Group string `json:"group"` + GroupColor uint32 `json:"groupColor"` + GroupCollapsed bool `json:"groupCollapsed"` +} + +type TabGroup struct { + Name string `json:"name"` + Color uint32 `json:"color"` + Collapsed bool `json:"collapsed"` } type Window struct { - Tabs []*Tab `json:"tabs"` - Active bool `json:"active"` - Deleted bool `json:"deleted"` + Tabs []*Tab `json:"tabs"` + TabGroups []*TabGroup `json:"tabGroups"` + Active bool `json:"active"` + Deleted bool `json:"deleted"` + Name string `json:"name"` + UserTitle string `json:"userTitle"` } type HistoryItem struct { @@ -334,9 +370,14 @@ func parse(path string) Result { high := readUint64(data) low := readUint64(data) - name := readString16(data) - getGroup(high, low).name = name + color := readUint32(data) + collapsed := readBool(data) + + group := getGroup(high, low) + group.name = name + group.color = color + group.collapsed = collapsed case kCommandSetTabGroup: id := readUint32(data) readUint32(data) //Struct padding @@ -350,6 +391,12 @@ func parse(path string) Result { id := readUint32(data) getTab(id).win = win + case kCommandSetWindowUserTitle: + readUint32(data) //size of the data (again) + id := readUint32(data) + title := readString(data) + + getWindow(id).userTitle = title case kCommandWindowClosed: id := readUint32(data) @@ -398,16 +445,28 @@ func parse(path string) Result { var Windows []*Window for _, w := range windows { - W := &Window{Active: w == activeWindow, Deleted: w.deleted} + W := &Window{Active: w == activeWindow, Deleted: w.deleted, UserTitle: w.userTitle} idx := 0 for _, t := range w.tabs { groupName := "" + groupCollapsed := false + groupColor := uint32(0) if t.group != nil { + groupKey := getGroupKey(t.group.high, t.group.low) groupName = t.group.name + groupCollapsed = t.group.collapsed + groupColor = t.group.color + w.tabGroups[groupKey] = t.group } - T := &Tab{Active: idx == int(w.activeTabIdx), Deleted: t.deleted, Group: groupName} + T := &Tab{ + Active: idx == int(w.activeTabIdx), + Deleted: t.deleted, + Group: groupName, + GroupColor: groupColor, + GroupCollapsed: groupCollapsed, + } for _, h := range t.history { T.History = append(T.History, &HistoryItem{h.url, h.title}) @@ -424,6 +483,16 @@ func parse(path string) Result { } } + for _, tg := range w.tabGroups { + TG := &TabGroup{ + Name: tg.name, + Color: tg.color, + Collapsed: tg.collapsed, + } + + W.TabGroups = append(W.TabGroups, TG) + } + Windows = append(Windows, W) }