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// VCDiffCodeTableReader is a class to interpret a stream of opcodes
170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// as VCDIFF instruction types, based on a VCDiffCodeTableData structure.
180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <config.h>
200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "decodetable.h"
210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "codetable.h"
220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "logging.h"
230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "varint_bigendian.h"
240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "vcdiff_defs.h"
250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathnamespace open_vcdiff {
270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathVCDiffCodeTableReader::VCDiffCodeTableReader()
290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    : code_table_data_(&VCDiffCodeTableData::kDefaultCodeTableData),
300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      non_default_code_table_data_(NULL),
310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      instructions_and_sizes_(NULL),
320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      instructions_and_sizes_end_(NULL),
330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      last_instruction_start_(NULL),
340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      pending_second_instruction_(kNoOpcode),
350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      last_pending_second_instruction_(kNoOpcode) {
360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffCodeTableReader::UseCodeTable(
390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    const VCDiffCodeTableData& code_table_data, unsigned char max_mode) {
400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!code_table_data.Validate(max_mode)) return false;
410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!non_default_code_table_data_.get()) {
420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    non_default_code_table_data_.reset(new VCDiffCodeTableData);
430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  *non_default_code_table_data_ = code_table_data;
450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  code_table_data_ = non_default_code_table_data_.get();
460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathVCDiffInstructionType VCDiffCodeTableReader::GetNextInstruction(
500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    int32_t* size,
510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    unsigned char* mode) {
520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!instructions_and_sizes_) {
530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    VCD_ERROR << "Internal error: GetNextInstruction() called before Init()"
540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << VCD_ENDL;
550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return VCD_INSTRUCTION_ERROR;
560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  last_instruction_start_ = *instructions_and_sizes_;
580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  last_pending_second_instruction_ = pending_second_instruction_;
590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  unsigned char opcode = 0;
600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  unsigned char instruction_type = VCD_NOOP;
610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  int32_t instruction_size = 0;
620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  unsigned char instruction_mode = 0;
630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  do {
640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (pending_second_instruction_ != kNoOpcode) {
650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      // There is a second instruction left over
660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      // from the most recently processed opcode.
670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      opcode = static_cast<unsigned char>(pending_second_instruction_);
680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      pending_second_instruction_ = kNoOpcode;
690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      instruction_type = code_table_data_->inst2[opcode];
700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      instruction_size = code_table_data_->size2[opcode];
710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      instruction_mode = code_table_data_->mode2[opcode];
720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      break;
730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (*instructions_and_sizes_ >= instructions_and_sizes_end_) {
750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      // Ran off end of instruction stream
760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return VCD_INSTRUCTION_END_OF_DATA;
770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    opcode = **instructions_and_sizes_;
790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (code_table_data_->inst2[opcode] != VCD_NOOP) {
800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      // This opcode contains two instructions; process the first one now, and
810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      // save a pointer to the second instruction, which should be returned
820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      // by the next call to GetNextInstruction
830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      pending_second_instruction_ = **instructions_and_sizes_;
840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    ++(*instructions_and_sizes_);
860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    instruction_type = code_table_data_->inst1[opcode];
870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    instruction_size = code_table_data_->size1[opcode];
880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    instruction_mode = code_table_data_->mode1[opcode];
890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // This do-while loop is necessary in case inst1 == VCD_NOOP for an opcode
900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // that was actually used in the encoding.  That case is unusual, but it
910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // is not prohibited by the standard.
920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } while (instruction_type == VCD_NOOP);
930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (instruction_size == 0) {
940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // Parse the size as a Varint in the instruction stream.
950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    switch (*size = VarintBE<int32_t>::Parse(instructions_and_sizes_end_,
960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                             instructions_and_sizes_)) {
970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      case RESULT_ERROR:
980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        VCD_ERROR << "Instruction size is not a valid variable-length integer"
990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  << VCD_ENDL;
1000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return VCD_INSTRUCTION_ERROR;
1010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      case RESULT_END_OF_DATA:
1020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        UnGetInstruction();  // Rewind to instruction start
1030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return VCD_INSTRUCTION_END_OF_DATA;
1040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      default:
1050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        break;  // Successfully parsed Varint
1060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
1070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else {
1080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    *size = instruction_size;
1090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  *mode = instruction_mode;
1110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return static_cast<VCDiffInstructionType>(instruction_type);
1120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
1130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath};  // namespace open_vcdiff
115