forked from saracen/go7z
/
streams_info.go
143 lines (117 loc) · 3.07 KB
/
streams_info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package headers
import (
"io"
)
// StreamsInfo is a top-level structure of the 7z format.
type StreamsInfo struct {
PackInfo *PackInfo
UnpackInfo *UnpackInfo
SubStreamsInfo *SubStreamsInfo
}
// ReadStreamsInfo reads the streams info structure.
func ReadStreamsInfo(r io.Reader) (*StreamsInfo, error) {
streamsInfo := &StreamsInfo{}
for {
id, err := ReadByte(r)
if err != nil {
return nil, err
}
switch id {
case k7zPackInfo:
if streamsInfo.PackInfo, err = ReadPackInfo(r); err != nil {
return nil, err
}
case k7zUnpackInfo:
if streamsInfo.UnpackInfo, err = ReadUnpackInfo(r); err != nil {
return nil, err
}
case k7zSubStreamsInfo:
if streamsInfo.UnpackInfo == nil {
return nil, ErrUnexpectedPropertyID
}
if streamsInfo.SubStreamsInfo, err = ReadSubStreamsInfo(r, streamsInfo.UnpackInfo); err != nil {
return nil, err
}
case k7zEnd:
if streamsInfo.PackInfo == nil || streamsInfo.UnpackInfo == nil {
return nil, ErrUnexpectedPropertyID
}
return streamsInfo, nil
default:
return nil, ErrUnexpectedPropertyID
}
}
}
// SubStreamsInfo is a structure found within the StreamsInfo structure.
type SubStreamsInfo struct {
NumUnpackStreamsInFolders []int
UnpackSizes []uint64
Digests []uint32
}
// ReadSubStreamsInfo reads the substreams info structure.
func ReadSubStreamsInfo(r io.Reader, unpackInfo *UnpackInfo) (*SubStreamsInfo, error) {
id, err := ReadByte(r)
if err != nil {
return nil, err
}
subStreamInfo := &SubStreamsInfo{}
subStreamInfo.NumUnpackStreamsInFolders = make([]int, len(unpackInfo.Folders))
for i := range subStreamInfo.NumUnpackStreamsInFolders {
subStreamInfo.NumUnpackStreamsInFolders[i] = 1
}
if id == k7zNumUnpackStream {
for i := range subStreamInfo.NumUnpackStreamsInFolders {
if subStreamInfo.NumUnpackStreamsInFolders[i], err = ReadNumberInt(r); err != nil {
return nil, err
}
}
id, err = ReadByte(r)
if err != nil {
return nil, err
}
}
for i := range unpackInfo.Folders {
if subStreamInfo.NumUnpackStreamsInFolders[i] == 0 {
continue
}
var sum uint64
if id == k7zSize {
for j := 1; j < subStreamInfo.NumUnpackStreamsInFolders[i]; j++ {
size, err := ReadNumber(r)
if err != nil {
return nil, err
}
sum += size
subStreamInfo.UnpackSizes = append(subStreamInfo.UnpackSizes, size)
}
}
subStreamInfo.UnpackSizes = append(subStreamInfo.UnpackSizes, unpackInfo.Folders[i].UnpackSize()-uint64(sum))
}
if id == k7zSize {
id, err = ReadByte(r)
if err != nil {
return nil, err
}
}
numDigests := 0
for i := range unpackInfo.Folders {
numSubStreams := subStreamInfo.NumUnpackStreamsInFolders[i]
if numSubStreams > 1 || unpackInfo.Folders[i].UnpackCRC == 0 {
numDigests += int(numSubStreams)
}
}
if id == k7zCRC {
subStreamInfo.Digests, err = ReadDigests(r, numDigests)
if err != nil {
return nil, err
}
id, err = ReadByte(r)
if err != nil {
return nil, err
}
}
if id != k7zEnd {
return nil, ErrUnexpectedPropertyID
}
return subStreamInfo, nil
}