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_VCDECODER_H_
17#define OPEN_VCDIFF_VCDECODER_H_
18
19#include <stddef.h>  // size_t
20#include <string>
21#include "google/output_string.h"
22
23namespace open_vcdiff {
24
25class VCDiffStreamingDecoderImpl;
26
27// A streaming decoder class.  Takes a dictionary (source) file and a delta
28// file, and produces the original target file.  It is intended to process
29// the partial contents of the delta file as they arrive, in "chunks".
30// As soon as a chunk of bytes is received from a file read or from a network
31// transmission, it can be passed to DecodeChunk(), which will then output
32// as much of the target file as it can.
33//
34// The client should use this class as follows:
35//    VCDiffStreamingDecoder v;
36//    v.StartDecoding(dictionary_ptr, dictionary_size);
37//    while (any data left) {
38//      if (!v.DecodeChunk(data, len, &output_string)) {
39//        handle error;
40//        break;
41//      }
42//      process(output_string);  // might have no new data, though
43//    }
44//    if (!v.FinishDecoding()) { ... handle error ... }
45//
46// I.e., the allowed pattern of calls is
47//    StartDecoding DecodeChunk* FinishDecoding
48//
49// NOTE: It is not necessary to call FinishDecoding if DecodeChunk
50//       returns false.  When DecodeChunk returns false to signal an
51//       error, it resets its state and is ready for a new StartDecoding.
52//       If FinishDecoding is called, it will also return false.
53//
54class VCDiffStreamingDecoder {
55 public:
56  VCDiffStreamingDecoder();
57  ~VCDiffStreamingDecoder();
58
59  // Resets the dictionary contents to "dictionary_ptr[0,dictionary_size-1]"
60  // and sets up the data structures for decoding.  Note that the dictionary
61  // contents are not copied, and the client is responsible for ensuring that
62  // dictionary_ptr is valid until FinishDecoding is called.
63  //
64  void StartDecoding(const char* dictionary_ptr, size_t dictionary_size);
65
66  // Accepts "data[0,len-1]" as additional data received in the
67  // compressed stream.  If any chunks of data can be fully decoded,
68  // they are appended to output_string.
69  //
70  // Returns true on success, and false if the data was malformed
71  // or if there was an error in decoding it (e.g. out of memory, etc.).
72  //
73  // Note: we *append*, so the old contents of output_string stick around.
74  // This convention differs from the non-streaming Encode/Decode
75  // interfaces in VCDiffDecoder.
76  //
77  // output_string is guaranteed to be resized no more than once for each
78  // window in the VCDIFF delta file.  This rule is irrespective
79  // of the number of calls to DecodeChunk().
80  //
81  template<class OutputType>
82  bool DecodeChunk(const char* data, size_t len, OutputType* output) {
83    OutputString<OutputType> output_string(output);
84    return DecodeChunkToInterface(data, len, &output_string);
85  }
86
87  bool DecodeChunkToInterface(const char* data, size_t len,
88                              OutputStringInterface* output_string);
89
90  // Finishes decoding after all data has been received.  Returns true
91  // if decoding of the entire stream was successful.  FinishDecoding()
92  // must be called for the current target before StartDecoding() can be
93  // called for a different target.
94  //
95  bool FinishDecoding();
96
97  // *** Adjustable parameters ***
98
99  // Specifies the maximum allowable target file size.  If the decoder
100  // encounters a delta file that would cause it to create a target file larger
101  // than this limit, it will log an error and stop decoding.  If the decoder is
102  // applied to delta files whose sizes vary greatly and whose contents can be
103  // trusted, then a value larger than the the default value (64 MB) can be
104  // specified to allow for maximum flexibility.  On the other hand, if the
105  // input data is known never to exceed a particular size, and/or the input
106  // data may be maliciously constructed, a lower value can be supplied in order
107  // to guard against running out of memory or swapping to disk while decoding
108  // an extremely large target file.  The argument must be between 0 and
109  // INT32_MAX (2G); if it is within these bounds, the function will set the
110  // limit and return true.  Otherwise, the function will return false and will
111  // not change the limit.  Setting the limit to 0 will cause all decode
112  // operations of non-empty target files to fail.
113  bool SetMaximumTargetFileSize(size_t new_maximum_target_file_size);
114
115  // Specifies the maximum allowable target *window* size.  (A target file is
116  // composed of zero or more target windows.)  If the decoder encounters a
117  // delta window that would cause it to create a target window larger
118  // than this limit, it will log an error and stop decoding.
119  bool SetMaximumTargetWindowSize(size_t new_maximum_target_window_size);
120
121  // This interface must be called before StartDecoding().  If its argument
122  // is true, then the VCD_TARGET flag can be specified to allow the source
123  // segment to be chosen from the previously-decoded target data.  (This is the
124  // default behavior.)  If it is false, then specifying the VCD_TARGET flag is
125  // considered an error, and the decoder does not need to keep in memory any
126  // decoded target data prior to the current window.
127  void SetAllowVcdTarget(bool allow_vcd_target);
128
129 private:
130  VCDiffStreamingDecoderImpl* const impl_;
131
132  // Make the copy constructor and assignment operator private
133  // so that they don't inadvertently get used.
134  explicit VCDiffStreamingDecoder(const VCDiffStreamingDecoder&);
135  void operator=(const VCDiffStreamingDecoder&);
136};
137
138// A simpler (non-streaming) interface to the VCDIFF decoder that can be used
139// if the entire delta file is available.
140//
141class VCDiffDecoder {
142 public:
143  typedef std::string string;
144
145  VCDiffDecoder() { }
146  ~VCDiffDecoder() { }
147
148  /***** Simple interface *****/
149
150  // Replaces old contents of "*target" with the result of decoding
151  // the bytes found in "encoding."
152  //
153  // Returns true if "encoding" was a well-formed sequence of
154  // instructions, and returns false if not.
155  //
156  template<class OutputType>
157  bool Decode(const char* dictionary_ptr,
158              size_t dictionary_size,
159              const string& encoding,
160              OutputType* target) {
161    OutputString<OutputType> output_string(target);
162    return DecodeToInterface(dictionary_ptr,
163                             dictionary_size,
164                             encoding,
165                             &output_string);
166  }
167
168 private:
169  bool DecodeToInterface(const char* dictionary_ptr,
170                         size_t dictionary_size,
171                         const string& encoding,
172                         OutputStringInterface* target);
173
174  VCDiffStreamingDecoder decoder_;
175
176  // Make the copy constructor and assignment operator private
177  // so that they don't inadvertently get used.
178  explicit VCDiffDecoder(const VCDiffDecoder&);
179  void operator=(const VCDiffDecoder&);
180};
181
182};  // namespace open_vcdiff
183
184#endif  // OPEN_VCDIFF_VCDECODER_H_
185