• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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