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