@@ -107,19 +107,84 @@ bool Replay::OpenReplayFromBuffer(std::vector<uint8_t>&& contents) {
107
107
}
108
108
if (pheader.base .flag & REPLAY_COMPRESSED) {
109
109
size_t replay_size = pheader.base .datasize ;
110
- auto comp_size = contents.size () - header_size;
111
- replay_data.resize (pheader.base .datasize );
110
+ size_t comp_size = contents.size () - header_size;
112
111
replay_data.resize (replay_size);
113
- lzma_filter filters[]{
114
- { LZMA_FILTER_LZMA1, nullptr },
115
- { LZMA_VLI_UNKNOWN, nullptr },
116
- };
117
- if (lzma_properties_decode (filters, nullptr , pheader.base .props , 5 ) != LZMA_OK)
112
+
113
+ const auto fake_header = [&]() {
114
+ /* the lzma header consists of :
115
+ 1 byte LZMA properties byte that encodes lc/lp/pb
116
+ 4 bytes dictionary size as little endian uint32_t
117
+ 8 bytes uncompressed size as little endian uint64_t
118
+
119
+ with the first 5 bytes corresponding to the "props"
120
+ stored in the replay header
121
+ */
122
+ std::array<uint8_t , sizeof (uint8_t ) + sizeof (uint32_t ) + sizeof (uint64_t )> header;
123
+ memcpy (header.data (), pheader.base .props , 5 );
124
+ header[5 ] = (pheader.base .datasize >> 8 * 0 ) & 0xff ;
125
+ header[6 ] = (pheader.base .datasize >> 8 * 1 ) & 0xff ;
126
+ header[7 ] = (pheader.base .datasize >> 8 * 2 ) & 0xff ;
127
+ header[8 ] = (pheader.base .datasize >> 8 * 3 ) & 0xff ;
128
+ header[9 ] = 0 ;
129
+ header[10 ] = 0 ;
130
+ header[11 ] = 0 ;
131
+ header[12 ] = 0 ;
132
+ return header;
133
+ }();
134
+
135
+ lzma_stream stream = LZMA_STREAM_INIT;
136
+ stream.avail_in = fake_header.size ();
137
+ stream.next_in = fake_header.data ();
138
+
139
+ stream.avail_out = pheader.base .datasize ;
140
+ stream.next_out = replay_data.data ();
141
+
142
+ if (lzma_alone_decoder (&stream, UINT64_MAX) != LZMA_OK) {
143
+ Reset ();
144
+ return false ;
145
+ }
146
+
147
+ while (stream.avail_in != 0 ) {
148
+ // this is should only feed the fake header, if for some reasons
149
+ // LZMA_STREAM_END is returned, then something went wrong
150
+ if (lzma_code (&stream, LZMA_RUN) != LZMA_OK) {
151
+ lzma_end (&stream);
152
+ Reset ();
153
+ return false ;
154
+ }
155
+ }
156
+
157
+ if (stream.total_out != 0 ) {
158
+ lzma_end (&stream);
159
+ Reset ();
118
160
return false ;
119
- size_t in_pos = 0 ;
120
- size_t out_pos = 0 ;
121
- lzma_raw_buffer_decode (filters, nullptr , contents.data () + header_size, &in_pos, comp_size, replay_data.data (), &out_pos, replay_size);
122
- free (filters[0 ].options );
161
+ }
162
+
163
+ stream.avail_in = comp_size;
164
+ stream.next_in = contents.data () + header_size;
165
+
166
+ while (stream.avail_in != 0 ) {
167
+ auto ret = lzma_code (&stream, LZMA_RUN);
168
+ if (ret == LZMA_STREAM_END) {
169
+ if (stream.total_out != pheader.base .datasize ) {
170
+ lzma_end (&stream);
171
+ Reset ();
172
+ return false ;
173
+ }
174
+ break ;
175
+ }
176
+ if (ret != LZMA_OK) {
177
+ // if liblzma finds both the header and the end of stream marker, it returns
178
+ // LZMA_DATA_ERROR, we ignore that error and just ensure that the total written
179
+ // size matches the uncompressed size
180
+ if (ret == LZMA_DATA_ERROR && stream.total_out == pheader.base .datasize )
181
+ break ;
182
+ Reset ();
183
+ lzma_end (&stream);
184
+ return false ;
185
+ }
186
+ }
187
+ lzma_end (&stream);
123
188
} else {
124
189
contents.erase (contents.begin (), contents.begin () + header_size);
125
190
replay_data = std::move (contents);
0 commit comments