aboutsummaryrefslogtreecommitdiff
path: root/src/decodetable.h
blob: f59fc1574bed3500179df067ca5353ae15fe837e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2008 Google Inc.
// Author: Lincoln Smith
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef OPEN_VCDIFF_DECODETABLE_H_
#define OPEN_VCDIFF_DECODETABLE_H_

#include <config.h>
#include <stddef.h>     // NULL
#include <stdint.h>     // int32_t
#include <memory>       // auto_ptr
#include "codetable.h"  // VCDiffInstructi...
#include "logging.h"

namespace open_vcdiff {

// This class is used by the decoder.  It can use a standard or
// non-standard code table, and will translate the opcodes in the code table
// into delta instructions.
//
// NOT threadsafe.
//
class VCDiffCodeTableReader {
 public:
  // When constructed, the object will be set up to use the default code table.
  // If a non-default code table is to be used, then UseCodeTable()
  // should be called after the VCDiffCodeTableReader has been constructed.
  // In any case, the Init() method must be called before GetNextInstruction()
  // may be used.
  //
  VCDiffCodeTableReader();

  // Sets up a non-standard code table.  The caller
  // may free the memory occupied by the argument code table after
  // passing it to this method, because the argument code table
  // allocates space to store a copy of it.
  // UseCodeTable() may be called either before or after calling Init().
  // Returns true if the code table was accepted, or false if the
  // argument did not appear to be a valid code table.
  //
  bool UseCodeTable(const VCDiffCodeTableData& code_table_data,
                    unsigned char max_mode);

  // Defines the buffer containing the instructions and sizes.
  // This method must be called before GetNextInstruction() may be used.
  // Init() may be called any number of times to reset the state of
  // the object.
  //
  void Init(const char** instructions_and_sizes,
            const char* instructions_and_sizes_end) {
    instructions_and_sizes_ = instructions_and_sizes;
    instructions_and_sizes_end_ = instructions_and_sizes_end;
    last_instruction_start_ = NULL;
    pending_second_instruction_ = kNoOpcode;
    last_pending_second_instruction_ = kNoOpcode;
  }

  // Updates the pointers to the buffer containing the instructions and sizes,
  // but leaves the rest of the reader state intact, so that (for example)
  // any pending second instruction or unread instruction will still be
  // read when requested.  NOTE: UnGetInstruction() will not work immediately
  // after using UpdatePointers(); GetNextInstruction() must be called first.
  //
  void UpdatePointers(const char** instructions_and_sizes,
                      const char* instructions_and_sizes_end) {
    instructions_and_sizes_ = instructions_and_sizes;
    instructions_and_sizes_end_ = instructions_and_sizes_end;
    last_instruction_start_ = *instructions_and_sizes;
    // pending_second_instruction_ is unchanged
    last_pending_second_instruction_ = pending_second_instruction_;
  }

  // Returns the next instruction from the stream of opcodes,
  // or VCD_INSTRUCTION_END_OF_DATA if the end of the opcode stream is reached,
  // or VCD_INSTRUCTION_ERROR if an error occurred.
  // In the first of these cases, increments *instructions_and_sizes_
  // past the values it reads, and populates *size
  // with the corresponding size for the returned instruction;
  // otherwise, the value of *size is undefined, and is not
  // guaranteed to be preserved.
  // If the instruction returned is VCD_COPY, *mode will
  // be populated with the copy mode; otherwise, the value of *mode
  // is undefined, and is not guaranteed to be preserved.
  // Any occurrences of VCD_NOOP in the opcode stream
  // are skipped over and ignored, not returned.
  // If Init() was not called before calling this method, then
  // VCD_INSTRUCTION_ERROR will be returned.
  //
  VCDiffInstructionType GetNextInstruction(int32_t* size, unsigned char* mode);

  // Puts a single instruction back onto the front of the
  // instruction stream.  The next call to GetNextInstruction()
  // will return the same value that was returned by the last
  // call.  Calling UnGetInstruction() more than once before calling
  // GetNextInstruction() will have no additional effect; you can
  // only rewind one instruction.
  //
  void UnGetInstruction() {
    if (last_instruction_start_) {
      if (last_instruction_start_ > *instructions_and_sizes_) {
        VCD_DFATAL << "Internal error: last_instruction_start past end of "
                      "instructions_and_sizes in UnGetInstruction" << VCD_ENDL;
      }
      *instructions_and_sizes_ = last_instruction_start_;
      if ((pending_second_instruction_ != kNoOpcode) &&
          (last_pending_second_instruction_ != kNoOpcode)) {
        VCD_DFATAL << "Internal error: two pending instructions in a row "
                      "in UnGetInstruction" << VCD_ENDL;
      }
      pending_second_instruction_ = last_pending_second_instruction_;
    }
  }

 private:
  // A pointer to the code table.  This is the object that will be used
  // to interpret opcodes in GetNextInstruction().
  const VCDiffCodeTableData* code_table_data_;

  // If the default code table is not being used, then space for the
  // code table data will be allocated using this pointer and freed
  // when the VCDiffCodeTableReader is destroyed.  This will keep the
  // code that uses the object from having to worry about memory
  // management for the non-standard code table, whose contents have
  // been read as part of the encoded data file/stream.
  //
  std::auto_ptr<VCDiffCodeTableData> non_default_code_table_data_;

  const char** instructions_and_sizes_;
  const char* instructions_and_sizes_end_;
  const char* last_instruction_start_;
  OpcodeOrNone pending_second_instruction_;
  OpcodeOrNone last_pending_second_instruction_;

  // Making these private avoids implicit copy constructor & assignment operator
  VCDiffCodeTableReader(const VCDiffCodeTableReader&);
  void operator=(const VCDiffCodeTableReader&);
};

};  // namespace open_vcdiff

#endif  // OPEN_VCDIFF_DECODETABLE_H_