10a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Copyright 2008 Google Inc.
20a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Author: Lincoln Smith
30a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//
40a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Licensed under the Apache License, Version 2.0 (the "License");
50a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// you may not use this file except in compliance with the License.
60a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// You may obtain a copy of the License at
70a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//
80a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//      http://www.apache.org/licenses/LICENSE-2.0
90a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//
100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Unless required by applicable law or agreed to in writing, software
110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// distributed under the License is distributed on an "AS IS" BASIS,
120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// See the License for the specific language governing permissions and
140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// limitations under the License.
150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath//
160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// A command-line interface to the open-vcdiff library.
170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <config.h>
190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <assert.h>
200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <errno.h>
210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#ifdef WIN32
220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <fcntl.h>
230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <io.h>
240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif  // WIN32
250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <stdio.h>
260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <string.h>  // strerror
270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <iostream>
280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <memory>
290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <string>
300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <vector>
310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "gflags/gflags.h"
320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "google/vcdecoder.h"
330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include "google/vcencoder.h"
340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#ifndef HAS_GLOBAL_STRING
360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathusing std::string;
370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif  // !HAS_GLOBAL_STRING
380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathusing google::GetCommandLineFlagInfoOrDie;
390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathusing google::ShowUsageWithFlagsRestrict;
400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathstatic const size_t kDefaultMaxTargetSize = 1 << 26;      // 64 MB
420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Definitions of command-line flags
440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_string(dictionary, "",
450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              "File containing dictionary data (required)");
460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_string(target, "",
470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              "Target file (default is stdin for encode, stdout for decode");
480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_string(delta, "",
490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              "Encoded delta file (default is stdout for encode, "
500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              "stdin for decode");
510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// --buffersize is the maximum allowable size of a target window.
520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// This value may be increased if there is sufficient memory available.
530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_uint64(buffersize, 1 << 20,  // 1 MB
540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              "Buffer size for reading input file");
550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_bool(allow_vcd_target, true,
560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath            "If false, the decoder issues an error when the VCD_TARGET flag "
570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath            "is encountered");
580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_bool(checksum, false,
590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath            "Include an Adler32 checksum of the target data when encoding");
600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_bool(interleaved, false, "Use interleaved format");
610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_bool(json, false, "Output diff in the JSON format when encoding");
620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_bool(stats, false, "Report compression percentage");
630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_bool(target_matches, false, "Find duplicate strings in target data"
640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                   " as well as dictionary data");
650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_uint64(max_target_file_size, kDefaultMaxTargetSize,
660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              "Maximum target file size allowed by decoder");
670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathDEFINE_uint64(max_target_window_size, kDefaultMaxTargetSize,
680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              "Maximum target window size allowed by decoder");
690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathstatic const char* const kUsageString =
710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    " {encode | delta | decode | patch }[ <options> ]\n"
720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    "encode or delta: create delta file from dictionary and target file\n"
730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    "decode or patch: reconstruct target file from dictionary and delta file";
740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathnamespace open_vcdiff {
760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathclass VCDiffFileBasedCoder {
780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath public:
790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  VCDiffFileBasedCoder();
800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  ~VCDiffFileBasedCoder();
810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Once the command-line arguments have been parsed, these functions
830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // will use the supplied options to carry out a file-based encode
840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // or decode operation.
850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool Encode();
860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool Decode();
870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool DecodeAndCompare();  // for "vcdiff test"; compare target with original
880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath private:
900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Determines the size of the file.  The given file must be an input file
910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // opened for reading only, not an input stream such as stdin.  The function
920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // returns true and populates file_size if successful; otherwise, it returns
930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // false.
940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  static bool FileSize(FILE* file, size_t* file_size);
950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Opens a file for incremental reading.  file_name is the name of the file
970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // to be opened.  file_type should be a descriptive name (like "target") for
980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // use in log messages.  If successful, returns true and sets *file to a
990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // valid input file, *buffer to a region of memory allocated using malloc()
1000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // (so the caller must release it using free()), and buffer_size to the size
1010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // of the buffer, which will not be larger than the size of the file, and
1020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // will not be smaller than the --buffersize option.  If the function fails,
1030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // it outputs a log message and returns false.
1040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool OpenFileForReading(const string& file_name,
1050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                          const char* file_type,
1060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                          FILE** file,
1070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                          std::vector<char>* buffer);
1080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Opens the dictionary file and reads it into a newly allocated buffer.
1100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // If successful, returns true and populates dictionary_ with the dictionary
1110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // contents; otherwise, returns false.
1120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool OpenDictionary();
1130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Opens the input file (the delta or target file) for reading.
1150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Allocates space for the input buffer.  If successful,
1160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // input_file_ will be valid and input_buffer_ will be allocated.
1170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool OpenInputFile() {
1180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return OpenFileForReading(input_file_name_,
1190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              input_file_type_,
1200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              &input_file_,
1210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              &input_buffer_);
1220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Opens the output file (the target or delta file) for writing.
1250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // If successful, output_file_ will be valid.
1260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool OpenOutputFile();
1270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Opens the output file (the target file) for comparison against the decoded
1290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // output when using "vcdiff test".
1300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool OpenOutputFileForCompare() {
1310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return OpenFileForReading(output_file_name_,
1320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              output_file_type_,
1330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              &output_file_,
1340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              &compare_buffer_);
1350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
1360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Reads as much input data as possible from the input file
1380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // into input_buffer_.  If successful, returns true and sets *bytes_read
1390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // to the number of bytes read into input_buffer_.  If an error occurs,
1400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // writes an error log message and returns false.
1410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool ReadInput(size_t* bytes_read);
1420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Writes the contents of output to output_file_.  If successful, returns
1440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // true.  If an error occurs, writes an error log message and returns false.
1450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool WriteOutput(const string& output);
1460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Reads a number of bytes from output_file_ equal to the size of output,
1480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // and compares to make sure they match the contents of output.  If the bytes
1490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // do not match, or if end of file is reached before the expected number of
1500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // bytes have been read, or a read error occurs, the function returns false;
1510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // otherwise, returns true.
1520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  bool CompareOutput(const string& output);
1530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Dictionary contents.  The entire dictionary file will be read into memory.
1550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  std::vector<char> dictionary_;
1560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  std::auto_ptr<open_vcdiff::HashedDictionary> hashed_dictionary_;
1580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // These should be set to either "delta" or "target".  They are only
1600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // used in log messages such as "Error opening delta file..."
1610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  const char* input_file_type_;
1620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  const char* output_file_type_;
1630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // The filenames used for input and output.  Will be empty if stdin
1650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // or stdout is being used.
1660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  string input_file_name_;
1670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  string output_file_name_;
1680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // stdio-style file handles for the input and output files and the dictionary.
1700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // When encoding, input_file_ is the target file and output_file_ is the delta
1710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // file; when decoding, the reverse is true.  The dictionary is always read
1720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // from a file rather than from standard input.
1730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  FILE* input_file_;
1740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  FILE* output_file_;
1750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // A memory buffer used to load the input file into memory.  If the input
1770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // comes from stdin because no input file was specified, then the size of
1780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // input_buffer_ will be the value specified by the --buffersize option.
1790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // If the input comes from a file, then the buffer will be allocated to match
1800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // the file size, if possible.  However, the buffer will not exceed
1810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // --buffersize bytes in length.
1820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  std::vector<char> input_buffer_;
1830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // A memory buffer used to load the output file into memory for comparison
1850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // if "vcdiff test" is specified.
1860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  std::vector<char> compare_buffer_;
1870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Making these private avoids implicit copy constructor & assignment operator
1890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  VCDiffFileBasedCoder(const VCDiffFileBasedCoder&);  // NOLINT
1900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  void operator=(const VCDiffFileBasedCoder&);
1910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath};
1920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathinline VCDiffFileBasedCoder::VCDiffFileBasedCoder()
1940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    : input_file_type_(""),
1950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      output_file_type_(""),
1960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      input_file_(NULL),
1970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      output_file_(NULL) { }
1980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
1990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathVCDiffFileBasedCoder::~VCDiffFileBasedCoder() {
2000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (input_file_ && (input_file_ != stdin)) {
2010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    fclose(input_file_);
2020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    input_file_ = NULL;
2030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (output_file_ && (output_file_ != stdout)) {
2050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    fclose(output_file_);
2060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output_file_ = NULL;
2070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::FileSize(FILE* file, size_t* file_size) {
2110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  long initial_position = ftell(file);
2120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (fseek(file, 0, SEEK_END) != 0) {
2130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  *file_size = static_cast<size_t>(ftell(file));
2160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (fseek(file, initial_position, SEEK_SET) != 0) {
2170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
2200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::OpenDictionary() {
2230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  assert(dictionary_.empty());
2240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  assert(!FLAGS_dictionary.empty());
2250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  FILE* dictionary_file = fopen(FLAGS_dictionary.c_str(), "rb");
2260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!dictionary_file) {
2270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Error opening dictionary file '" << FLAGS_dictionary
2280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "': " << strerror(errno) << std::endl;
2290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  size_t dictionary_size = 0U;
2320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!FileSize(dictionary_file, &dictionary_size)) {
2330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Error finding size of dictionary file '" << FLAGS_dictionary
2340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "': " << strerror(errno) << std::endl;
2350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
2360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  dictionary_.resize(dictionary_size);
2380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (dictionary_size > 0) {
2390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (fread(&dictionary_[0], 1, dictionary_size, dictionary_file)
2400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath            != dictionary_size) {
2410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << "Unable to read dictionary file '" << FLAGS_dictionary
2420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << "': " << strerror(errno) << std::endl;
2430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      fclose(dictionary_file);
2440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      dictionary_.clear();
2450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
2460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
2470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  fclose(dictionary_file);
2490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
2500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::OpenFileForReading(const string& file_name,
2530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                              const char* file_type,
2540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                              FILE** file,
2550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                              std::vector<char>* buffer) {
2560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  assert(buffer->empty());
2570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  size_t buffer_size = 0U;
2580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!*file && file_name.empty()) {
2590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#ifdef WIN32
2600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    _setmode(_fileno(stdin), _O_BINARY);
2610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif
2620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    *file = stdin;
2630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    buffer_size = static_cast<size_t>(FLAGS_buffersize);
2640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else {
2650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!*file) {
2660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      *file = fopen(file_name.c_str(), "rb");
2670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      if (!*file) {
2680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        std::cerr << "Error opening " << file_type << " file '"
2690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  << file_name << "': " << strerror(errno) << std::endl;
2700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return false;
2710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      }
2720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
2730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t file_size = 0U;
2740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!FileSize(*file, &file_size)) {
2750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << "Error finding size of " << file_type << " file '"
2760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << file_name << "': " << strerror(errno) << std::endl;
2770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
2780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
2790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    buffer_size = static_cast<size_t>(FLAGS_buffersize);
2800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (file_size < buffer_size) {
2810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      // Allocate just enough memory to store the entire file
2820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      buffer_size = file_size;
2830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
2840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
2850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  buffer->resize(buffer_size);
2860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
2870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
2880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
2890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Opens the output file for streamed read operations using the
2900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// standard C I/O library, i.e., fopen(), fwrite(), fclose().
2910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// No output buffer is allocated because the encoded/decoded output
2920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// is constructed progressively using a std::string object
2930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// whose buffer is resized as needed.
2940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::OpenOutputFile() {
2950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (output_file_name_.empty()) {
2960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#ifdef WIN32
2970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    _setmode(_fileno(stdout), _O_BINARY);
2980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif
2990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output_file_ = stdout;
3000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else {
3010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output_file_ = fopen(output_file_name_.c_str(), "wb");
3020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!output_file_) {
3030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << "Error opening " << output_file_type_ << " file '"
3040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << output_file_name_
3050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << "': " << strerror(errno) << std::endl;
3060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
3070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
3080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
3100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
3110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
3120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::ReadInput(size_t* bytes_read) {
3130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Read from file or stdin
3140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  *bytes_read = fread(&input_buffer_[0], 1, input_buffer_.size(), input_file_);
3150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (ferror(input_file_)) {
3160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Error reading from " << input_file_type_ << " file '"
3170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << input_file_name_
3180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "': " << strerror(errno) << std::endl;
3190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
3200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
3220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
3230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
3240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::WriteOutput(const string& output) {
3250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!output.empty()) {
3260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // Some new output has been generated and is ready to be written
3270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // to the output file or to stdout.
3280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    fwrite(output.data(), 1, output.size(), output_file_);
3290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (ferror(output_file_)) {
3300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << "Error writing " << output.size() << " bytes to "
3310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << output_file_type_ << " file '" << output_file_name_
3320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << "': " << strerror(errno) << std::endl;
3330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
3340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
3350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
3370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
3380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
3390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::CompareOutput(const string& output) {
3400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!output.empty()) {
3410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t output_size = output.size();
3420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // Some new output has been generated and is ready to be compared against
3430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // the output file.
3440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (output_size > compare_buffer_.size()) {
3450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      compare_buffer_.resize(output_size);
3460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
3470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t bytes_read = fread(&compare_buffer_[0],
3480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              1,
3490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              output_size,
3500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                              output_file_);
3510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (ferror(output_file_)) {
3520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << "Error reading from " << output_file_type_ << " file '"
3530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << output_file_name_ << "': " << strerror(errno) << std::endl;
3540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
3550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
3560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (bytes_read < output_size) {
3570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << "Decoded target is longer than original target file"
3580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << std::endl;
3590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
3600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
3610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (output.compare(0, output_size, &compare_buffer_[0], bytes_read) != 0) {
3620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << "Original target file does not match decoded target"
3630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << std::endl;
3640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
3650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
3660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
3680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
3690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
3700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::Encode() {
3710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  input_file_type_ = "target";
3720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  input_file_name_ = FLAGS_target;
3730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_file_type_ = "delta";
3740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_file_name_ = FLAGS_delta;
3750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!OpenDictionary() || !OpenInputFile() || !OpenOutputFile()) {
3760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
3770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Issue 6: Visual Studio STL produces a runtime exception
3790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // if &dictionary_[0] is attempted for an empty dictionary.
3800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (dictionary_.empty()) {
3810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    hashed_dictionary_.reset(new open_vcdiff::HashedDictionary("", 0));
3820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else {
3830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    hashed_dictionary_.reset(
3840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        new open_vcdiff::HashedDictionary(&dictionary_[0],
3850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                          dictionary_.size()));
3860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!hashed_dictionary_->Init()) {
3880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Error initializing hashed dictionary" << std::endl;
3890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
3900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  VCDiffFormatExtensionFlags format_flags = open_vcdiff::VCD_STANDARD_FORMAT;
3920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (FLAGS_interleaved) {
3930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    format_flags |= open_vcdiff::VCD_FORMAT_INTERLEAVED;
3940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (FLAGS_checksum) {
3960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    format_flags |= open_vcdiff::VCD_FORMAT_CHECKSUM;
3970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
3980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (FLAGS_json) {
3990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    format_flags |= open_vcdiff::VCD_FORMAT_JSON;
4000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
4010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  open_vcdiff::VCDiffStreamingEncoder encoder(hashed_dictionary_.get(),
4020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                              format_flags,
4030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                                              FLAGS_target_matches);
4040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  string output;
4050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  size_t input_size = 0;
4060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  size_t output_size = 0;
4070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  {
4080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!encoder.StartEncoding(&output)) {
4090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << "Error during encoder initialization" << std::endl;
4100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
4110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
4120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
4130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  do {
4140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t bytes_read = 0;
4150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!WriteOutput(output) || !ReadInput(&bytes_read)) {
4160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
4170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
4180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output_size += output.size();
4190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output.clear();
4200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (bytes_read > 0) {
4210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      input_size += bytes_read;
4220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      if (!encoder.EncodeChunk(&input_buffer_[0], bytes_read, &output)) {
4230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        std::cerr << "Error trying to encode data chunk of length "
4240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  << bytes_read << std::endl;
4250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return false;
4260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      }
4270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
4280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } while (!feof(input_file_));
4290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  encoder.FinishEncoding(&output);
4300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!WriteOutput(output)) {
4310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
4320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
4330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_size += output.size();
4340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output.clear();
4350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (FLAGS_stats && (input_size > 0)) {
4360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Original size: " << input_size
4370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "\tCompressed size: " << output_size << " ("
4380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << ((static_cast<double>(output_size) / input_size) * 100)
4390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "% of original)" << std::endl;
4400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
4410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
4420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
4430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
4440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::Decode() {
4450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  input_file_type_ = "delta";
4460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  input_file_name_ = FLAGS_delta;
4470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_file_type_ = "target";
4480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_file_name_ = FLAGS_target;
4490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!OpenDictionary() || !OpenInputFile() || !OpenOutputFile()) {
4500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
4510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
4520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
4530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  open_vcdiff::VCDiffStreamingDecoder decoder;
4540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  decoder.SetMaximumTargetFileSize(
4550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      static_cast<size_t>(FLAGS_max_target_file_size));
4560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  decoder.SetMaximumTargetWindowSize(
4570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      static_cast<size_t>(FLAGS_max_target_window_size));
4580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  decoder.SetAllowVcdTarget(FLAGS_allow_vcd_target);
4590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  string output;
4600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  size_t input_size = 0;
4610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  size_t output_size = 0;
4620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Issue 6: Visual Studio STL produces a runtime exception
4630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // if &dictionary_[0] is attempted for an empty dictionary.
4640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (dictionary_.empty()) {
4650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    decoder.StartDecoding("", 0);
4660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else {
4670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    decoder.StartDecoding(&dictionary_[0], dictionary_.size());
4680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
4690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
4700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  do {
4710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t bytes_read = 0;
4720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!ReadInput(&bytes_read)) {
4730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
4740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
4750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (bytes_read > 0) {
4760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      input_size += bytes_read;
4770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      if (!decoder.DecodeChunk(&input_buffer_[0], bytes_read, &output)) {
4780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        std::cerr << "Error trying to decode data chunk of length "
4790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  << bytes_read << std::endl;
4800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return false;
4810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      }
4820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
4830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!WriteOutput(output)) {
4840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
4850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
4860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output_size += output.size();
4870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output.clear();
4880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } while (!feof(input_file_));
4890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!decoder.FinishDecoding()) {
4900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Decode error; '" << FLAGS_delta
4910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << " may not be a valid VCDIFF delta file" << std::endl;
4920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
4930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
4940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!WriteOutput(output)) {
4950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
4960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
4970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_size += output.size();
4980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output.clear();
4990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (FLAGS_stats && (output_size > 0)) {
5000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Decompressed size: " << output_size
5010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "\tCompressed size: " << input_size << " ("
5020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << ((static_cast<double>(input_size) / output_size) * 100)
5030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "% of original)" << std::endl;
5040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
5060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
5070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
5080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool VCDiffFileBasedCoder::DecodeAndCompare() {
5090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  input_file_type_ = "delta";
5100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  input_file_name_ = FLAGS_delta;
5110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_file_type_ = "target";
5120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_file_name_ = FLAGS_target;
5130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!OpenDictionary() || !OpenInputFile() || !OpenOutputFileForCompare()) {
5140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
5150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
5170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  open_vcdiff::VCDiffStreamingDecoder decoder;
5180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  decoder.SetMaximumTargetFileSize(
5190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      static_cast<size_t>(FLAGS_max_target_file_size));
5200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  decoder.SetMaximumTargetWindowSize(
5210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      static_cast<size_t>(FLAGS_max_target_window_size));
5220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  decoder.SetAllowVcdTarget(FLAGS_allow_vcd_target);
5230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  string output;
5240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  size_t input_size = 0;
5250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  size_t output_size = 0;
5260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // Issue 6: Visual Studio STL produces a runtime exception
5270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  // if &dictionary_[0] is attempted for an empty dictionary.
5280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (dictionary_.empty()) {
5290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    decoder.StartDecoding("", 0);
5300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else {
5310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    decoder.StartDecoding(&dictionary_[0], dictionary_.size());
5320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
5340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  do {
5350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    size_t bytes_read = 0;
5360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!ReadInput(&bytes_read)) {
5370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
5380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
5390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (bytes_read > 0) {
5400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      input_size += bytes_read;
5410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      if (!decoder.DecodeChunk(&input_buffer_[0], bytes_read, &output)) {
5420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        std::cerr << "Error trying to decode data chunk of length "
5430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                  << bytes_read << std::endl;
5440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return false;
5450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      }
5460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
5470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!CompareOutput(output)) {
5480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return false;
5490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
5500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output_size += output.size();
5510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    output.clear();
5520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } while (!feof(input_file_));
5530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!decoder.FinishDecoding()) {
5540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Decode error; '" << FLAGS_delta
5550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << " may not be a valid VCDIFF delta file" << std::endl;
5560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
5570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!CompareOutput(output)) {
5590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
5600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output_size += output.size();
5620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  output.clear();
5630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (fgetc(output_file_) != EOF) {
5640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Decoded target is shorter than original target file"
5650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << std::endl;
5660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
5670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (ferror(output_file_)) {
5690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Error reading end-of-file indicator from target file"
5700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << std::endl;
5710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return false;
5720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (FLAGS_stats && (output_size > 0)) {
5740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << "Decompressed size: " << output_size
5750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "\tCompressed size: " << input_size << " ("
5760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << ((static_cast<double>(input_size) / output_size) * 100)
5770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << "% of original)" << std::endl;
5780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return true;
5800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
5810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
5820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}  // namespace open_vcdiff
5830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath
5840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathint main(int argc, char** argv) {
5850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  const char* const command_name = argv[0];
5860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  google::SetUsageMessage(kUsageString);
5870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  google::ParseCommandLineFlags(&argc, &argv, true);
5880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (argc != 2) {
5890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << command_name << ": Must specify exactly one command option"
5900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << std::endl;
5910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    ShowUsageWithFlagsRestrict(command_name, "vcdiff");
5920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return 1;
5930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
5940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  const char* const command_option = argv[1];
5950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (FLAGS_dictionary.empty()) {
5960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << command_name << " " << command_option
5970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << ": Must specify --dictionary <file-name>" << std::endl;
5980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    ShowUsageWithFlagsRestrict(command_name, "vcdiff");
5990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return 1;
6000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
6010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if (!GetCommandLineFlagInfoOrDie("buffersize").is_default &&
6020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath       (FLAGS_buffersize == 0)) {
6030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << command_name << ": Option --buffersize cannot be 0"
6040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << std::endl;
6050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    ShowUsageWithFlagsRestrict(command_name, "vcdiff");
6060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return 1;
6070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
6080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  if ((strcmp(command_option, "encode") == 0) ||
6090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      (strcmp(command_option, "delta") == 0)) {
6100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    open_vcdiff::VCDiffFileBasedCoder coder;
6110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!coder.Encode()) {
6120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return 1;
6130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
6140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // The destructor for VCDiffFileBasedCoder will clean up the open files
6150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // and allocated memory.
6160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else if ((strcmp(command_option, "decode") == 0) ||
6170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath             (strcmp(command_option, "patch") == 0)) {
6180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    open_vcdiff::VCDiffFileBasedCoder coder;
6190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (!coder.Decode()) {
6200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return 1;
6210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
6220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else if ((strcmp(command_option, "test") == 0)) {
6230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // "vcdiff test" does not appear in the usage string, but can be
6240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // used for debugging.  It encodes, then decodes, then compares the result
6250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // with the original target. It expects the same arguments as
6260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // "vcdiff encode", with the additional requirement that the --target
6270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // and --delta file arguments must be specified, rather than using stdin
6280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // or stdout.  It produces a delta file just as for "vcdiff encode".
6290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    if (FLAGS_target.empty() || FLAGS_delta.empty()) {
6300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      std::cerr << command_name
6310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                << " test: Must specify both --target <file-name>"
6320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath                   " and --delta <file-name>" << std::endl;
6330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      return 1;
6340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
6350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    const string original_target(FLAGS_target);
6360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    // Put coder into a separate scope.
6370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    {
6380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      open_vcdiff::VCDiffFileBasedCoder coder;
6390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      if (!coder.Encode()) {
6400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return 1;
6410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      }
6420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
6430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    {
6440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      open_vcdiff::VCDiffFileBasedCoder coder;
6450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      if (!coder.DecodeAndCompare()) {
6460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath        return 1;
6470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath      }
6480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    }
6490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  } else {
6500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    std::cerr << command_name << ": Unrecognized command option "
6510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath              << command_option << std::endl;
6520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    ShowUsageWithFlagsRestrict(command_name, "vcdiff");
6530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath    return 1;
6540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  }
6550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath  return 0;
6560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath}
657