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#ifndef OPEN_VCDIFF_DECODETABLE_H_
17#define OPEN_VCDIFF_DECODETABLE_H_
18
19#include <config.h>
20#include <stddef.h>     // NULL
21#include <stdint.h>     // int32_t
22#include <memory>       // auto_ptr
23#include "codetable.h"  // VCDiffInstructi...
24#include "logging.h"
25
26namespace open_vcdiff {
27
28// This class is used by the decoder.  It can use a standard or
29// non-standard code table, and will translate the opcodes in the code table
30// into delta instructions.
31//
32// NOT threadsafe.
33//
34class VCDiffCodeTableReader {
35 public:
36  // When constructed, the object will be set up to use the default code table.
37  // If a non-default code table is to be used, then UseCodeTable()
38  // should be called after the VCDiffCodeTableReader has been constructed.
39  // In any case, the Init() method must be called before GetNextInstruction()
40  // may be used.
41  //
42  VCDiffCodeTableReader();
43
44  // Sets up a non-standard code table.  The caller
45  // may free the memory occupied by the argument code table after
46  // passing it to this method, because the argument code table
47  // allocates space to store a copy of it.
48  // UseCodeTable() may be called either before or after calling Init().
49  // Returns true if the code table was accepted, or false if the
50  // argument did not appear to be a valid code table.
51  //
52  bool UseCodeTable(const VCDiffCodeTableData& code_table_data,
53                    unsigned char max_mode);
54
55  // Defines the buffer containing the instructions and sizes.
56  // This method must be called before GetNextInstruction() may be used.
57  // Init() may be called any number of times to reset the state of
58  // the object.
59  //
60  void Init(const char** instructions_and_sizes,
61            const char* instructions_and_sizes_end) {
62    instructions_and_sizes_ = instructions_and_sizes;
63    instructions_and_sizes_end_ = instructions_and_sizes_end;
64    last_instruction_start_ = NULL;
65    pending_second_instruction_ = kNoOpcode;
66    last_pending_second_instruction_ = kNoOpcode;
67  }
68
69  // Updates the pointers to the buffer containing the instructions and sizes,
70  // but leaves the rest of the reader state intact, so that (for example)
71  // any pending second instruction or unread instruction will still be
72  // read when requested.  NOTE: UnGetInstruction() will not work immediately
73  // after using UpdatePointers(); GetNextInstruction() must be called first.
74  //
75  void UpdatePointers(const char** instructions_and_sizes,
76                      const char* instructions_and_sizes_end) {
77    instructions_and_sizes_ = instructions_and_sizes;
78    instructions_and_sizes_end_ = instructions_and_sizes_end;
79    last_instruction_start_ = *instructions_and_sizes;
80    // pending_second_instruction_ is unchanged
81    last_pending_second_instruction_ = pending_second_instruction_;
82  }
83
84  // Returns the next instruction from the stream of opcodes,
85  // or VCD_INSTRUCTION_END_OF_DATA if the end of the opcode stream is reached,
86  // or VCD_INSTRUCTION_ERROR if an error occurred.
87  // In the first of these cases, increments *instructions_and_sizes_
88  // past the values it reads, and populates *size
89  // with the corresponding size for the returned instruction;
90  // otherwise, the value of *size is undefined, and is not
91  // guaranteed to be preserved.
92  // If the instruction returned is VCD_COPY, *mode will
93  // be populated with the copy mode; otherwise, the value of *mode
94  // is undefined, and is not guaranteed to be preserved.
95  // Any occurrences of VCD_NOOP in the opcode stream
96  // are skipped over and ignored, not returned.
97  // If Init() was not called before calling this method, then
98  // VCD_INSTRUCTION_ERROR will be returned.
99  //
100  VCDiffInstructionType GetNextInstruction(int32_t* size, unsigned char* mode);
101
102  // Puts a single instruction back onto the front of the
103  // instruction stream.  The next call to GetNextInstruction()
104  // will return the same value that was returned by the last
105  // call.  Calling UnGetInstruction() more than once before calling
106  // GetNextInstruction() will have no additional effect; you can
107  // only rewind one instruction.
108  //
109  void UnGetInstruction() {
110    if (last_instruction_start_) {
111      if (last_instruction_start_ > *instructions_and_sizes_) {
112        VCD_DFATAL << "Internal error: last_instruction_start past end of "
113                      "instructions_and_sizes in UnGetInstruction" << VCD_ENDL;
114      }
115      *instructions_and_sizes_ = last_instruction_start_;
116      if ((pending_second_instruction_ != kNoOpcode) &&
117          (last_pending_second_instruction_ != kNoOpcode)) {
118        VCD_DFATAL << "Internal error: two pending instructions in a row "
119                      "in UnGetInstruction" << VCD_ENDL;
120      }
121      pending_second_instruction_ = last_pending_second_instruction_;
122    }
123  }
124
125 private:
126  // A pointer to the code table.  This is the object that will be used
127  // to interpret opcodes in GetNextInstruction().
128  const VCDiffCodeTableData* code_table_data_;
129
130  // If the default code table is not being used, then space for the
131  // code table data will be allocated using this pointer and freed
132  // when the VCDiffCodeTableReader is destroyed.  This will keep the
133  // code that uses the object from having to worry about memory
134  // management for the non-standard code table, whose contents have
135  // been read as part of the encoded data file/stream.
136  //
137  std::auto_ptr<VCDiffCodeTableData> non_default_code_table_data_;
138
139  const char** instructions_and_sizes_;
140  const char* instructions_and_sizes_end_;
141  const char* last_instruction_start_;
142  OpcodeOrNone pending_second_instruction_;
143  OpcodeOrNone last_pending_second_instruction_;
144
145  // Making these private avoids implicit copy constructor & assignment operator
146  VCDiffCodeTableReader(const VCDiffCodeTableReader&);
147  void operator=(const VCDiffCodeTableReader&);
148};
149
150};  // namespace open_vcdiff
151
152#endif  // OPEN_VCDIFF_DECODETABLE_H_
153