1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright 2008 Google Inc.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Author: Lincoln Smith
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Licensed under the Apache License, Version 2.0 (the "License");
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// you may not use this file except in compliance with the License.
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// You may obtain a copy of the License at
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//      http://www.apache.org/licenses/LICENSE-2.0
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Unless required by applicable law or agreed to in writing, software
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// distributed under the License is distributed on an "AS IS" BASIS,
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// See the License for the specific language governing permissions and
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// limitations under the License.
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// VCDiffCodeTableReader is a class to interpret a stream of opcodes
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// as VCDIFF instruction types, based on a VCDiffCodeTableData structure.
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <config.h>
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "decodetable.h"
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "codetable.h"
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "logging.h"
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "varint_bigendian.h"
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "vcdiff_defs.h"
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace open_vcdiff {
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottVCDiffCodeTableReader::VCDiffCodeTableReader()
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : code_table_data_(&VCDiffCodeTableData::kDefaultCodeTableData),
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      non_default_code_table_data_(NULL),
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      instructions_and_sizes_(NULL),
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      instructions_and_sizes_end_(NULL),
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      last_instruction_start_(NULL),
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pending_second_instruction_(kNoOpcode),
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      last_pending_second_instruction_(kNoOpcode) {
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool VCDiffCodeTableReader::UseCodeTable(
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const VCDiffCodeTableData& code_table_data, unsigned char max_mode) {
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!code_table_data.Validate(max_mode)) return false;
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!non_default_code_table_data_.get()) {
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    non_default_code_table_data_.reset(new VCDiffCodeTableData);
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *non_default_code_table_data_ = code_table_data;
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  code_table_data_ = non_default_code_table_data_.get();
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottVCDiffInstructionType VCDiffCodeTableReader::GetNextInstruction(
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int32_t* size,
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    unsigned char* mode) {
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!instructions_and_sizes_) {
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "Internal error: GetNextInstruction() called before Init()"
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott               << LOG_ENDL;
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return VCD_INSTRUCTION_ERROR;
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  last_instruction_start_ = *instructions_and_sizes_;
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  last_pending_second_instruction_ = pending_second_instruction_;
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  unsigned char opcode = 0;
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  unsigned char instruction_type = VCD_NOOP;
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int32_t instruction_size = 0;
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  unsigned char instruction_mode = 0;
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  do {
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (pending_second_instruction_ != kNoOpcode) {
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // There is a second instruction left over
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // from the most recently processed opcode.
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      opcode = static_cast<unsigned char>(pending_second_instruction_);
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pending_second_instruction_ = kNoOpcode;
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      instruction_type = code_table_data_->inst2[opcode];
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      instruction_size = code_table_data_->size2[opcode];
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      instruction_mode = code_table_data_->mode2[opcode];
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (*instructions_and_sizes_ >= instructions_and_sizes_end_) {
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Ran off end of instruction stream
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return VCD_INSTRUCTION_END_OF_DATA;
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    opcode = **instructions_and_sizes_;
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (code_table_data_->inst2[opcode] != VCD_NOOP) {
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // This opcode contains two instructions; process the first one now, and
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // save a pointer to the second instruction, which should be returned
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // by the next call to GetNextInstruction
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pending_second_instruction_ = **instructions_and_sizes_;
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ++(*instructions_and_sizes_);
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    instruction_type = code_table_data_->inst1[opcode];
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    instruction_size = code_table_data_->size1[opcode];
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    instruction_mode = code_table_data_->mode1[opcode];
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // This do-while loop is necessary in case inst1 == VCD_NOOP for an opcode
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // that was actually used in the encoding.  That case is unusual, but it
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // is not prohibited by the standard.
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } while (instruction_type == VCD_NOOP);
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (instruction_size == 0) {
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Parse the size as a Varint in the instruction stream.
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    switch (*size = VarintBE<int32_t>::Parse(instructions_and_sizes_end_,
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                             instructions_and_sizes_)) {
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case RESULT_ERROR:
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        LOG(ERROR) << "Instruction size is not a valid variable-length integer"
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   << LOG_ENDL;
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return VCD_INSTRUCTION_ERROR;
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case RESULT_END_OF_DATA:
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        UnGetInstruction();  // Rewind to instruction start
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return VCD_INSTRUCTION_END_OF_DATA;
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      default:
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;  // Successfully parsed Varint
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *size = instruction_size;
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *mode = instruction_mode;
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return static_cast<VCDiffInstructionType>(instruction_type);
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};  // namespace open_vcdiff
115