1 // Copyright 2008 Google Inc.
2 // Author: Lincoln Smith
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include <config.h>
17 #include "headerparser.h"
18 #include "logging.h"
19 #include "varint_bigendian.h"
20 #include "vcdiff_defs.h"
21
22 namespace open_vcdiff {
23
24 // *** Methods for ParseableChunk
25
Advance(size_t number_of_bytes)26 void ParseableChunk::Advance(size_t number_of_bytes) {
27 if (number_of_bytes > UnparsedSize()) {
28 VCD_DFATAL << "Internal error: position advanced by " << number_of_bytes
29 << " bytes, current unparsed size " << UnparsedSize()
30 << VCD_ENDL;
31 position_ = end_;
32 return;
33 }
34 position_ += number_of_bytes;
35 }
36
SetPosition(const char * position)37 void ParseableChunk::SetPosition(const char* position) {
38 if (position < start_) {
39 VCD_DFATAL << "Internal error: new data position " << position
40 << " is beyond start of data " << start_ << VCD_ENDL;
41 position_ = start_;
42 return;
43 }
44 if (position > end_) {
45 VCD_DFATAL << "Internal error: new data position " << position
46 << " is beyond end of data " << end_ << VCD_ENDL;
47 position_ = end_;
48 return;
49 }
50 position_ = position;
51 }
52
FinishExcept(size_t number_of_bytes)53 void ParseableChunk::FinishExcept(size_t number_of_bytes) {
54 if (number_of_bytes > UnparsedSize()) {
55 VCD_DFATAL << "Internal error: specified number of remaining bytes "
56 << number_of_bytes << " is greater than unparsed data size "
57 << UnparsedSize() << VCD_ENDL;
58 Finish();
59 return;
60 }
61 position_ = end_ - number_of_bytes;
62 }
63
64 // *** Methods for VCDiffHeaderParser
65
VCDiffHeaderParser(const char * header_start,const char * data_end)66 VCDiffHeaderParser::VCDiffHeaderParser(const char* header_start,
67 const char* data_end)
68 : parseable_chunk_(header_start, data_end - header_start),
69 return_code_(RESULT_SUCCESS),
70 delta_encoding_length_(0),
71 delta_encoding_start_(NULL) { }
72
ParseByte(unsigned char * value)73 bool VCDiffHeaderParser::ParseByte(unsigned char* value) {
74 if (RESULT_SUCCESS != return_code_) {
75 return false;
76 }
77 if (parseable_chunk_.Empty()) {
78 return_code_ = RESULT_END_OF_DATA;
79 return false;
80 }
81 *value = static_cast<unsigned char>(*parseable_chunk_.UnparsedData());
82 parseable_chunk_.Advance(1);
83 return true;
84 }
85
ParseInt32(const char * variable_description,int32_t * value)86 bool VCDiffHeaderParser::ParseInt32(const char* variable_description,
87 int32_t* value) {
88 if (RESULT_SUCCESS != return_code_) {
89 return false;
90 }
91 int32_t parsed_value =
92 VarintBE<int32_t>::Parse(parseable_chunk_.End(),
93 parseable_chunk_.UnparsedDataAddr());
94 switch (parsed_value) {
95 case RESULT_ERROR:
96 VCD_ERROR << "Expected " << variable_description
97 << "; found invalid variable-length integer" << VCD_ENDL;
98 return_code_ = RESULT_ERROR;
99 return false;
100 case RESULT_END_OF_DATA:
101 return_code_ = RESULT_END_OF_DATA;
102 return false;
103 default:
104 *value = parsed_value;
105 return true;
106 }
107 }
108
109 // When an unsigned 32-bit integer is expected, parse a signed 64-bit value
110 // instead, then check the value limit. The uint32_t type can't be parsed
111 // directly because two negative values are given special meanings (RESULT_ERROR
112 // and RESULT_END_OF_DATA) and could not be expressed in an unsigned format.
ParseUInt32(const char * variable_description,uint32_t * value)113 bool VCDiffHeaderParser::ParseUInt32(const char* variable_description,
114 uint32_t* value) {
115 if (RESULT_SUCCESS != return_code_) {
116 return false;
117 }
118 int64_t parsed_value =
119 VarintBE<int64_t>::Parse(parseable_chunk_.End(),
120 parseable_chunk_.UnparsedDataAddr());
121 switch (parsed_value) {
122 case RESULT_ERROR:
123 VCD_ERROR << "Expected " << variable_description
124 << "; found invalid variable-length integer" << VCD_ENDL;
125 return_code_ = RESULT_ERROR;
126 return false;
127 case RESULT_END_OF_DATA:
128 return_code_ = RESULT_END_OF_DATA;
129 return false;
130 default:
131 if (parsed_value > 0xFFFFFFFF) {
132 VCD_ERROR << "Value of " << variable_description << "(" << parsed_value
133 << ") is too large for unsigned 32-bit integer" << VCD_ENDL;
134 return_code_ = RESULT_ERROR;
135 return false;
136 }
137 *value = static_cast<uint32_t>(parsed_value);
138 return true;
139 }
140 }
141
142 // A VCDChecksum represents an unsigned 32-bit value returned by adler32(),
143 // but isn't a uint32_t.
ParseChecksum(const char * variable_description,VCDChecksum * value)144 bool VCDiffHeaderParser::ParseChecksum(const char* variable_description,
145 VCDChecksum* value) {
146 uint32_t parsed_value = 0;
147 if (!ParseUInt32(variable_description, &parsed_value)) {
148 return false;
149 }
150 *value = static_cast<VCDChecksum>(parsed_value);
151 return true;
152 }
153
ParseSize(const char * variable_description,size_t * value)154 bool VCDiffHeaderParser::ParseSize(const char* variable_description,
155 size_t* value) {
156 int32_t parsed_value = 0;
157 if (!ParseInt32(variable_description, &parsed_value)) {
158 return false;
159 }
160 *value = static_cast<size_t>(parsed_value);
161 return true;
162 }
163
ParseSourceSegmentLengthAndPosition(size_t from_size,const char * from_boundary_name,const char * from_name,size_t * source_segment_length,size_t * source_segment_position)164 bool VCDiffHeaderParser::ParseSourceSegmentLengthAndPosition(
165 size_t from_size,
166 const char* from_boundary_name,
167 const char* from_name,
168 size_t* source_segment_length,
169 size_t* source_segment_position) {
170 // Verify the length and position values
171 if (!ParseSize("source segment length", source_segment_length)) {
172 return false;
173 }
174 // Guard against overflow by checking source length first
175 if (*source_segment_length > from_size) {
176 VCD_ERROR << "Source segment length (" << *source_segment_length
177 << ") is larger than " << from_name << " (" << from_size
178 << ")" << VCD_ENDL;
179 return_code_ = RESULT_ERROR;
180 return false;
181 }
182 if (!ParseSize("source segment position", source_segment_position)) {
183 return false;
184 }
185 if ((*source_segment_position >= from_size) &&
186 (*source_segment_length > 0)) {
187 VCD_ERROR << "Source segment position (" << *source_segment_position
188 << ") is past " << from_boundary_name
189 << " (" << from_size << ")" << VCD_ENDL;
190 return_code_ = RESULT_ERROR;
191 return false;
192 }
193 const size_t source_segment_end = *source_segment_position +
194 *source_segment_length;
195 if (source_segment_end > from_size) {
196 VCD_ERROR << "Source segment end position (" << source_segment_end
197 << ") is past " << from_boundary_name
198 << " (" << from_size << ")" << VCD_ENDL;
199 return_code_ = RESULT_ERROR;
200 return false;
201 }
202 return true;
203 }
204
ParseWinIndicatorAndSourceSegment(size_t dictionary_size,size_t decoded_target_size,bool allow_vcd_target,unsigned char * win_indicator,size_t * source_segment_length,size_t * source_segment_position)205 bool VCDiffHeaderParser::ParseWinIndicatorAndSourceSegment(
206 size_t dictionary_size,
207 size_t decoded_target_size,
208 bool allow_vcd_target,
209 unsigned char* win_indicator,
210 size_t* source_segment_length,
211 size_t* source_segment_position) {
212 if (!ParseByte(win_indicator)) {
213 return false;
214 }
215 unsigned char source_target_flags =
216 *win_indicator & (VCD_SOURCE | VCD_TARGET);
217 switch (source_target_flags) {
218 case VCD_SOURCE:
219 return ParseSourceSegmentLengthAndPosition(dictionary_size,
220 "end of dictionary",
221 "dictionary",
222 source_segment_length,
223 source_segment_position);
224 case VCD_TARGET:
225 if (!allow_vcd_target) {
226 VCD_ERROR << "Delta file contains VCD_TARGET flag, which is not "
227 "allowed by current decoder settings" << VCD_ENDL;
228 return_code_ = RESULT_ERROR;
229 return false;
230 }
231 return ParseSourceSegmentLengthAndPosition(decoded_target_size,
232 "current target position",
233 "target file",
234 source_segment_length,
235 source_segment_position);
236 case VCD_SOURCE | VCD_TARGET:
237 VCD_ERROR << "Win_Indicator must not have both VCD_SOURCE"
238 " and VCD_TARGET set" << VCD_ENDL;
239 return_code_ = RESULT_ERROR;
240 return false;
241 default:
242 return true;
243 }
244 }
245
ParseWindowLengths(size_t * target_window_length)246 bool VCDiffHeaderParser::ParseWindowLengths(size_t* target_window_length) {
247 if (delta_encoding_start_) {
248 VCD_DFATAL << "Internal error: VCDiffHeaderParser::ParseWindowLengths "
249 "was called twice for the same delta window" << VCD_ENDL;
250 return_code_ = RESULT_ERROR;
251 return false;
252 }
253 if (!ParseSize("length of the delta encoding", &delta_encoding_length_)) {
254 return false;
255 }
256 delta_encoding_start_ = UnparsedData();
257 if (!ParseSize("size of the target window", target_window_length)) {
258 return false;
259 }
260 return true;
261 }
262
EndOfDeltaWindow() const263 const char* VCDiffHeaderParser::EndOfDeltaWindow() const {
264 if (!delta_encoding_start_) {
265 VCD_DFATAL << "Internal error: VCDiffHeaderParser::GetDeltaWindowEnd "
266 "was called before ParseWindowLengths" << VCD_ENDL;
267 return NULL;
268 }
269 return delta_encoding_start_ + delta_encoding_length_;
270 }
271
ParseDeltaIndicator()272 bool VCDiffHeaderParser::ParseDeltaIndicator() {
273 unsigned char delta_indicator;
274 if (!ParseByte(&delta_indicator)) {
275 return false;
276 }
277 if (delta_indicator & (VCD_DATACOMP | VCD_INSTCOMP | VCD_ADDRCOMP)) {
278 VCD_ERROR << "Secondary compression of delta file sections "
279 "is not supported" << VCD_ENDL;
280 return_code_ = RESULT_ERROR;
281 return false;
282 }
283 return true;
284 }
285
ParseSectionLengths(bool has_checksum,size_t * add_and_run_data_length,size_t * instructions_and_sizes_length,size_t * addresses_length,VCDChecksum * checksum)286 bool VCDiffHeaderParser::ParseSectionLengths(
287 bool has_checksum,
288 size_t* add_and_run_data_length,
289 size_t* instructions_and_sizes_length,
290 size_t* addresses_length,
291 VCDChecksum* checksum) {
292 ParseSize("length of data for ADDs and RUNs", add_and_run_data_length);
293 ParseSize("length of instructions section", instructions_and_sizes_length);
294 ParseSize("length of addresses for COPYs", addresses_length);
295 if (has_checksum) {
296 ParseChecksum("Adler32 checksum value", checksum);
297 }
298 if (RESULT_SUCCESS != return_code_) {
299 return false;
300 }
301 if (!delta_encoding_start_) {
302 VCD_DFATAL << "Internal error: VCDiffHeaderParser::ParseSectionLengths "
303 "was called before ParseWindowLengths" << VCD_ENDL;
304 return_code_ = RESULT_ERROR;
305 return false;
306 }
307 const size_t delta_encoding_header_length =
308 UnparsedData() - delta_encoding_start_;
309 if (delta_encoding_length_ !=
310 (delta_encoding_header_length +
311 *add_and_run_data_length +
312 *instructions_and_sizes_length +
313 *addresses_length)) {
314 VCD_ERROR << "The length of the delta encoding does not match "
315 "the size of the header plus the sizes of the data sections"
316 << VCD_ENDL;
317 return_code_ = RESULT_ERROR;
318 return false;
319 }
320 return true;
321 }
322
323 } // namespace open_vcdiff
324