10a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Copyright 2008 Google Inc.
20a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Author: Lincoln Smith
30a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//
40a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Licensed under the Apache License, Version 2.0 (the "License");
50a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// you may not use this file except in compliance with the License.
60a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// You may obtain a copy of the License at
70a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//
80a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//      http://www.apache.org/licenses/LICENSE-2.0
90a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//
100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Unless required by applicable law or agreed to in writing, software
110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// distributed under the License is distributed on an "AS IS" BASIS,
120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// See the License for the specific language governing permissions and
140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// limitations under the License.
150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <config.h>
170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "headerparser.h"
180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "logging.h"
190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "varint_bigendian.h"
200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "vcdiff_defs.h"
210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathnamespace open_vcdiff {
230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// *** Methods for ParseableChunk
250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathvoid ParseableChunk::Advance(size_t number_of_bytes) {
270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (number_of_bytes > UnparsedSize()) {
280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_DFATAL << "Internal error: position advanced by " << number_of_bytes
290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath               << " bytes, current unparsed size " << UnparsedSize()
300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath               << VCD_ENDL;
310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    position_ = end_;
320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return;
330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  position_ += number_of_bytes;
350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathvoid ParseableChunk::SetPosition(const char* position) {
380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (position < start_) {
390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_DFATAL << "Internal error: new data position " << position
400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath               << " is beyond start of data " << start_ << VCD_ENDL;
410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    position_ = start_;
420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return;
430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (position > end_) {
450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_DFATAL << "Internal error: new data position " << position
460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath               << " is beyond end of data " << end_ << VCD_ENDL;
470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    position_ = end_;
480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return;
490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  position_ = position;
510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathvoid ParseableChunk::FinishExcept(size_t number_of_bytes) {
540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (number_of_bytes > UnparsedSize()) {
550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_DFATAL << "Internal error: specified number of remaining bytes "
560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath               << number_of_bytes << " is greater than unparsed data size "
570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath               << UnparsedSize() << VCD_ENDL;
580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    Finish();
590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return;
600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  position_ = end_ - number_of_bytes;
620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// *** Methods for VCDiffHeaderParser
650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathVCDiffHeaderParser::VCDiffHeaderParser(const char* header_start,
670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                       const char* data_end)
680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    : parseable_chunk_(header_start, data_end - header_start),
690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return_code_(RESULT_SUCCESS),
700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      delta_encoding_length_(0),
710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      delta_encoding_start_(NULL) { }
720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseByte(unsigned char* value) {
740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (RESULT_SUCCESS != return_code_) {
750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (parseable_chunk_.Empty()) {
780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return_code_ = RESULT_END_OF_DATA;
790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  *value = static_cast<unsigned char>(*parseable_chunk_.UnparsedData());
820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  parseable_chunk_.Advance(1);
830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseInt32(const char* variable_description,
870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                    int32_t* value) {
880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (RESULT_SUCCESS != return_code_) {
890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  int32_t parsed_value =
920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      VarintBE<int32_t>::Parse(parseable_chunk_.End(),
930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                               parseable_chunk_.UnparsedDataAddr());
940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  switch (parsed_value) {
950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    case RESULT_ERROR:
960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      VCD_ERROR << "Expected " << variable_description
970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << "; found invalid variable-length integer" << VCD_ENDL;
980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return_code_ = RESULT_ERROR;
990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
1000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    case RESULT_END_OF_DATA:
1010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return_code_ = RESULT_END_OF_DATA;
1020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
1030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    default:
1040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      *value = parsed_value;
1050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return true;
1060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
1080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// When an unsigned 32-bit integer is expected, parse a signed 64-bit value
1100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// instead, then check the value limit.  The uint32_t type can't be parsed
1110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// directly because two negative values are given special meanings (RESULT_ERROR
1120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// and RESULT_END_OF_DATA) and could not be expressed in an unsigned format.
1130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseUInt32(const char* variable_description,
1140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                     uint32_t* value) {
1150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (RESULT_SUCCESS != return_code_) {
1160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
1170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  int64_t parsed_value =
1190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      VarintBE<int64_t>::Parse(parseable_chunk_.End(),
1200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                               parseable_chunk_.UnparsedDataAddr());
1210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  switch (parsed_value) {
1220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    case RESULT_ERROR:
1230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      VCD_ERROR << "Expected " << variable_description
1240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << "; found invalid variable-length integer" << VCD_ENDL;
1250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return_code_ = RESULT_ERROR;
1260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
1270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    case RESULT_END_OF_DATA:
1280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return_code_ = RESULT_END_OF_DATA;
1290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
1300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    default:
1310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      if (parsed_value > 0xFFFFFFFF) {
1320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        VCD_ERROR << "Value of " << variable_description << "(" << parsed_value
1330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  << ") is too large for unsigned 32-bit integer" << VCD_ENDL;
1340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return_code_ = RESULT_ERROR;
1350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return false;
1360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      }
1370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      *value = static_cast<uint32_t>(parsed_value);
1380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return true;
1390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
1410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// A VCDChecksum represents an unsigned 32-bit value returned by adler32(),
1430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// but isn't a uint32_t.
1440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseChecksum(const char* variable_description,
1450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                       VCDChecksum* value) {
1460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  uint32_t parsed_value = 0;
1470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!ParseUInt32(variable_description, &parsed_value)) {
1480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
1490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  *value = static_cast<VCDChecksum>(parsed_value);
1510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
1520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
1530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseSize(const char* variable_description,
1550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                   size_t* value) {
1560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  int32_t parsed_value = 0;
1570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!ParseInt32(variable_description, &parsed_value)) {
1580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
1590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  *value = static_cast<size_t>(parsed_value);
1610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
1620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
1630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseSourceSegmentLengthAndPosition(
1650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t from_size,
1660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    const char* from_boundary_name,
1670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    const char* from_name,
1680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t* source_segment_length,
1690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t* source_segment_position) {
1700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Verify the length and position values
1710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!ParseSize("source segment length", source_segment_length)) {
1720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
1730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Guard against overflow by checking source length first
1750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (*source_segment_length > from_size) {
1760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_ERROR << "Source segment length (" << *source_segment_length
1770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << ") is larger than " << from_name << " (" << from_size
1780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << ")" << VCD_ENDL;
1790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return_code_ = RESULT_ERROR;
1800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
1810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!ParseSize("source segment position", source_segment_position)) {
1830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
1840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if ((*source_segment_position >= from_size) &&
1860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      (*source_segment_length > 0)) {
1870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_ERROR << "Source segment position (" << *source_segment_position
1880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << ") is past " << from_boundary_name
1890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << " (" << from_size << ")" << VCD_ENDL;
1900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return_code_ = RESULT_ERROR;
1910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
1920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  const size_t source_segment_end = *source_segment_position +
1940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                    *source_segment_length;
1950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (source_segment_end > from_size) {
1960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_ERROR << "Source segment end position (" << source_segment_end
1970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << ") is past " << from_boundary_name
1980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << " (" << from_size << ")" << VCD_ENDL;
1990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return_code_ = RESULT_ERROR;
2000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
2030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseWinIndicatorAndSourceSegment(
2060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t dictionary_size,
2070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t decoded_target_size,
2080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    bool allow_vcd_target,
2090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    unsigned char* win_indicator,
2100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t* source_segment_length,
2110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t* source_segment_position) {
2120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!ParseByte(win_indicator)) {
2130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  unsigned char source_target_flags =
2160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      *win_indicator & (VCD_SOURCE | VCD_TARGET);
2170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  switch (source_target_flags) {
2180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    case VCD_SOURCE:
2190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return ParseSourceSegmentLengthAndPosition(dictionary_size,
2200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                                 "end of dictionary",
2210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                                 "dictionary",
2220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                                 source_segment_length,
2230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                                 source_segment_position);
2240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    case VCD_TARGET:
2250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      if (!allow_vcd_target) {
2260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        VCD_ERROR << "Delta file contains VCD_TARGET flag, which is not "
2270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                     "allowed by current decoder settings" << VCD_ENDL;
2280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return_code_ = RESULT_ERROR;
2290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return false;
2300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      }
2310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return ParseSourceSegmentLengthAndPosition(decoded_target_size,
2320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                                 "current target position",
2330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                                 "target file",
2340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                                 source_segment_length,
2350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                                 source_segment_position);
2360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    case VCD_SOURCE | VCD_TARGET:
2370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      VCD_ERROR << "Win_Indicator must not have both VCD_SOURCE"
2380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                   " and VCD_TARGET set" << VCD_ENDL;
2390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return_code_ = RESULT_ERROR;
2400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
2410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    default:
2420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return true;
2430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseWindowLengths(size_t* target_window_length) {
2470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (delta_encoding_start_) {
2480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_DFATAL << "Internal error: VCDiffHeaderParser::ParseWindowLengths "
2490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  "was called twice for the same delta window" << VCD_ENDL;
2500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return_code_ = RESULT_ERROR;
2510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!ParseSize("length of the delta encoding", &delta_encoding_length_)) {
2540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  delta_encoding_start_ = UnparsedData();
2570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!ParseSize("size of the target window", target_window_length)) {
2580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
2610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst char* VCDiffHeaderParser::EndOfDeltaWindow() const {
2640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!delta_encoding_start_) {
2650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_DFATAL << "Internal error: VCDiffHeaderParser::GetDeltaWindowEnd "
2660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  "was called before ParseWindowLengths" << VCD_ENDL;
2670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return NULL;
2680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return delta_encoding_start_ + delta_encoding_length_;
2700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseDeltaIndicator() {
2730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  unsigned char delta_indicator;
2740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!ParseByte(&delta_indicator)) {
2750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (delta_indicator & (VCD_DATACOMP | VCD_INSTCOMP | VCD_ADDRCOMP)) {
2780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_ERROR << "Secondary compression of delta file sections "
2790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                 "is not supported" << VCD_ENDL;
2800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return_code_ = RESULT_ERROR;
2810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
2840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffHeaderParser::ParseSectionLengths(
2870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    bool has_checksum,
2880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t* add_and_run_data_length,
2890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t* instructions_and_sizes_length,
2900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t* addresses_length,
2910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCDChecksum* checksum) {
2920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  ParseSize("length of data for ADDs and RUNs", add_and_run_data_length);
2930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  ParseSize("length of instructions section", instructions_and_sizes_length);
2940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  ParseSize("length of addresses for COPYs", addresses_length);
2950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (has_checksum) {
2960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    ParseChecksum("Adler32 checksum value", checksum);
2970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (RESULT_SUCCESS != return_code_) {
2990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
3000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!delta_encoding_start_) {
3020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_DFATAL << "Internal error: VCDiffHeaderParser::ParseSectionLengths "
3030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  "was called before ParseWindowLengths" << VCD_ENDL;
3040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return_code_ = RESULT_ERROR;
3050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
3060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  const size_t delta_encoding_header_length =
3080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      UnparsedData() - delta_encoding_start_;
3090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (delta_encoding_length_ !=
3100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath          (delta_encoding_header_length +
3110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath           *add_and_run_data_length +
3120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath           *instructions_and_sizes_length +
3130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath           *addresses_length)) {
3140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_ERROR << "The length of the delta encoding does not match "
3150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                 "the size of the header plus the sizes of the data sections"
3160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << VCD_ENDL;
3170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return_code_ = RESULT_ERROR;
3180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
3190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
3210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
3220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
3230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}  // namespace open_vcdiff
324