Home | History | Annotate | Download | only in src
      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 
     26 void ParseableChunk::Advance(size_t number_of_bytes) {
     27   if (number_of_bytes > UnparsedSize()) {
     28     LOG(DFATAL) << "Internal error: position advanced by " << number_of_bytes
     29                 << " bytes, current unparsed size " << UnparsedSize()
     30                 << LOG_ENDL;
     31     position_ = end_;
     32     return;
     33   }
     34   position_ += number_of_bytes;
     35 }
     36 
     37 void ParseableChunk::SetPosition(const char* position) {
     38   if (position < start_) {
     39     LOG(DFATAL) << "Internal error: new data position " << position
     40                 << " is beyond start of data " << start_ << LOG_ENDL;
     41     position_ = start_;
     42     return;
     43   }
     44   if (position > end_) {
     45     LOG(DFATAL) << "Internal error: new data position " << position
     46                 << " is beyond end of data " << end_ << LOG_ENDL;
     47     position_ = end_;
     48     return;
     49   }
     50   position_ = position;
     51 }
     52 
     53 void ParseableChunk::FinishExcept(size_t number_of_bytes) {
     54   if (number_of_bytes > UnparsedSize()) {
     55     LOG(DFATAL) << "Internal error: specified number of remaining bytes "
     56                 << number_of_bytes << " is greater than unparsed data size "
     57                 << UnparsedSize() << LOG_ENDL;
     58     Finish();
     59     return;
     60   }
     61   position_ = end_ - number_of_bytes;
     62 }
     63 
     64 // *** Methods for VCDiffHeaderParser
     65 
     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 
     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 
     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       LOG(ERROR) << "Expected " << variable_description
     97                  << "; found invalid variable-length integer" << LOG_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.
    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       LOG(ERROR) << "Expected " << variable_description
    124                  << "; found invalid variable-length integer" << LOG_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         LOG(ERROR) << "Value of " << variable_description << "(" << parsed_value
    133                    << ") is too large for unsigned 32-bit integer" << LOG_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.
    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 
    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 
    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     LOG(ERROR) << "Source segment length (" << *source_segment_length
    177                << ") is larger than " << from_name << " (" << from_size
    178                << ")" << LOG_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     LOG(ERROR) << "Source segment position (" << *source_segment_position
    188                << ") is past " << from_boundary_name
    189                << " (" << from_size << ")" << LOG_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     LOG(ERROR) << "Source segment end position (" << source_segment_end
    197                << ") is past " << from_boundary_name
    198                << " (" << from_size << ")" << LOG_ENDL;
    199     return_code_ = RESULT_ERROR;
    200     return false;
    201   }
    202   return true;
    203 }
    204 
    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         LOG(ERROR) << "Delta file contains VCD_TARGET flag, which is not "
    227                       "allowed by current decoder settings" << LOG_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       LOG(ERROR) << "Win_Indicator must not have both VCD_SOURCE"
    238                     " and VCD_TARGET set" << LOG_ENDL;
    239       return_code_ = RESULT_ERROR;
    240       return false;
    241     default:
    242       return true;
    243   }
    244 }
    245 
    246 bool VCDiffHeaderParser::ParseWindowLengths(size_t* target_window_length) {
    247   if (delta_encoding_start_) {
    248     LOG(DFATAL) << "Internal error: VCDiffHeaderParser::ParseWindowLengths "
    249                    "was called twice for the same delta window" << LOG_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 
    263 const char* VCDiffHeaderParser::EndOfDeltaWindow() const {
    264   if (!delta_encoding_start_) {
    265     LOG(DFATAL) << "Internal error: VCDiffHeaderParser::GetDeltaWindowEnd "
    266                    "was called before ParseWindowLengths" << LOG_ENDL;
    267     return NULL;
    268   }
    269   return delta_encoding_start_ + delta_encoding_length_;
    270 }
    271 
    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     LOG(ERROR) << "Secondary compression of delta file sections "
    279                   "is not supported" << LOG_ENDL;
    280     return_code_ = RESULT_ERROR;
    281     return false;
    282   }
    283   return true;
    284 }
    285 
    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     LOG(DFATAL) << "Internal error: VCDiffHeaderParser::ParseSectionLengths "
    303                    "was called before ParseWindowLengths" << LOG_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     LOG(ERROR) << "The length of the delta encoding does not match "
    315                   "the size of the header plus the sizes of the data sections"
    316                << LOG_ENDL;
    317     return_code_ = RESULT_ERROR;
    318     return false;
    319   }
    320   return true;
    321 }
    322 
    323 }  // namespace open_vcdiff
    324