#include <config.h>
#include "decodetable.h"
#include "codetable.h"
#include "logging.h"
#include "varint_bigendian.h"
#include "vcdiff_defs.h"
namespace open_vcdiff {
VCDiffCodeTableReader::VCDiffCodeTableReader()
: code_table_data_(&VCDiffCodeTableData::kDefaultCodeTableData),
non_default_code_table_data_(NULL),
instructions_and_sizes_(NULL),
instructions_and_sizes_end_(NULL),
last_instruction_start_(NULL),
pending_second_instruction_(kNoOpcode),
last_pending_second_instruction_(kNoOpcode) {
}
bool VCDiffCodeTableReader::UseCodeTable(
const VCDiffCodeTableData& code_table_data, unsigned char max_mode) {
if (!code_table_data.Validate(max_mode)) return false;
if (!non_default_code_table_data_.get()) {
non_default_code_table_data_.reset(new VCDiffCodeTableData);
}
*non_default_code_table_data_ = code_table_data;
code_table_data_ = non_default_code_table_data_.get();
return true;
}
VCDiffInstructionType VCDiffCodeTableReader::GetNextInstruction(
int32_t* size,
unsigned char* mode) {
if (!instructions_and_sizes_) {
VCD_ERROR << "Internal error: GetNextInstruction() called before Init()"
<< VCD_ENDL;
return VCD_INSTRUCTION_ERROR;
}
last_instruction_start_ = *instructions_and_sizes_;
last_pending_second_instruction_ = pending_second_instruction_;
unsigned char opcode = 0;
unsigned char instruction_type = VCD_NOOP;
int32_t instruction_size = 0;
unsigned char instruction_mode = 0;
do {
if (pending_second_instruction_ != kNoOpcode) {
opcode = static_cast<unsigned char>(pending_second_instruction_);
pending_second_instruction_ = kNoOpcode;
instruction_type = code_table_data_->inst2[opcode];
instruction_size = code_table_data_->size2[opcode];
instruction_mode = code_table_data_->mode2[opcode];
break;
}
if (*instructions_and_sizes_ >= instructions_and_sizes_end_) {
return VCD_INSTRUCTION_END_OF_DATA;
}
opcode = **instructions_and_sizes_;
if (code_table_data_->inst2[opcode] != VCD_NOOP) {
pending_second_instruction_ = **instructions_and_sizes_;
}
++(*instructions_and_sizes_);
instruction_type = code_table_data_->inst1[opcode];
instruction_size = code_table_data_->size1[opcode];
instruction_mode = code_table_data_->mode1[opcode];
} while (instruction_type == VCD_NOOP);
if (instruction_size == 0) {
switch (*size = VarintBE<int32_t>::Parse(instructions_and_sizes_end_,
instructions_and_sizes_)) {
case RESULT_ERROR:
VCD_ERROR << "Instruction size is not a valid variable-length integer"
<< VCD_ENDL;
return VCD_INSTRUCTION_ERROR;
case RESULT_END_OF_DATA:
UnGetInstruction(); return VCD_INSTRUCTION_END_OF_DATA;
default:
break; }
} else {
*size = instruction_size;
}
*mode = instruction_mode;
return static_cast<VCDiffInstructionType>(instruction_type);
}
};