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