| 1 | 
 /* xdelta 3 - delta compression tools and library | 
 
 
 
 
 
 | 2 | 
  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, | 
 
 
 
 
 
 | 3 | 
  * Joshua P. MacDonald | 
 
 
 
 
 
 | 4 | 
  * | 
 
 
 
 
 
 | 5 | 
  *  This program is free software; you can redistribute it and/or modify | 
 
 
 
 
 
 | 6 | 
  *  it under the terms of the GNU General Public License as published by | 
 
 
 
 
 
 | 7 | 
  *  the Free Software Foundation; either version 2 of the License, or | 
 
 
 
 
 
 | 8 | 
  *  (at your option) any later version. | 
 
 
 
 
 
 | 9 | 
  * | 
 
 
 
 
 
 | 10 | 
  *  This program is distributed in the hope that it will be useful, | 
 
 
 
 
 
 | 11 | 
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 
 
 
 
 
 | 12 | 
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 
 
 
 
 
 | 13 | 
  *  GNU General Public License for more details. | 
 
 
 
 
 
 | 14 | 
  * | 
 
 
 
 
 
 | 15 | 
  *  You should have received a copy of the GNU General Public License | 
 
 
 
 
 
 | 16 | 
  *  along with this program; if not, write to the Free Software | 
 
 
 
 
 
 | 17 | 
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
 
 
 
 
 
 | 18 | 
  */ | 
 
 
 
 
 
 | 19 | 
  | 
 
 
 
 
 
 | 20 | 
 /* This is all the extra stuff you need for convenience to users in a command line | 
 
 
 
 
 
 | 21 | 
  * application.  It contains these major components: | 
 
 
 
 
 
 | 22 | 
  * | 
 
 
 
 
 
 | 23 | 
  * 1. VCDIFF tools | 
 
 
 
 
 
 | 24 | 
  * 2. external compression support (this is POSIX-specific). | 
 
 
 
 
 
 | 25 | 
  * 3. a general read/write loop that handles all of the Xdelta decode/encode/VCDIFF-print | 
 
 
 
 
 
 | 26 | 
  *    functions | 
 
 
 
 
 
 | 27 | 
  * 4. command-line interpreter | 
 
 
 
 
 
 | 28 | 
  * 5. an Xdelta application header which stores default filename, external compression settings | 
 
 
 
 
 
 | 29 | 
  * 6. output/error printing | 
 
 
 
 
 
 | 30 | 
  * 7. basic file support and OS interface | 
 
 
 
 
 
 | 31 | 
  */ | 
 
 
 
 
 
 | 32 | 
  | 
 
 
 
 
 
 | 33 | 
 /* TODO list: | 
 
 
 
 
 
 | 34 | 
  * 1. do exact gzip-like filename, stdout handling.  make a .vcdiff extension, refuse | 
 
 
 
 
 
 | 35 | 
  *    to encode to stdout without -cf, etc. | 
 
 
 
 
 
 | 36 | 
  * 2. Allow the user to add a comment string to the app header without disturbing the default | 
 
 
 
 
 
 | 37 | 
  *    behavior. | 
 
 
 
 
 
 | 38 | 
  * 3. "Source file must be seekable" is not actually true for encoding, given current | 
 
 
 
 
 
 | 39 | 
  *    behavior.  Allow non-seekable sources?  It would in theory let you use a fifo for | 
 
 
 
 
 
 | 40 | 
  *    the source. | 
 
 
 
 
 
 | 41 | 
  */ | 
 
 
 
 
 
 | 42 | 
  | 
 
 
 
 
 
 | 43 | 
 /* On error handling and printing: | 
 
 
 
 
 
 | 44 | 
  * | 
 
 
 
 
 
 | 45 | 
  * The xdelta library sets stream->msg to indicate what condition caused an internal | 
 
 
 
 
 
 | 46 | 
  * failure, but many failures originate here and are printed here.  The return convention | 
 
 
 
 
 
 | 47 | 
  * is 0 for success, as throughout Xdelta code, but special attention is required here for | 
 
 
 
 
 
 | 48 | 
  * the operating system calls with different error handling.  See the main_file_* routines. | 
 
 
 
 
 
 | 49 | 
  * All errors in this file have a message printed at the time of occurance.  Since some of | 
 
 
 
 
 
 | 50 | 
  * these calls occur within calls to the library, the error may end up being printed again | 
 
 
 
 
 
 | 51 | 
  * with a more general error message. | 
 
 
 
 
 
 | 52 | 
  */ | 
 
 
 
 
 
 | 53 | 
  | 
 
 
 
 
 
 | 54 | 
 /******************************************************************************************/ | 
 
 
 
 
 
 | 55 | 
  | 
 
 
 
 
 
 | 56 | 
 #ifndef XD3_POSIX | 
 
 
 
 
 
 | 57 | 
 #define XD3_POSIX 0 | 
 
 
 
 
 
 | 58 | 
 #endif | 
 
 
 
 
 
 | 59 | 
 #ifndef XD3_STDIO | 
 
 
 
 
 
 | 60 | 
 #define XD3_STDIO 0 | 
 
 
 
 
 
 | 61 | 
 #endif | 
 
 
 
 
 
 | 62 | 
 #ifndef XD3_WIN32 | 
 
 
 
 
 
 | 63 | 
 #define XD3_WIN32 0 | 
 
 
 
 
 
 | 64 | 
 #endif | 
 
 
 
 
 
 | 65 | 
  | 
 
 
 
 
 
 | 66 | 
 /* Combines xd3_strerror() and strerror() */ | 
 
 
 
 
 
 | 67 | 
 const char* xd3_mainerror(int err_num); | 
 
 
 
 
 
 | 68 | 
  | 
 
 
 
 
 
 | 69 | 
 /* XPRINTX (used by main) prefixes an "xdelta3: " to the output. */ | 
 
 
 
 
 
 | 70 | 
 #define XPR fprintf | 
 
 
 
 
 
 | 71 | 
 #define NT stderr, "xdelta3: " | 
 
 
 
 
 
 | 72 | 
  | 
 
 
 
 
 
 | 73 | 
 /* If none are set, default to posix. */ | 
 
 
 
 
 
 | 74 | 
 #if (XD3_POSIX + XD3_STDIO + XD3_WIN32) == 0 | 
 
 
 
 
 
 | 75 | 
 #undef XD3_POSIX | 
 
 
 
 
 
 | 76 | 
 #define XD3_POSIX 1 | 
 
 
 
 
 
 | 77 | 
 #endif | 
 
 
 
 
 
 | 78 | 
  | 
 
 
 
 
 
 | 79 | 
 /* Handle externally-compressed inputs. */ | 
 
 
 
 
 
 | 80 | 
 #ifndef EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 81 | 
 #define EXTERNAL_COMPRESSION 1 | 
 
 
 
 
 
 | 82 | 
 #endif | 
 
 
 
 
 
 | 83 | 
  | 
 
 
 
 
 
 | 84 | 
 #define PRINTHDR_SPECIAL -4378291 | 
 
 
 
 
 
 | 85 | 
  | 
 
 
 
 
 
 | 86 | 
 /* The number of soft-config variables.  */ | 
 
 
 
 
 
 | 87 | 
 #define XD3_SOFTCFG_VARCNT 7 | 
 
 
 
 
 
 | 88 | 
  | 
 
 
 
 
 
 | 89 | 
 /* this is used as in XPR(NT XD3_LIB_ERRMSG (stream, ret)) to print an error message | 
 
 
 
 
 
 | 90 | 
  * from the library. */ | 
 
 
 
 
 
 | 91 | 
 #define XD3_LIB_ERRMSG(stream, ret) "%s: %s\n", xd3_errstring (stream), xd3_mainerror (ret) | 
 
 
 
 
 
 | 92 | 
  | 
 
 
 
 
 
 | 93 | 
 #include <stdio.h>  /* fprintf */ | 
 
 
 
 
 
 | 94 | 
  | 
 
 
 
 
 
 | 95 | 
 #if XD3_POSIX | 
 
 
 
 
 
 | 96 | 
 #include <unistd.h> /* close, read, write... */ | 
 
 
 
 
 
 | 97 | 
 #include <sys/types.h> | 
 
 
 
 
 
 | 98 | 
 #include <fcntl.h> | 
 
 
 
 
 
 | 99 | 
 #endif | 
 
 
 
 
 
 | 100 | 
  | 
 
 
 
 
 
 | 101 | 
 #ifndef _WIN32 | 
 
 
 
 
 
 | 102 | 
 #include <unistd.h> /* lots */ | 
 
 
 
 
 
 | 103 | 
 #include <sys/time.h> /* gettimeofday() */ | 
 
 
 
 
 
 | 104 | 
 #include <sys/stat.h> /* stat() and fstat() */ | 
 
 
 
 
 
 | 105 | 
 #else | 
 
 
 
 
 
 | 106 | 
 #define strtoll _strtoi64 | 
 
 
 
 
 
 | 107 | 
 #include <sys/types.h> | 
 
 
 
 
 
 | 108 | 
 #include <sys/stat.h> | 
 
 
 
 
 
 | 109 | 
 #ifndef WIFEXITED | 
 
 
 
 
 
 | 110 | 
 #   define WIFEXITED(stat)  (((*((int *) &(stat))) & 0xff) == 0) | 
 
 
 
 
 
 | 111 | 
 #endif | 
 
 
 
 
 
 | 112 | 
 #ifndef WEXITSTATUS | 
 
 
 
 
 
 | 113 | 
 #   define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff) | 
 
 
 
 
 
 | 114 | 
 #endif | 
 
 
 
 
 
 | 115 | 
 #ifndef S_ISREG | 
 
 
 
 
 
 | 116 | 
 //#   ifdef S_IFREG | 
 
 
 
 
 
 | 117 | 
 //#       define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) | 
 
 
 
 
 
 | 118 | 
 //#   else | 
 
 
 
 
 
 | 119 | 
 #       define S_ISREG(m) 1 | 
 
 
 
 
 
 | 120 | 
 //#   endif | 
 
 
 
 
 
 | 121 | 
 #endif /* !S_ISREG */ | 
 
 
 
 
 
 | 122 | 
  | 
 
 
 
 
 
 | 123 | 
 // For standard input/output handles | 
 
 
 
 
 
 | 124 | 
 static STARTUPINFO winStartupInfo; | 
 
 
 
 
 
 | 125 | 
 #endif | 
 
 
 
 
 
 | 126 | 
  | 
 
 
 
 
 
 | 127 | 
 /****************************************************************************************** | 
 
 
 
 
 
 | 128 | 
  ENUMS and TYPES | 
 
 
 
 
 
 | 129 | 
  ******************************************************************************************/ | 
 
 
 
 
 
 | 130 | 
  | 
 
 
 
 
 
 | 131 | 
 /* These flags (mainly pertaining to main_read() operations) are set in the | 
 
 
 
 
 
 | 132 | 
  * main_file->flags variable.  All are related to with external decompression support. | 
 
 
 
 
 
 | 133 | 
  * | 
 
 
 
 
 
 | 134 | 
  * RD_FIRST causes the external decompression check when the input is first read. | 
 
 
 
 
 
 | 135 | 
  * | 
 
 
 
 
 
 | 136 | 
  * RD_NONEXTERNAL disables external decompression for reading a compressed input, in the | 
 
 
 
 
 
 | 137 | 
  * case of Xdelta inputs.  Note: Xdelta is supported as an external compression type, | 
 
 
 
 
 
 | 138 | 
  * which makes is the reason for this flag.  An example to justify this is: to create a | 
 
 
 
 
 
 | 139 | 
  * delta between two files that are VCDIFF-compressed.  Two external Xdelta decoders are | 
 
 
 
 
 
 | 140 | 
  * run to supply decompressed source and target inputs to the Xdelta encoder. */ | 
 
 
 
 
 
 | 141 | 
 typedef enum | 
 
 
 
 
 
 | 142 | 
 { | 
 
 
 
 
 
 | 143 | 
   RD_FIRST        = (1 << 0), | 
 
 
 
 
 
 | 144 | 
   RD_NONEXTERNAL  = (1 << 1), | 
 
 
 
 
 
 | 145 | 
   RD_EXTERNAL_V1  = (1 << 2), | 
 
 
 
 
 
 | 146 | 
 } xd3_read_flags; | 
 
 
 
 
 
 | 147 | 
  | 
 
 
 
 
 
 | 148 | 
 /* main_file->mode values */ | 
 
 
 
 
 
 | 149 | 
 typedef enum | 
 
 
 
 
 
 | 150 | 
 { | 
 
 
 
 
 
 | 151 | 
   XO_READ  = 0, | 
 
 
 
 
 
 | 152 | 
   XO_WRITE = 1, | 
 
 
 
 
 
 | 153 | 
 } main_file_modes; | 
 
 
 
 
 
 | 154 | 
  | 
 
 
 
 
 
 | 155 | 
 /* Main commands.  For example, CMD_PRINTHDR is the "xdelta printhdr" command. */ | 
 
 
 
 
 
 | 156 | 
 typedef enum | 
 
 
 
 
 
 | 157 | 
 { | 
 
 
 
 
 
 | 158 | 
   CMD_NONE = 0, | 
 
 
 
 
 
 | 159 | 
   CMD_PRINTHDR, | 
 
 
 
 
 
 | 160 | 
   CMD_PRINTHDRS, | 
 
 
 
 
 
 | 161 | 
   CMD_PRINTDELTA, | 
 
 
 
 
 
 | 162 | 
 #if XD3_ENCODER | 
 
 
 
 
 
 | 163 | 
   CMD_ENCODE, | 
 
 
 
 
 
 | 164 | 
 #endif | 
 
 
 
 
 
 | 165 | 
   CMD_DECODE, | 
 
 
 
 
 
 | 166 | 
   CMD_TEST, | 
 
 
 
 
 
 | 167 | 
   CMD_CONFIG, | 
 
 
 
 
 
 | 168 | 
 } xd3_cmd; | 
 
 
 
 
 
 | 169 | 
  | 
 
 
 
 
 
 | 170 | 
 #if XD3_ENCODER | 
 
 
 
 
 
 | 171 | 
 #define CMD_DEFAULT CMD_ENCODE | 
 
 
 
 
 
 | 172 | 
 #define IS_ENCODE(cmd) (cmd == CMD_ENCODE) | 
 
 
 
 
 
 | 173 | 
 #else | 
 
 
 
 
 
 | 174 | 
 #define CMD_DEFAULT CMD_DECODE | 
 
 
 
 
 
 | 175 | 
 #define IS_ENCODE(cmd) (0) | 
 
 
 
 
 
 | 176 | 
 #endif | 
 
 
 
 
 
 | 177 | 
  | 
 
 
 
 
 
 | 178 | 
 typedef struct _main_file        main_file; | 
 
 
 
 
 
 | 179 | 
 typedef struct _main_extcomp     main_extcomp; | 
 
 
 
 
 
 | 180 | 
 typedef struct _main_blklru      main_blklru; | 
 
 
 
 
 
 | 181 | 
 typedef struct _main_blklru_list main_blklru_list; | 
 
 
 
 
 
 | 182 | 
  | 
 
 
 
 
 
 | 183 | 
 /* The main_file object supports abstract system calls like open, close, read, write, seek, | 
 
 
 
 
 
 | 184 | 
  * stat.  The program uses these to represent both seekable files and non-seekable files. | 
 
 
 
 
 
 | 185 | 
  * Source files must be seekable, but the target input and any output file do not require | 
 
 
 
 
 
 | 186 | 
  * seekability. | 
 
 
 
 
 
 | 187 | 
  */ | 
 
 
 
 
 
 | 188 | 
 struct _main_file | 
 
 
 
 
 
 | 189 | 
 { | 
 
 
 
 
 
 | 190 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 191 | 
   FILE               *file; | 
 
 
 
 
 
 | 192 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 193 | 
   int                 file; | 
 
 
 
 
 
 | 194 | 
 #elif XD3_WIN32 | 
 
 
 
 
 
 | 195 | 
   HANDLE              file; | 
 
 
 
 
 
 | 196 | 
 #endif | 
 
 
 
 
 
 | 197 | 
  | 
 
 
 
 
 
 | 198 | 
   int                 mode;          /* XO_READ and XO_WRITE */ | 
 
 
 
 
 
 | 199 | 
   const char         *filename;      /* File name or /dev/stdin, /dev/stdout, /dev/stderr. */ | 
 
 
 
 
 
 | 200 | 
   char               *filename_copy; /* File name or /dev/stdin, /dev/stdout, /dev/stderr. */ | 
 
 
 
 
 
 | 201 | 
   const char         *realname;      /* File name or /dev/stdin, /dev/stdout, /dev/stderr. */ | 
 
 
 
 
 
 | 202 | 
   const main_extcomp *compressor;    /* External compression struct. */ | 
 
 
 
 
 
 | 203 | 
   int                 flags;         /* RD_FIRST, RD_NONEXTERNAL, ... */ | 
 
 
 
 
 
 | 204 | 
   xoff_t              nread;         /* for input position */ | 
 
 
 
 
 
 | 205 | 
   xoff_t              nwrite;        /* for output position */ | 
 
 
 
 
 
 | 206 | 
   uint8_t            *snprintf_buf;  /* internal snprintf() use */ | 
 
 
 
 
 
 | 207 | 
 }; | 
 
 
 
 
 
 | 208 | 
  | 
 
 
 
 
 
 | 209 | 
 /* Various strings and magic values used to detect and call external compression.  See | 
 
 
 
 
 
 | 210 | 
  * below for examples. */ | 
 
 
 
 
 
 | 211 | 
 struct _main_extcomp | 
 
 
 
 
 
 | 212 | 
 { | 
 
 
 
 
 
 | 213 | 
   const char    *recomp_cmdname; | 
 
 
 
 
 
 | 214 | 
   const char    *recomp_options; | 
 
 
 
 
 
 | 215 | 
  | 
 
 
 
 
 
 | 216 | 
   const char    *decomp_cmdname; | 
 
 
 
 
 
 | 217 | 
   const char    *decomp_options; | 
 
 
 
 
 
 | 218 | 
  | 
 
 
 
 
 
 | 219 | 
   const char    *ident; | 
 
 
 
 
 
 | 220 | 
   const char    *magic; | 
 
 
 
 
 
 | 221 | 
   int            magic_size; | 
 
 
 
 
 
 | 222 | 
   int            flags; | 
 
 
 
 
 
 | 223 | 
 }; | 
 
 
 
 
 
 | 224 | 
  | 
 
 
 
 
 
 | 225 | 
 /* This file implements a small LRU of source blocks.  For encoding purposes, | 
 
 
 
 
 
 | 226 | 
  * we prevent paging in blocks we've already scanned in the source (return | 
 
 
 
 
 
 | 227 | 
  * XD3_NOTAVAIL). */ | 
 
 
 
 
 
 | 228 | 
 struct _main_blklru_list | 
 
 
 
 
 
 | 229 | 
 { | 
 
 
 
 
 
 | 230 | 
   main_blklru_list  *next; | 
 
 
 
 
 
 | 231 | 
   main_blklru_list  *prev; | 
 
 
 
 
 
 | 232 | 
 }; | 
 
 
 
 
 
 | 233 | 
  | 
 
 
 
 
 
 | 234 | 
 struct _main_blklru | 
 
 
 
 
 
 | 235 | 
 { | 
 
 
 
 
 
 | 236 | 
   uint8_t         *blk; | 
 
 
 
 
 
 | 237 | 
   xoff_t           blkno; | 
 
 
 
 
 
 | 238 | 
   main_blklru_list  link; | 
 
 
 
 
 
 | 239 | 
 }; | 
 
 
 
 
 
 | 240 | 
  | 
 
 
 
 
 
 | 241 | 
 #define LRU_SIZE 32U | 
 
 
 
 
 
 | 242 | 
 #define XD3_MINSRCWINSZ XD3_ALLOCSIZE | 
 
 
 
 
 
 | 243 | 
  | 
 
 
 
 
 
 | 244 | 
 /* ... represented as a list (no cache index). */ | 
 
 
 
 
 
 | 245 | 
 XD3_MAKELIST(main_blklru_list,main_blklru,link); | 
 
 
 
 
 
 | 246 | 
  | 
 
 
 
 
 
 | 247 | 
 // TODO: | 
 
 
 
 
 
 | 248 | 
 // struct _main_state | 
 
 
 
 
 
 | 249 | 
 // { | 
 
 
 
 
 
 | 250 | 
  | 
 
 
 
 
 
 | 251 | 
 /* Program options: various command line flags and options. */ | 
 
 
 
 
 
 | 252 | 
 static int         option_stdout             = 0; | 
 
 
 
 
 
 | 253 | 
 static int         option_force              = 0; | 
 
 
 
 
 
 | 254 | 
 static int         option_verbose            = 0; | 
 
 
 
 
 
 | 255 | 
 static int         option_quiet              = 0; | 
 
 
 
 
 
 | 256 | 
 static int         option_use_appheader      = 1; | 
 
 
 
 
 
 | 257 | 
 static uint8_t*    option_appheader          = NULL; | 
 
 
 
 
 
 | 258 | 
 static int         option_use_secondary      = 0; | 
 
 
 
 
 
 | 259 | 
 static char*       option_secondary          = NULL; | 
 
 
 
 
 
 | 260 | 
 static int         option_use_checksum       = 1; | 
 
 
 
 
 
 | 261 | 
 static int         option_use_altcodetable   = 0; | 
 
 
 
 
 
 | 262 | 
 static char*       option_smatch_config      = NULL; | 
 
 
 
 
 
 | 263 | 
 static int         option_no_compress        = 0; | 
 
 
 
 
 
 | 264 | 
 static int         option_no_output          = 0; /* do not open or write output */ | 
 
 
 
 
 
 | 265 | 
 static const char *option_source_filename    = NULL; | 
 
 
 
 
 
 | 266 | 
  | 
 
 
 
 
 
 | 267 | 
 static int         option_level              = XD3_DEFAULT_LEVEL; | 
 
 
 
 
 
 | 268 | 
 static usize_t     option_iopt_size          = XD3_DEFAULT_IOPT_SIZE; | 
 
 
 
 
 
 | 269 | 
 static usize_t     option_winsize            = XD3_DEFAULT_WINSIZE; | 
 
 
 
 
 
 | 270 | 
 static usize_t     option_srcwinsz           = XD3_DEFAULT_SRCWINSZ; | 
 
 
 
 
 
 | 271 | 
 static usize_t     option_sprevsz            = XD3_DEFAULT_SPREVSZ; | 
 
 
 
 
 
 | 272 | 
  | 
 
 
 
 
 
 | 273 | 
 /* These variables are supressed to avoid their use w/o support.  main() warns | 
 
 
 
 
 
 | 274 | 
  * appropriately. */ | 
 
 
 
 
 
 | 275 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 276 | 
 static int         option_decompress_inputs  = 1; | 
 
 
 
 
 
 | 277 | 
 static int         option_recompress_outputs = 1; | 
 
 
 
 
 
 | 278 | 
 #endif | 
 
 
 
 
 
 | 279 | 
  | 
 
 
 
 
 
 | 280 | 
 /* This is for comparing "printdelta" output without attention to | 
 
 
 
 
 
 | 281 | 
  * copy-instruction modes. */ | 
 
 
 
 
 
 | 282 | 
 #if VCDIFF_TOOLS | 
 
 
 
 
 
 | 283 | 
 static int         option_print_cpymode = 1; | 
 
 
 
 
 
 | 284 | 
 #endif | 
 
 
 
 
 
 | 285 | 
  | 
 
 
 
 
 
 | 286 | 
 /* Static variables */ | 
 
 
 
 
 
 | 287 | 
 IF_DEBUG(static int main_mallocs = 0;) | 
 
 
 
 
 
 | 288 | 
  | 
 
 
 
 
 
 | 289 | 
 static char*          program_name = NULL; | 
 
 
 
 
 
 | 290 | 
 static uint8_t*       appheader_used = NULL; | 
 
 
 
 
 
 | 291 | 
 static uint8_t*       main_bdata = NULL; | 
 
 
 
 
 
 | 292 | 
  | 
 
 
 
 
 
 | 293 | 
 /* The LRU: obviously this is shared by all callers. */ | 
 
 
 
 
 
 | 294 | 
 static int               lru_size = 0; | 
 
 
 
 
 
 | 295 | 
 static main_blklru      *lru = NULL;  /* array of lru_size elts */ | 
 
 
 
 
 
 | 296 | 
 static main_blklru_list  lru_list; | 
 
 
 
 
 
 | 297 | 
 static main_blklru_list  lru_free; | 
 
 
 
 
 
 | 298 | 
 static int               do_not_lru = 0;  /* set to avoid lru, instead discard oldest */ | 
 
 
 
 
 
 | 299 | 
  | 
 
 
 
 
 
 | 300 | 
 static int lru_hits   = 0; | 
 
 
 
 
 
 | 301 | 
 static int lru_misses = 0; | 
 
 
 
 
 
 | 302 | 
 static int lru_filled = 0; | 
 
 
 
 
 
 | 303 | 
  | 
 
 
 
 
 
 | 304 | 
 /* Hacks for VCDIFF tools */ | 
 
 
 
 
 
 | 305 | 
 static int allow_fake_source = 0; | 
 
 
 
 
 
 | 306 | 
  | 
 
 
 
 
 
 | 307 | 
 /* This array of compressor types is compiled even if EXTERNAL_COMPRESSION is false just so | 
 
 
 
 
 
 | 308 | 
  * the program knows the mapping of IDENT->NAME. */ | 
 
 
 
 
 
 | 309 | 
 static main_extcomp extcomp_types[] = | 
 
 
 
 
 
 | 310 | 
 { | 
 
 
 
 
 
 | 311 | 
   /* The entry for xdelta3 must be 0 because the program_name is set there. */ | 
 
 
 
 
 
 | 312 | 
   { "xdelta3",  "-cfq",  "xdelta3",    "-dcfq",  "X", "\xd6\xc3\xc4", 3, RD_NONEXTERNAL }, | 
 
 
 
 
 
 | 313 | 
   { "bzip2",    "-cf",   "bzip2",      "-dcf",   "B", "BZh",          3, 0 }, | 
 
 
 
 
 
 | 314 | 
   { "gzip",     "-cf",   "gzip",       "-dcf",   "G", "\037\213",     2, 0 }, | 
 
 
 
 
 
 | 315 | 
   { "compress", "-cf",   "uncompress", "-cf",    "Z", "\037\235",     2, 0 }, | 
 
 
 
 
 
 | 316 | 
  | 
 
 
 
 
 
 | 317 | 
   /* TODO: add commandline support for magic-less formats */ | 
 
 
 
 
 
 | 318 | 
   /*{ "lzma",     "-cf",   "lzma",       "-dcf",   "M", "]\000",        2, 0 },*/ | 
 
 
 
 
 
 | 319 | 
 }; | 
 
 
 
 
 
 | 320 | 
  | 
 
 
 
 
 
 | 321 | 
 // }; | 
 
 
 
 
 
 | 322 | 
  | 
 
 
 
 
 
 | 323 | 
 static void main_get_appheader (xd3_stream *stream, main_file *ifile, | 
 
 
 
 
 
 | 324 | 
                                 main_file *output, main_file *sfile); | 
 
 
 
 
 
 | 325 | 
  | 
 
 
 
 
 
 | 326 | 
 static int main_help (void); | 
 
 
 
 
 
 | 327 | 
  | 
 
 
 
 
 
 | 328 | 
 static int | 
 
 
 
 
 
 | 329 | 
 main_version (void) | 
 
 
 
 
 
 | 330 | 
 { | 
 
 
 
 
 
 | 331 | 
   /* $Format: "  DP(RINT \"VERSION=3.$Xdelta3Version$\\n\");" $ */ | 
 
 
 
 
 
 | 332 | 
   DP(RINT "VERSION=3.0q\n"); | 
 
 
 
 
 
 | 333 | 
   return EXIT_SUCCESS; | 
 
 
 
 
 
 | 334 | 
 } | 
 
 
 
 
 
 | 335 | 
  | 
 
 
 
 
 
 | 336 | 
 static int | 
 
 
 
 
 
 | 337 | 
 main_config (void) | 
 
 
 
 
 
 | 338 | 
 { | 
 
 
 
 
 
 | 339 | 
   main_version (); | 
 
 
 
 
 
 | 340 | 
  | 
 
 
 
 
 
 | 341 | 
   DP(RINT "EXTERNAL_COMPRESSION=%d\n", EXTERNAL_COMPRESSION); | 
 
 
 
 
 
 | 342 | 
   DP(RINT "GENERIC_ENCODE_TABLES=%d\n", GENERIC_ENCODE_TABLES); | 
 
 
 
 
 
 | 343 | 
   DP(RINT "GENERIC_ENCODE_TABLES_COMPUTE=%d\n", GENERIC_ENCODE_TABLES_COMPUTE); | 
 
 
 
 
 
 | 344 | 
   DP(RINT "REGRESSION_TEST=%d\n", REGRESSION_TEST); | 
 
 
 
 
 
 | 345 | 
   DP(RINT "SECONDARY_DJW=%d\n", SECONDARY_DJW); | 
 
 
 
 
 
 | 346 | 
   DP(RINT "SECONDARY_FGK=%d\n", SECONDARY_FGK); | 
 
 
 
 
 
 | 347 | 
   DP(RINT "VCDIFF_TOOLS=%d\n", VCDIFF_TOOLS); | 
 
 
 
 
 
 | 348 | 
   DP(RINT "XD3_ALLOCSIZE=%d\n", XD3_ALLOCSIZE); | 
 
 
 
 
 
 | 349 | 
   DP(RINT "XD3_DEBUG=%d\n", XD3_DEBUG); | 
 
 
 
 
 
 | 350 | 
   DP(RINT "XD3_ENCODER=%d\n", XD3_ENCODER); | 
 
 
 
 
 
 | 351 | 
   DP(RINT "XD3_POSIX=%d\n", XD3_POSIX); | 
 
 
 
 
 
 | 352 | 
   DP(RINT "XD3_STDIO=%d\n", XD3_STDIO); | 
 
 
 
 
 
 | 353 | 
   DP(RINT "XD3_WIN32=%d\n", XD3_WIN32); | 
 
 
 
 
 
 | 354 | 
   DP(RINT "XD3_USE_LARGEFILE64=%d\n", XD3_USE_LARGEFILE64); | 
 
 
 
 
 
 | 355 | 
   DP(RINT "XD3_DEFAULT_LEVEL=%d\n", XD3_DEFAULT_LEVEL); | 
 
 
 
 
 
 | 356 | 
   DP(RINT "XD3_DEFAULT_IOPT_SIZE=%d\n", XD3_DEFAULT_IOPT_SIZE); | 
 
 
 
 
 
 | 357 | 
   DP(RINT "XD3_DEFAULT_SPREVSZ=%d\n", XD3_DEFAULT_SPREVSZ); | 
 
 
 
 
 
 | 358 | 
   DP(RINT "XD3_DEFAULT_SRCWINSZ=%d\n", XD3_DEFAULT_SRCWINSZ); | 
 
 
 
 
 
 | 359 | 
   DP(RINT "XD3_DEFAULT_WINSIZE=%d\n", XD3_DEFAULT_WINSIZE); | 
 
 
 
 
 
 | 360 | 
   DP(RINT "XD3_HARDMAXWINSIZE=%d\n", XD3_HARDMAXWINSIZE); | 
 
 
 
 
 
 | 361 | 
   DP(RINT "XD3_NODECOMPRESSSIZE=%d\n", XD3_NODECOMPRESSSIZE); | 
 
 
 
 
 
 | 362 | 
  | 
 
 
 
 
 
 | 363 | 
   return EXIT_SUCCESS; | 
 
 
 
 
 
 | 364 | 
 } | 
 
 
 
 
 
 | 365 | 
  | 
 
 
 
 
 
 | 366 | 
 static void | 
 
 
 
 
 
 | 367 | 
 reset_defaults(void) | 
 
 
 
 
 
 | 368 | 
 { | 
 
 
 
 
 
 | 369 | 
   option_stdout = 0; | 
 
 
 
 
 
 | 370 | 
   option_force = 0; | 
 
 
 
 
 
 | 371 | 
   option_verbose = 0; | 
 
 
 
 
 
 | 372 | 
   option_quiet = 0; | 
 
 
 
 
 
 | 373 | 
   option_appheader = NULL; | 
 
 
 
 
 
 | 374 | 
   option_use_secondary = 0; | 
 
 
 
 
 
 | 375 | 
   option_secondary = NULL; | 
 
 
 
 
 
 | 376 | 
   option_use_altcodetable = 0; | 
 
 
 
 
 
 | 377 | 
   option_smatch_config = NULL; | 
 
 
 
 
 
 | 378 | 
   option_no_compress = 0; | 
 
 
 
 
 
 | 379 | 
   option_no_output = 0; | 
 
 
 
 
 
 | 380 | 
   option_source_filename = NULL; | 
 
 
 
 
 
 | 381 | 
   program_name = NULL; | 
 
 
 
 
 
 | 382 | 
   appheader_used = NULL; | 
 
 
 
 
 
 | 383 | 
   main_bdata = NULL; | 
 
 
 
 
 
 | 384 | 
   lru_size = 0; | 
 
 
 
 
 
 | 385 | 
   lru = NULL; | 
 
 
 
 
 
 | 386 | 
   do_not_lru = 0; | 
 
 
 
 
 
 | 387 | 
   lru_hits   = 0; | 
 
 
 
 
 
 | 388 | 
   lru_misses = 0; | 
 
 
 
 
 
 | 389 | 
   lru_filled = 0; | 
 
 
 
 
 
 | 390 | 
   allow_fake_source = 0; | 
 
 
 
 
 
 | 391 | 
   option_smatch_config = NULL; | 
 
 
 
 
 
 | 392 | 
  | 
 
 
 
 
 
 | 393 | 
   option_use_appheader = 1; | 
 
 
 
 
 
 | 394 | 
   option_use_checksum = 1; | 
 
 
 
 
 
 | 395 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 396 | 
   option_decompress_inputs  = 1; | 
 
 
 
 
 
 | 397 | 
   option_recompress_outputs = 1; | 
 
 
 
 
 
 | 398 | 
 #endif | 
 
 
 
 
 
 | 399 | 
 #if VCDIFF_TOOLS | 
 
 
 
 
 
 | 400 | 
   option_print_cpymode = 1; | 
 
 
 
 
 
 | 401 | 
 #endif | 
 
 
 
 
 
 | 402 | 
   option_level = XD3_DEFAULT_LEVEL; | 
 
 
 
 
 
 | 403 | 
   option_iopt_size = XD3_DEFAULT_IOPT_SIZE; | 
 
 
 
 
 
 | 404 | 
   option_winsize = XD3_DEFAULT_WINSIZE; | 
 
 
 
 
 
 | 405 | 
   option_srcwinsz = XD3_DEFAULT_SRCWINSZ; | 
 
 
 
 
 
 | 406 | 
   option_sprevsz = XD3_DEFAULT_SPREVSZ; | 
 
 
 
 
 
 | 407 | 
 } | 
 
 
 
 
 
 | 408 | 
  | 
 
 
 
 
 
 | 409 | 
 static void* | 
 
 
 
 
 
 | 410 | 
 main_malloc1 (usize_t size) | 
 
 
 
 
 
 | 411 | 
 { | 
 
 
 
 
 
 | 412 | 
   void* r = malloc (size); | 
 
 
 
 
 
 | 413 | 
   if (r == NULL) { XPR(NT "malloc: %s\n", xd3_mainerror (ENOMEM)); } | 
 
 
 
 
 
 | 414 | 
   else if (option_verbose > 3) { XPR(NT "malloc: %u: %p\n", size, r); } | 
 
 
 
 
 
 | 415 | 
   return r; | 
 
 
 
 
 
 | 416 | 
 } | 
 
 
 
 
 
 | 417 | 
  | 
 
 
 
 
 
 | 418 | 
 static void* | 
 
 
 
 
 
 | 419 | 
 main_malloc (usize_t size) | 
 
 
 
 
 
 | 420 | 
 { | 
 
 
 
 
 
 | 421 | 
   void *r = main_malloc1 (size); | 
 
 
 
 
 
 | 422 | 
    if (r) { IF_DEBUG (main_mallocs += 1); } | 
 
 
 
 
 
 | 423 | 
   return r; | 
 
 
 
 
 
 | 424 | 
 } | 
 
 
 
 
 
 | 425 | 
  | 
 
 
 
 
 
 | 426 | 
 static void* | 
 
 
 
 
 
 | 427 | 
 main_alloc (void   *opaque, | 
 
 
 
 
 
 | 428 | 
             usize_t  items, | 
 
 
 
 
 
 | 429 | 
             usize_t  size) | 
 
 
 
 
 
 | 430 | 
 { | 
 
 
 
 
 
 | 431 | 
   return main_malloc1 (items * size); | 
 
 
 
 
 
 | 432 | 
 } | 
 
 
 
 
 
 | 433 | 
  | 
 
 
 
 
 
 | 434 | 
 static void | 
 
 
 
 
 
 | 435 | 
 main_free1 (void *opaque, void *ptr) | 
 
 
 
 
 
 | 436 | 
 { | 
 
 
 
 
 
 | 437 | 
   if (option_verbose > 3) { XPR(NT "free: %p\n", ptr); } | 
 
 
 
 
 
 | 438 | 
   free (ptr); | 
 
 
 
 
 
 | 439 | 
 } | 
 
 
 
 
 
 | 440 | 
  | 
 
 
 
 
 
 | 441 | 
 static void | 
 
 
 
 
 
 | 442 | 
 main_free (void *ptr) | 
 
 
 
 
 
 | 443 | 
 { | 
 
 
 
 
 
 | 444 | 
   if (ptr) | 
 
 
 
 
 
 | 445 | 
     { | 
 
 
 
 
 
 | 446 | 
       IF_DEBUG (main_mallocs -= 1); | 
 
 
 
 
 
 | 447 | 
       main_free1 (NULL, ptr); | 
 
 
 
 
 
 | 448 | 
       IF_DEBUG (XD3_ASSERT(main_mallocs >= 0)); | 
 
 
 
 
 
 | 449 | 
     } | 
 
 
 
 
 
 | 450 | 
 } | 
 
 
 
 
 
 | 451 | 
  | 
 
 
 
 
 
 | 452 | 
 /* This ensures that (ret = errno) always indicates failure, in case errno was | 
 
 
 
 
 
 | 453 | 
  * accidentally not set.  If this prints there's a bug somewhere. */ | 
 
 
 
 
 
 | 454 | 
 static int | 
 
 
 
 
 
 | 455 | 
 get_errno (void) | 
 
 
 
 
 
 | 456 | 
 { | 
 
 
 
 
 
 | 457 | 
 #ifndef _WIN32 | 
 
 
 
 
 
 | 458 | 
   if (errno == 0) | 
 
 
 
 
 
 | 459 | 
     { | 
 
 
 
 
 
 | 460 | 
       XPR(NT "you found a bug: expected errno != 0\n"); | 
 
 
 
 
 
 | 461 | 
       errno = XD3_INTERNAL; | 
 
 
 
 
 
 | 462 | 
     } | 
 
 
 
 
 
 | 463 | 
   return errno; | 
 
 
 
 
 
 | 464 | 
 #else | 
 
 
 
 
 
 | 465 | 
   DWORD errNum = GetLastError(); | 
 
 
 
 
 
 | 466 | 
   if (errNum == NO_ERROR) { | 
 
 
 
 
 
 | 467 | 
           errNum = XD3_INTERNAL; | 
 
 
 
 
 
 | 468 | 
   } | 
 
 
 
 
 
 | 469 | 
   return errNum; | 
 
 
 
 
 
 | 470 | 
 #endif | 
 
 
 
 
 
 | 471 | 
 } | 
 
 
 
 
 
 | 472 | 
  | 
 
 
 
 
 
 | 473 | 
 const char* | 
 
 
 
 
 
 | 474 | 
 xd3_mainerror(int err_num) { | 
 
 
 
 
 
 | 475 | 
 #ifndef _WIN32 | 
 
 
 
 
 
 | 476 | 
         const char* x = xd3_strerror (err_num); | 
 
 
 
 
 
 | 477 | 
         if (x != NULL) { | 
 
 
 
 
 
 | 478 | 
                 return x; | 
 
 
 
 
 
 | 479 | 
         } | 
 
 
 
 
 
 | 480 | 
         return strerror(err_num); | 
 
 
 
 
 
 | 481 | 
 #else | 
 
 
 
 
 
 | 482 | 
         static char err_buf[256]; | 
 
 
 
 
 
 | 483 | 
         const char* x = xd3_strerror (err_num); | 
 
 
 
 
 
 | 484 | 
         if (x != NULL) { | 
 
 
 
 
 
 | 485 | 
                 return x; | 
 
 
 
 
 
 | 486 | 
         } | 
 
 
 
 
 
 | 487 | 
         memset (err_buf, 0, 256); | 
 
 
 
 
 
 | 488 | 
         FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | 
 
 
 
 
 
 | 489 | 
                 NULL, err_num, | 
 
 
 
 
 
 | 490 | 
                 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), | 
 
 
 
 
 
 | 491 | 
                 err_buf, 256, NULL); | 
 
 
 
 
 
 | 492 | 
         return err_buf; | 
 
 
 
 
 
 | 493 | 
 #endif | 
 
 
 
 
 
 | 494 | 
 } | 
 
 
 
 
 
 | 495 | 
  | 
 
 
 
 
 
 | 496 | 
 static long | 
 
 
 
 
 
 | 497 | 
 get_millisecs_now (void) | 
 
 
 
 
 
 | 498 | 
 { | 
 
 
 
 
 
 | 499 | 
 #ifndef _WIN32 | 
 
 
 
 
 
 | 500 | 
   struct timeval tv; | 
 
 
 
 
 
 | 501 | 
  | 
 
 
 
 
 
 | 502 | 
   gettimeofday (& tv, NULL); | 
 
 
 
 
 
 | 503 | 
  | 
 
 
 
 
 
 | 504 | 
   return (tv.tv_sec) * 1000L + (tv.tv_usec) / 1000; | 
 
 
 
 
 
 | 505 | 
 #else | 
 
 
 
 
 
 | 506 | 
   // Found this in an example on www.codeproject.com | 
 
 
 
 
 
 | 507 | 
   // It doesn't matter that the offset is Jan 1, 1601 | 
 
 
 
 
 
 | 508 | 
   // Result is the numbre of 100 nanosecond units | 
 
 
 
 
 
 | 509 | 
   // 100ns * 10,000 = 1ms | 
 
 
 
 
 
 | 510 | 
   SYSTEMTIME st; | 
 
 
 
 
 
 | 511 | 
   FILETIME ft; | 
 
 
 
 
 
 | 512 | 
   __int64 *pi = (__int64*)&ft; | 
 
 
 
 
 
 | 513 | 
   GetLocalTime(&st); | 
 
 
 
 
 
 | 514 | 
   SystemTimeToFileTime(&st, &ft); | 
 
 
 
 
 
 | 515 | 
   return (long)((*pi) / 10000); | 
 
 
 
 
 
 | 516 | 
 #endif | 
 
 
 
 
 
 | 517 | 
 } | 
 
 
 
 
 
 | 518 | 
  | 
 
 
 
 
 
 | 519 | 
 /* Always >= 1 millisec, right? */ | 
 
 
 
 
 
 | 520 | 
 static long | 
 
 
 
 
 
 | 521 | 
 get_millisecs_since (void) | 
 
 
 
 
 
 | 522 | 
 { | 
 
 
 
 
 
 | 523 | 
   static long last = 0; | 
 
 
 
 
 
 | 524 | 
   long now = get_millisecs_now(); | 
 
 
 
 
 
 | 525 | 
   long diff = now - last; | 
 
 
 
 
 
 | 526 | 
   last = now; | 
 
 
 
 
 
 | 527 | 
   return diff; | 
 
 
 
 
 
 | 528 | 
 } | 
 
 
 
 
 
 | 529 | 
  | 
 
 
 
 
 
 | 530 | 
 static char* | 
 
 
 
 
 
 | 531 | 
 main_format_bcnt (xoff_t r, char *buf) | 
 
 
 
 
 
 | 532 | 
 { | 
 
 
 
 
 
 | 533 | 
   static const char* fmts[] = { "B", "KB", "MB", "GB" }; | 
 
 
 
 
 
 | 534 | 
   int i; | 
 
 
 
 
 
 | 535 | 
  | 
 
 
 
 
 
 | 536 | 
   for (i = 0; i < SIZEOF_ARRAY(fmts); i += 1) | 
 
 
 
 
 
 | 537 | 
     { | 
 
 
 
 
 
 | 538 | 
       if (r <= (10 * 1024) || i == (-1 + (int)SIZEOF_ARRAY(fmts))) | 
 
 
 
 
 
 | 539 | 
             { | 
 
 
 
 
 
 | 540 | 
               sprintf (buf, "%"Q"u %s", r, fmts[i]); | 
 
 
 
 
 
 | 541 | 
               break; | 
 
 
 
 
 
 | 542 | 
             } | 
 
 
 
 
 
 | 543 | 
       r /= 1024; | 
 
 
 
 
 
 | 544 | 
     } | 
 
 
 
 
 
 | 545 | 
   return buf; | 
 
 
 
 
 
 | 546 | 
 } | 
 
 
 
 
 
 | 547 | 
  | 
 
 
 
 
 
 | 548 | 
 static char* | 
 
 
 
 
 
 | 549 | 
 main_format_rate (xoff_t bytes, long millis, char *buf) | 
 
 
 
 
 
 | 550 | 
 { | 
 
 
 
 
 
 | 551 | 
   xoff_t r = (xoff_t)(1.0 * bytes / (1.0 * millis / 1000.0)); | 
 
 
 
 
 
 | 552 | 
   static char lbuf[32]; | 
 
 
 
 
 
 | 553 | 
  | 
 
 
 
 
 
 | 554 | 
   main_format_bcnt (r, lbuf); | 
 
 
 
 
 
 | 555 | 
   sprintf (buf, "%s/sec", lbuf); | 
 
 
 
 
 
 | 556 | 
   return buf; | 
 
 
 
 
 
 | 557 | 
 } | 
 
 
 
 
 
 | 558 | 
  | 
 
 
 
 
 
 | 559 | 
 static char* | 
 
 
 
 
 
 | 560 | 
 main_format_millis (long millis, char *buf) | 
 
 
 
 
 
 | 561 | 
 { | 
 
 
 
 
 
 | 562 | 
   if (millis < 1000)       { sprintf (buf, "%lu ms", millis); } | 
 
 
 
 
 
 | 563 | 
   else if (millis < 10000) { sprintf (buf, "%.1f sec", millis / 1000.0); } | 
 
 
 
 
 
 | 564 | 
   else                     { sprintf (buf, "%lu sec", millis / 1000L); } | 
 
 
 
 
 
 | 565 | 
   return buf; | 
 
 
 
 
 
 | 566 | 
 } | 
 
 
 
 
 
 | 567 | 
  | 
 
 
 
 
 
 | 568 | 
 /* A safe version of strtol for xoff_t. */ | 
 
 
 
 
 
 | 569 | 
 static int | 
 
 
 
 
 
 | 570 | 
 main_strtoxoff (const char* s, xoff_t *xo, char which) | 
 
 
 
 
 
 | 571 | 
 { | 
 
 
 
 
 
 | 572 | 
   char *e; | 
 
 
 
 
 
 | 573 | 
   xoff_t x; | 
 
 
 
 
 
 | 574 | 
  | 
 
 
 
 
 
 | 575 | 
   XD3_ASSERT(s && *s != 0); | 
 
 
 
 
 
 | 576 | 
  | 
 
 
 
 
 
 | 577 | 
   { | 
 
 
 
 
 
 | 578 | 
     /* Should check LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX? */ | 
 
 
 
 
 
 | 579 | 
 #if SIZEOF_XOFF_T == 4 | 
 
 
 
 
 
 | 580 | 
     long xx = strtol (s, &e, 0); | 
 
 
 
 
 
 | 581 | 
 #else | 
 
 
 
 
 
 | 582 | 
     long long xx = strtoll (s, &e, 0); | 
 
 
 
 
 
 | 583 | 
 #endif | 
 
 
 
 
 
 | 584 | 
  | 
 
 
 
 
 
 | 585 | 
     if (xx < 0) | 
 
 
 
 
 
 | 586 | 
       { | 
 
 
 
 
 
 | 587 | 
         XPR(NT "-%c: negative integer: %s\n", which, s); | 
 
 
 
 
 
 | 588 | 
         return EXIT_FAILURE; | 
 
 
 
 
 
 | 589 | 
       } | 
 
 
 
 
 
 | 590 | 
  | 
 
 
 
 
 
 | 591 | 
     x = xx; | 
 
 
 
 
 
 | 592 | 
   } | 
 
 
 
 
 
 | 593 | 
  | 
 
 
 
 
 
 | 594 | 
   if (*e != 0) | 
 
 
 
 
 
 | 595 | 
     { | 
 
 
 
 
 
 | 596 | 
       XPR(NT "-%c: invalid integer: %s\n", which, s); | 
 
 
 
 
 
 | 597 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 598 | 
     } | 
 
 
 
 
 
 | 599 | 
  | 
 
 
 
 
 
 | 600 | 
   (*xo) = x; | 
 
 
 
 
 
 | 601 | 
   return 0; | 
 
 
 
 
 
 | 602 | 
 } | 
 
 
 
 
 
 | 603 | 
  | 
 
 
 
 
 
 | 604 | 
 static int | 
 
 
 
 
 
 | 605 | 
 main_atou (const char* arg, usize_t *xo, usize_t low, usize_t high, char which) | 
 
 
 
 
 
 | 606 | 
 { | 
 
 
 
 
 
 | 607 | 
   xoff_t x; | 
 
 
 
 
 
 | 608 | 
   int ret; | 
 
 
 
 
 
 | 609 | 
  | 
 
 
 
 
 
 | 610 | 
   if ((ret = main_strtoxoff (arg, & x, which))) { return ret; } | 
 
 
 
 
 
 | 611 | 
  | 
 
 
 
 
 
 | 612 | 
   if (x < low) | 
 
 
 
 
 
 | 613 | 
     { | 
 
 
 
 
 
 | 614 | 
       XPR(NT "-%c: minimum value: %u\n", which, low); | 
 
 
 
 
 
 | 615 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 616 | 
     } | 
 
 
 
 
 
 | 617 | 
   if (high == 0) | 
 
 
 
 
 
 | 618 | 
     { | 
 
 
 
 
 
 | 619 | 
       high = USIZE_T_MAX; | 
 
 
 
 
 
 | 620 | 
     } | 
 
 
 
 
 
 | 621 | 
   if (x > high) | 
 
 
 
 
 
 | 622 | 
     { | 
 
 
 
 
 
 | 623 | 
       XPR(NT "-%c: maximum value: %u\n", which, high); | 
 
 
 
 
 
 | 624 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 625 | 
     } | 
 
 
 
 
 
 | 626 | 
   (*xo) = (usize_t)x; | 
 
 
 
 
 
 | 627 | 
   return 0; | 
 
 
 
 
 
 | 628 | 
 } | 
 
 
 
 
 
 | 629 | 
  | 
 
 
 
 
 
 | 630 | 
 /****************************************************************************************** | 
 
 
 
 
 
 | 631 | 
  FILE BASICS | 
 
 
 
 
 
 | 632 | 
  ******************************************************************************************/ | 
 
 
 
 
 
 | 633 | 
  | 
 
 
 
 
 
 | 634 | 
 /* With all the variation in file system-call semantics, arguments, return values and | 
 
 
 
 
 
 | 635 | 
  * error-handling for the POSIX and STDIO file APIs, the insides of these functions make | 
 
 
 
 
 
 | 636 | 
  * me sick, which is why these wrappers exist. */ | 
 
 
 
 
 
 | 637 | 
  | 
 
 
 
 
 
 | 638 | 
 #define XOPEN_OPNAME (xfile->mode == XO_READ ? "read" : "write") | 
 
 
 
 
 
 | 639 | 
 #define XOPEN_STDIO  (xfile->mode == XO_READ ? "rb" : "wb") | 
 
 
 
 
 
 | 640 | 
 #define XOPEN_POSIX  (xfile->mode == XO_READ ? O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC) | 
 
 
 
 
 
 | 641 | 
 #define XOPEN_MODE   (xfile->mode == XO_READ ? 0 : 0666) | 
 
 
 
 
 
 | 642 | 
  | 
 
 
 
 
 
 | 643 | 
 #define XF_ERROR(op, name, ret) \ | 
 
 
 
 
 
 | 644 | 
   XPR(NT "file %s failed: %s: %s: %s\n", (op), XOPEN_OPNAME, (name), xd3_mainerror (ret)) | 
 
 
 
 
 
 | 645 | 
  | 
 
 
 
 
 
 | 646 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 647 | 
 #define XFNO(f) fileno(f->file) | 
 
 
 
 
 
 | 648 | 
 #define XSTDOUT_XF(f) { (f)->file = stdout; (f)->filename = "/dev/stdout"; } | 
 
 
 
 
 
 | 649 | 
 #define XSTDIN_XF(f)  { (f)->file = stdin;  (f)->filename = "/dev/stdin"; } | 
 
 
 
 
 
 | 650 | 
  | 
 
 
 
 
 
 | 651 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 652 | 
 #define XFNO(f) f->file | 
 
 
 
 
 
 | 653 | 
 #define XSTDOUT_XF(f) { (f)->file = STDOUT_FILENO; (f)->filename = "/dev/stdout"; } | 
 
 
 
 
 
 | 654 | 
 #define XSTDIN_XF(f)  { (f)->file = STDIN_FILENO;  (f)->filename = "/dev/stdin"; } | 
 
 
 
 
 
 | 655 | 
  | 
 
 
 
 
 
 | 656 | 
 #elif XD3_WIN32 | 
 
 
 
 
 
 | 657 | 
 #define XFNO(f) -1 | 
 
 
 
 
 
 | 658 | 
 #define XSTDOUT_XF(f) { (f)->file = winStartupInfo.hStdOutput; (f)->filename = "(stdout)"; } | 
 
 
 
 
 
 | 659 | 
 #define XSTDIN_XF(f)  { (f)->file = winStartupInfo.hStdInput;  (f)->filename = "(stdin)"; } | 
 
 
 
 
 
 | 660 | 
 #endif | 
 
 
 
 
 
 | 661 | 
  | 
 
 
 
 
 
 | 662 | 
 static void | 
 
 
 
 
 
 | 663 | 
 main_file_init (main_file *xfile) | 
 
 
 
 
 
 | 664 | 
 { | 
 
 
 
 
 
 | 665 | 
   memset (xfile, 0, sizeof (*xfile)); | 
 
 
 
 
 
 | 666 | 
  | 
 
 
 
 
 
 | 667 | 
 #if XD3_POSIX | 
 
 
 
 
 
 | 668 | 
   xfile->file = -1; | 
 
 
 
 
 
 | 669 | 
 #endif | 
 
 
 
 
 
 | 670 | 
 #if XD3_WIN32 | 
 
 
 
 
 
 | 671 | 
   xfile->file = INVALID_HANDLE_VALUE; | 
 
 
 
 
 
 | 672 | 
 #endif | 
 
 
 
 
 
 | 673 | 
 } | 
 
 
 
 
 
 | 674 | 
  | 
 
 
 
 
 
 | 675 | 
 static int | 
 
 
 
 
 
 | 676 | 
 main_file_isopen (main_file *xfile) | 
 
 
 
 
 
 | 677 | 
 { | 
 
 
 
 
 
 | 678 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 679 | 
   return xfile->file != NULL; | 
 
 
 
 
 
 | 680 | 
  | 
 
 
 
 
 
 | 681 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 682 | 
   return xfile->file != -1; | 
 
 
 
 
 
 | 683 | 
  | 
 
 
 
 
 
 | 684 | 
 #elif XD3_WIN32 | 
 
 
 
 
 
 | 685 | 
   return xfile->file != INVALID_HANDLE_VALUE; | 
 
 
 
 
 
 | 686 | 
 #endif | 
 
 
 
 
 
 | 687 | 
 } | 
 
 
 
 
 
 | 688 | 
  | 
 
 
 
 
 
 | 689 | 
 static int | 
 
 
 
 
 
 | 690 | 
 main_file_close (main_file *xfile) | 
 
 
 
 
 
 | 691 | 
 { | 
 
 
 
 
 
 | 692 | 
   int ret = 0; | 
 
 
 
 
 
 | 693 | 
  | 
 
 
 
 
 
 | 694 | 
   if (! main_file_isopen (xfile)) | 
 
 
 
 
 
 | 695 | 
     { | 
 
 
 
 
 
 | 696 | 
       return 0; | 
 
 
 
 
 
 | 697 | 
     } | 
 
 
 
 
 
 | 698 | 
  | 
 
 
 
 
 
 | 699 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 700 | 
   ret = fclose (xfile->file); | 
 
 
 
 
 
 | 701 | 
   xfile->file = NULL; | 
 
 
 
 
 
 | 702 | 
  | 
 
 
 
 
 
 | 703 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 704 | 
   ret = close (xfile->file); | 
 
 
 
 
 
 | 705 | 
   xfile->file = -1; | 
 
 
 
 
 
 | 706 | 
  | 
 
 
 
 
 
 | 707 | 
 #elif XD3_WIN32 | 
 
 
 
 
 
 | 708 | 
   if (!CloseHandle(xfile->file)) { | 
 
 
 
 
 
 | 709 | 
     ret = get_errno (); | 
 
 
 
 
 
 | 710 | 
   } | 
 
 
 
 
 
 | 711 | 
   xfile->file = INVALID_HANDLE_VALUE; | 
 
 
 
 
 
 | 712 | 
 #endif | 
 
 
 
 
 
 | 713 | 
  | 
 
 
 
 
 
 | 714 | 
   if (ret != 0) { XF_ERROR ("close", xfile->filename, ret = get_errno ()); } | 
 
 
 
 
 
 | 715 | 
   return ret; | 
 
 
 
 
 
 | 716 | 
 } | 
 
 
 
 
 
 | 717 | 
  | 
 
 
 
 
 
 | 718 | 
 static void | 
 
 
 
 
 
 | 719 | 
 main_file_cleanup (main_file *xfile) | 
 
 
 
 
 
 | 720 | 
 { | 
 
 
 
 
 
 | 721 | 
   if (main_file_isopen (xfile)) | 
 
 
 
 
 
 | 722 | 
     { | 
 
 
 
 
 
 | 723 | 
       main_file_close (xfile); | 
 
 
 
 
 
 | 724 | 
     } | 
 
 
 
 
 
 | 725 | 
  | 
 
 
 
 
 
 | 726 | 
   if (xfile->snprintf_buf != NULL) | 
 
 
 
 
 
 | 727 | 
     { | 
 
 
 
 
 
 | 728 | 
       main_free(xfile->snprintf_buf); | 
 
 
 
 
 
 | 729 | 
       xfile->snprintf_buf = NULL; | 
 
 
 
 
 
 | 730 | 
     } | 
 
 
 
 
 
 | 731 | 
  | 
 
 
 
 
 
 | 732 | 
   if (xfile->filename_copy != NULL) | 
 
 
 
 
 
 | 733 | 
     { | 
 
 
 
 
 
 | 734 | 
       main_free(xfile->filename_copy); | 
 
 
 
 
 
 | 735 | 
       xfile->filename_copy = NULL; | 
 
 
 
 
 
 | 736 | 
     } | 
 
 
 
 
 
 | 737 | 
 } | 
 
 
 
 
 
 | 738 | 
  | 
 
 
 
 
 
 | 739 | 
 static int | 
 
 
 
 
 
 | 740 | 
 main_file_open (main_file *xfile, const char* name, int mode) | 
 
 
 
 
 
 | 741 | 
 { | 
 
 
 
 
 
 | 742 | 
   int ret = 0; | 
 
 
 
 
 
 | 743 | 
  | 
 
 
 
 
 
 | 744 | 
   xfile->mode = mode; | 
 
 
 
 
 
 | 745 | 
  | 
 
 
 
 
 
 | 746 | 
   XD3_ASSERT (name != NULL); | 
 
 
 
 
 
 | 747 | 
   XD3_ASSERT (! main_file_isopen (xfile)); | 
 
 
 
 
 
 | 748 | 
   if (name[0] == 0) | 
 
 
 
 
 
 | 749 | 
     { | 
 
 
 
 
 
 | 750 | 
       XPR(NT "invalid file name: empty string\n"); | 
 
 
 
 
 
 | 751 | 
       return XD3_INVALID; | 
 
 
 
 
 
 | 752 | 
     } | 
 
 
 
 
 
 | 753 | 
  | 
 
 
 
 
 
 | 754 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 755 | 
   xfile->file = fopen (name, XOPEN_STDIO); | 
 
 
 
 
 
 | 756 | 
  | 
 
 
 
 
 
 | 757 | 
   ret = (xfile->file == NULL) ? get_errno () : 0; | 
 
 
 
 
 
 | 758 | 
  | 
 
 
 
 
 
 | 759 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 760 | 
   if ((ret = open (name, XOPEN_POSIX, XOPEN_MODE)) < 0) | 
 
 
 
 
 
 | 761 | 
     { | 
 
 
 
 
 
 | 762 | 
       ret = get_errno (); | 
 
 
 
 
 
 | 763 | 
     } | 
 
 
 
 
 
 | 764 | 
   else | 
 
 
 
 
 
 | 765 | 
     { | 
 
 
 
 
 
 | 766 | 
       xfile->file = ret; | 
 
 
 
 
 
 | 767 | 
       ret = 0; | 
 
 
 
 
 
 | 768 | 
     } | 
 
 
 
 
 
 | 769 | 
  | 
 
 
 
 
 
 | 770 | 
 #elif XD3_WIN32 | 
 
 
 
 
 
 | 771 | 
   xfile->file = CreateFile(name, | 
 
 
 
 
 
 | 772 | 
           (mode == XO_READ) ? GENERIC_READ : GENERIC_WRITE, | 
 
 
 
 
 
 | 773 | 
           FILE_SHARE_READ, | 
 
 
 
 
 
 | 774 | 
           NULL, | 
 
 
 
 
 
 | 775 | 
           (mode == XO_READ) ? OPEN_EXISTING : (option_force ? CREATE_ALWAYS : CREATE_NEW), | 
 
 
 
 
 
 | 776 | 
           FILE_ATTRIBUTE_NORMAL, | 
 
 
 
 
 
 | 777 | 
           NULL); | 
 
 
 
 
 
 | 778 | 
   if (xfile->file == INVALID_HANDLE_VALUE) { | 
 
 
 
 
 
 | 779 | 
           ret = get_errno (); | 
 
 
 
 
 
 | 780 | 
   } | 
 
 
 
 
 
 | 781 | 
 #endif | 
 
 
 
 
 
 | 782 | 
   if (ret) { XF_ERROR ("open", name, ret); } | 
 
 
 
 
 
 | 783 | 
   else     { xfile->realname = name; xfile->nread = 0; } | 
 
 
 
 
 
 | 784 | 
   return ret; | 
 
 
 
 
 
 | 785 | 
 } | 
 
 
 
 
 
 | 786 | 
  | 
 
 
 
 
 
 | 787 | 
 static int | 
 
 
 
 
 
 | 788 | 
 main_file_stat (main_file *xfile, xoff_t *size, int err_ifnoseek) | 
 
 
 
 
 
 | 789 | 
 { | 
 
 
 
 
 
 | 790 | 
   int ret = 0; | 
 
 
 
 
 
 | 791 | 
 #if XD3_WIN32 | 
 
 
 
 
 
 | 792 | 
   LARGE_INTEGER li; | 
 
 
 
 
 
 | 793 | 
   if (GetFileSizeEx(xfile->file, &li) == 0) { | 
 
 
 
 
 
 | 794 | 
           ret = get_errno (); | 
 
 
 
 
 
 | 795 | 
   } else { | 
 
 
 
 
 
 | 796 | 
       *size = li.QuadPart; | 
 
 
 
 
 
 | 797 | 
   } | 
 
 
 
 
 
 | 798 | 
 #else | 
 
 
 
 
 
 | 799 | 
   struct stat sbuf; | 
 
 
 
 
 
 | 800 | 
   if (fstat (XFNO (xfile), & sbuf) < 0) | 
 
 
 
 
 
 | 801 | 
     { | 
 
 
 
 
 
 | 802 | 
       ret = get_errno (); | 
 
 
 
 
 
 | 803 | 
       if (err_ifnoseek) { XF_ERROR ("stat", xfile->filename, ret); } | 
 
 
 
 
 
 | 804 | 
       return ret; | 
 
 
 
 
 
 | 805 | 
     } | 
 
 
 
 
 
 | 806 | 
  | 
 
 
 
 
 
 | 807 | 
   if (! S_ISREG (sbuf.st_mode)) | 
 
 
 
 
 
 | 808 | 
     { | 
 
 
 
 
 
 | 809 | 
       if (err_ifnoseek) { XPR(NT "source file must be seekable: %s\n", xfile->filename); } | 
 
 
 
 
 
 | 810 | 
       return ESPIPE; | 
 
 
 
 
 
 | 811 | 
     } | 
 
 
 
 
 
 | 812 | 
   (*size) = sbuf.st_size; | 
 
 
 
 
 
 | 813 | 
 #endif | 
 
 
 
 
 
 | 814 | 
   return ret; | 
 
 
 
 
 
 | 815 | 
 } | 
 
 
 
 
 
 | 816 | 
  | 
 
 
 
 
 
 | 817 | 
 static int | 
 
 
 
 
 
 | 818 | 
 main_file_exists (main_file *xfile) | 
 
 
 
 
 
 | 819 | 
 { | 
 
 
 
 
 
 | 820 | 
   struct stat sbuf; | 
 
 
 
 
 
 | 821 | 
   return stat (xfile->filename, & sbuf) == 0 && S_ISREG (sbuf.st_mode); | 
 
 
 
 
 
 | 822 | 
 } | 
 
 
 
 
 
 | 823 | 
  | 
 
 
 
 
 
 | 824 | 
 #if (XD3_POSIX || EXTERNAL_COMPRESSION) | 
 
 
 
 
 
 | 825 | 
 /* POSIX-generic code takes a function pointer to read() or write().  This calls the | 
 
 
 
 
 
 | 826 | 
  * function repeatedly until the buffer is full or EOF.  The NREAD parameter is not | 
 
 
 
 
 
 | 827 | 
  * set for write, NULL is passed.  Return is signed, < 0 indicate errors, otherwise | 
 
 
 
 
 
 | 828 | 
  * byte count. */ | 
 
 
 
 
 
 | 829 | 
 typedef int (xd3_posix_func) (int fd, uint8_t *buf, usize_t size); | 
 
 
 
 
 
 | 830 | 
  | 
 
 
 
 
 
 | 831 | 
 static int | 
 
 
 
 
 
 | 832 | 
 xd3_posix_io (int fd, uint8_t *buf, usize_t size, xd3_posix_func *func, usize_t *nread) | 
 
 
 
 
 
 | 833 | 
 { | 
 
 
 
 
 
 | 834 | 
   int ret; | 
 
 
 
 
 
 | 835 | 
   usize_t nproc = 0; | 
 
 
 
 
 
 | 836 | 
  | 
 
 
 
 
 
 | 837 | 
   while (nproc < size) | 
 
 
 
 
 
 | 838 | 
     { | 
 
 
 
 
 
 | 839 | 
       int result = (*func) (fd, buf + nproc, size - nproc); | 
 
 
 
 
 
 | 840 | 
  | 
 
 
 
 
 
 | 841 | 
       if (result < 0) | 
 
 
 
 
 
 | 842 | 
         { | 
 
 
 
 
 
 | 843 | 
           ret = get_errno (); | 
 
 
 
 
 
 | 844 | 
           if (ret != EAGAIN && ret != EINTR) | 
 
 
 
 
 
 | 845 | 
             { | 
 
 
 
 
 
 | 846 | 
               return ret; | 
 
 
 
 
 
 | 847 | 
             } | 
 
 
 
 
 
 | 848 | 
           result = 0; | 
 
 
 
 
 
 | 849 | 
         } | 
 
 
 
 
 
 | 850 | 
  | 
 
 
 
 
 
 | 851 | 
       if (nread != NULL && result == 0) { break; } | 
 
 
 
 
 
 | 852 | 
  | 
 
 
 
 
 
 | 853 | 
       nproc += result; | 
 
 
 
 
 
 | 854 | 
     } | 
 
 
 
 
 
 | 855 | 
   if (nread != NULL) { (*nread) = nproc; } | 
 
 
 
 
 
 | 856 | 
   return 0; | 
 
 
 
 
 
 | 857 | 
 } | 
 
 
 
 
 
 | 858 | 
 #endif | 
 
 
 
 
 
 | 859 | 
  | 
 
 
 
 
 
 | 860 | 
 /* POSIX is unbuffered, while STDIO is buffered.  main_file_read() should always be called | 
 
 
 
 
 
 | 861 | 
  * on blocks. */ | 
 
 
 
 
 
 | 862 | 
 static int | 
 
 
 
 
 
 | 863 | 
 main_file_read (main_file   *ifile, | 
 
 
 
 
 
 | 864 | 
                uint8_t    *buf, | 
 
 
 
 
 
 | 865 | 
                usize_t      size, | 
 
 
 
 
 
 | 866 | 
                usize_t     *nread, | 
 
 
 
 
 
 | 867 | 
                const char *msg) | 
 
 
 
 
 
 | 868 | 
 { | 
 
 
 
 
 
 | 869 | 
   int ret = 0; | 
 
 
 
 
 
 | 870 | 
  | 
 
 
 
 
 
 | 871 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 872 | 
   usize_t result; | 
 
 
 
 
 
 | 873 | 
  | 
 
 
 
 
 
 | 874 | 
   result = fread (buf, 1, size, ifile->file); | 
 
 
 
 
 
 | 875 | 
  | 
 
 
 
 
 
 | 876 | 
   if (result < size && ferror (ifile->file)) | 
 
 
 
 
 
 | 877 | 
     { | 
 
 
 
 
 
 | 878 | 
       ret = get_errno (); | 
 
 
 
 
 
 | 879 | 
     } | 
 
 
 
 
 
 | 880 | 
   else | 
 
 
 
 
 
 | 881 | 
     { | 
 
 
 
 
 
 | 882 | 
       *nread = result; | 
 
 
 
 
 
 | 883 | 
     } | 
 
 
 
 
 
 | 884 | 
  | 
 
 
 
 
 
 | 885 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 886 | 
   ret = xd3_posix_io (ifile->file, buf, size, (xd3_posix_func*) &read, nread); | 
 
 
 
 
 
 | 887 | 
  | 
 
 
 
 
 
 | 888 | 
 #elif XD3_WIN32 | 
 
 
 
 
 
 | 889 | 
   DWORD nread2; | 
 
 
 
 
 
 | 890 | 
   if (ReadFile (ifile->file, buf, size, &nread2, NULL) == 0) { | 
 
 
 
 
 
 | 891 | 
           ret = get_errno(); | 
 
 
 
 
 
 | 892 | 
   } else { | 
 
 
 
 
 
 | 893 | 
       *nread = (usize_t)nread2; | 
 
 
 
 
 
 | 894 | 
   } | 
 
 
 
 
 
 | 895 | 
 #endif | 
 
 
 
 
 
 | 896 | 
  | 
 
 
 
 
 
 | 897 | 
   if (ret) | 
 
 
 
 
 
 | 898 | 
     { | 
 
 
 
 
 
 | 899 | 
       XPR(NT "%s: %s: %s\n", msg, ifile->filename, xd3_mainerror (ret)); | 
 
 
 
 
 
 | 900 | 
     } | 
 
 
 
 
 
 | 901 | 
   else | 
 
 
 
 
 
 | 902 | 
     { | 
 
 
 
 
 
 | 903 | 
       if (option_verbose > 3) { XPR(NT "main read: %s: %u\n", ifile->filename, (*nread)); } | 
 
 
 
 
 
 | 904 | 
       ifile->nread += (*nread); | 
 
 
 
 
 
 | 905 | 
     } | 
 
 
 
 
 
 | 906 | 
  | 
 
 
 
 
 
 | 907 | 
   return ret; | 
 
 
 
 
 
 | 908 | 
 } | 
 
 
 
 
 
 | 909 | 
  | 
 
 
 
 
 
 | 910 | 
 static int | 
 
 
 
 
 
 | 911 | 
 main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg) | 
 
 
 
 
 
 | 912 | 
 { | 
 
 
 
 
 
 | 913 | 
   int ret = 0; | 
 
 
 
 
 
 | 914 | 
  | 
 
 
 
 
 
 | 915 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 916 | 
   usize_t result; | 
 
 
 
 
 
 | 917 | 
  | 
 
 
 
 
 
 | 918 | 
   result = fwrite (buf, 1, size, ofile->file); | 
 
 
 
 
 
 | 919 | 
  | 
 
 
 
 
 
 | 920 | 
   if (result != size) { ret = get_errno (); } | 
 
 
 
 
 
 | 921 | 
  | 
 
 
 
 
 
 | 922 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 923 | 
   ret = xd3_posix_io (ofile->file, buf, size, (xd3_posix_func*) &write, NULL); | 
 
 
 
 
 
 | 924 | 
  | 
 
 
 
 
 
 | 925 | 
 #elif XD3_WIN32 | 
 
 
 
 
 
 | 926 | 
   DWORD nwrite; | 
 
 
 
 
 
 | 927 | 
   if (WriteFile(ofile->file, buf, size, &nwrite, NULL) == 0) { | 
 
 
 
 
 
 | 928 | 
           ret = get_errno (); | 
 
 
 
 
 
 | 929 | 
   } else { | 
 
 
 
 
 
 | 930 | 
           if (size != nwrite) { | 
 
 
 
 
 
 | 931 | 
                   XPR(NT "Incorrect write count"); | 
 
 
 
 
 
 | 932 | 
                   ret = XD3_INTERNAL; | 
 
 
 
 
 
 | 933 | 
           } | 
 
 
 
 
 
 | 934 | 
   } | 
 
 
 
 
 
 | 935 | 
 #endif | 
 
 
 
 
 
 | 936 | 
  | 
 
 
 
 
 
 | 937 | 
   if (ret) | 
 
 
 
 
 
 | 938 | 
     { | 
 
 
 
 
 
 | 939 | 
       XPR(NT "%s: %s: %s\n", msg, ofile->filename, xd3_mainerror (ret)); | 
 
 
 
 
 
 | 940 | 
     } | 
 
 
 
 
 
 | 941 | 
   else | 
 
 
 
 
 
 | 942 | 
     { | 
 
 
 
 
 
 | 943 | 
       if (option_verbose > 3) { XPR(NT "main write: %s: %u\n", ofile->filename, size); } | 
 
 
 
 
 
 | 944 | 
       ofile->nwrite += size; | 
 
 
 
 
 
 | 945 | 
     } | 
 
 
 
 
 
 | 946 | 
  | 
 
 
 
 
 
 | 947 | 
   return ret; | 
 
 
 
 
 
 | 948 | 
 } | 
 
 
 
 
 
 | 949 | 
  | 
 
 
 
 
 
 | 950 | 
 static int | 
 
 
 
 
 
 | 951 | 
 main_file_seek (main_file *xfile, xoff_t pos) | 
 
 
 
 
 
 | 952 | 
 { | 
 
 
 
 
 
 | 953 | 
   int ret = 0; | 
 
 
 
 
 
 | 954 | 
  | 
 
 
 
 
 
 | 955 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 956 | 
   if (fseek (xfile->file, pos, SEEK_SET) != 0) { ret = get_errno (); } | 
 
 
 
 
 
 | 957 | 
  | 
 
 
 
 
 
 | 958 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 959 | 
   if (lseek (xfile->file, pos, SEEK_SET) != pos) { ret = get_errno (); } | 
 
 
 
 
 
 | 960 | 
  | 
 
 
 
 
 
 | 961 | 
 #elif XD3_WIN32 | 
 
 
 
 
 
 | 962 | 
   LARGE_INTEGER move, out; | 
 
 
 
 
 
 | 963 | 
   move.QuadPart = pos; | 
 
 
 
 
 
 | 964 | 
   if (SetFilePointerEx(xfile->file, move, &out, FILE_BEGIN) == 0) { | 
 
 
 
 
 
 | 965 | 
           ret = get_errno (); | 
 
 
 
 
 
 | 966 | 
   } | 
 
 
 
 
 
 | 967 | 
 #endif | 
 
 
 
 
 
 | 968 | 
  | 
 
 
 
 
 
 | 969 | 
   if (ret) | 
 
 
 
 
 
 | 970 | 
     { | 
 
 
 
 
 
 | 971 | 
       XPR(NT "seek failed: %s: %s\n", xfile->filename, xd3_mainerror (ret)); | 
 
 
 
 
 
 | 972 | 
     } | 
 
 
 
 
 
 | 973 | 
  | 
 
 
 
 
 
 | 974 | 
   return ret; | 
 
 
 
 
 
 | 975 | 
 } | 
 
 
 
 
 
 | 976 | 
  | 
 
 
 
 
 
 | 977 | 
 /****************************************************************************************** | 
 
 
 
 
 
 | 978 | 
  VCDIFF TOOLS | 
 
 
 
 
 
 | 979 | 
  ******************************************************************************************/ | 
 
 
 
 
 
 | 980 | 
  | 
 
 
 
 
 
 | 981 | 
 #if VCDIFF_TOOLS | 
 
 
 
 
 
 | 982 | 
  | 
 
 
 
 
 
 | 983 | 
 /* The following macros let VCDIFF printing something printf-like with | 
 
 
 
 
 
 | 984 | 
  * main_file_write(), e.g.,: | 
 
 
 
 
 
 | 985 | 
  *  | 
 
 
 
 
 
 | 986 | 
  *   VC(UT "trying to be portable: %d\n", x)VE; | 
 
 
 
 
 
 | 987 | 
  */ | 
 
 
 
 
 
 | 988 | 
 #define SNPRINTF_BUFSIZE 1024 | 
 
 
 
 
 
 | 989 | 
 #define VC do { if (((ret = snprintf | 
 
 
 
 
 
 | 990 | 
 #define UT (char*)xfile->snprintf_buf, SNPRINTF_BUFSIZE, | 
 
 
 
 
 
 | 991 | 
 #define VE ) >= SNPRINTF_BUFSIZE                               \ | 
 
 
 
 
 
 | 992 | 
   && (ret = main_print_overflow(ret)) != 0)                    \ | 
 
 
 
 
 
 | 993 | 
   || (ret = main_file_write(xfile, xfile->snprintf_buf,        \ | 
 
 
 
 
 
 | 994 | 
                             ret, "print")) != 0)               \ | 
 
 
 
 
 
 | 995 | 
   { return ret; } } while (0) | 
 
 
 
 
 
 | 996 | 
  | 
 
 
 
 
 
 | 997 | 
 #ifdef WIN32 | 
 
 
 
 
 
 | 998 | 
 /* According to the internet, Windows vsnprintf() differs from most Unix | 
 
 
 
 
 
 | 999 | 
  * implementations regarding the terminating 0 when the boundary condition | 
 
 
 
 
 
 | 1000 | 
  * is met. It doesn't matter here, we don't rely on the trailing 0. */ | 
 
 
 
 
 
 | 1001 | 
 #include <stdarg.h> | 
 
 
 
 
 
 | 1002 | 
 int | 
 
 
 
 
 
 | 1003 | 
 snprintf (char *str, int n, char *fmt, ...) | 
 
 
 
 
 
 | 1004 | 
 { | 
 
 
 
 
 
 | 1005 | 
   va_list a; | 
 
 
 
 
 
 | 1006 | 
   int ret; | 
 
 
 
 
 
 | 1007 | 
   va_start (a, fmt); | 
 
 
 
 
 
 | 1008 | 
   ret = vsnprintf (str, n, fmt, a); | 
 
 
 
 
 
 | 1009 | 
   va_end (a); | 
 
 
 
 
 
 | 1010 | 
   return ret; | 
 
 
 
 
 
 | 1011 | 
 } | 
 
 
 
 
 
 | 1012 | 
 #endif | 
 
 
 
 
 
 | 1013 | 
  | 
 
 
 
 
 
 | 1014 | 
 static int | 
 
 
 
 
 
 | 1015 | 
 main_print_overflow (int x) | 
 
 
 
 
 
 | 1016 | 
 { | 
 
 
 
 
 
 | 1017 | 
   XPR(NT "internal print buffer overflow: %d bytes\n", x); | 
 
 
 
 
 
 | 1018 | 
   return XD3_INTERNAL; | 
 
 
 
 
 
 | 1019 | 
 } | 
 
 
 
 
 
 | 1020 | 
  | 
 
 
 
 
 
 | 1021 | 
 /* This function prints a single VCDIFF window. */ | 
 
 
 
 
 
 | 1022 | 
 static int | 
 
 
 
 
 
 | 1023 | 
 main_print_window (xd3_stream* stream, main_file *xfile) | 
 
 
 
 
 
 | 1024 | 
 { | 
 
 
 
 
 
 | 1025 | 
   int ret; | 
 
 
 
 
 
 | 1026 | 
   usize_t size = 0; | 
 
 
 
 
 
 | 1027 | 
  | 
 
 
 
 
 
 | 1028 | 
   VC(UT "  Offset Code Type1 Size1 @Addr1 + Type2 Size2 @Addr2\n")VE; | 
 
 
 
 
 
 | 1029 | 
  | 
 
 
 
 
 
 | 1030 | 
   while (stream->inst_sect.buf < stream->inst_sect.buf_max) | 
 
 
 
 
 
 | 1031 | 
     { | 
 
 
 
 
 
 | 1032 | 
       uint   code = stream->inst_sect.buf[0]; | 
 
 
 
 
 
 | 1033 | 
  | 
 
 
 
 
 
 | 1034 | 
       if ((ret = xd3_decode_instruction (stream))) { return ret; } | 
 
 
 
 
 
 | 1035 | 
  | 
 
 
 
 
 
 | 1036 | 
       VC(UT "  %06"Q"u %03u  %s %3u", stream->dec_winstart + size, code, | 
 
 
 
 
 
 | 1037 | 
          xd3_rtype_to_string (stream->dec_current1.type, option_print_cpymode), | 
 
 
 
 
 
 | 1038 | 
          (usize_t) stream->dec_current1.size)VE; | 
 
 
 
 
 
 | 1039 | 
  | 
 
 
 
 
 
 | 1040 | 
       if (stream->dec_current1.type != XD3_NOOP) | 
 
 
 
 
 
 | 1041 | 
         { | 
 
 
 
 
 
 | 1042 | 
           size += stream->dec_current1.size; | 
 
 
 
 
 
 | 1043 | 
           if (stream->dec_current1.type >= XD3_CPY) | 
 
 
 
 
 
 | 1044 | 
             { | 
 
 
 
 
 
 | 1045 | 
               VC(UT " @%-6u", (usize_t)stream->dec_current1.addr)VE; | 
 
 
 
 
 
 | 1046 | 
             } | 
 
 
 
 
 
 | 1047 | 
           else | 
 
 
 
 
 
 | 1048 | 
             { | 
 
 
 
 
 
 | 1049 | 
               VC(UT "        ")VE; | 
 
 
 
 
 
 | 1050 | 
             } | 
 
 
 
 
 
 | 1051 | 
         } | 
 
 
 
 
 
 | 1052 | 
  | 
 
 
 
 
 
 | 1053 | 
       if (stream->dec_current2.type != XD3_NOOP) | 
 
 
 
 
 
 | 1054 | 
         { | 
 
 
 
 
 
 | 1055 | 
           size += stream->dec_current2.size; | 
 
 
 
 
 
 | 1056 | 
           VC(UT "  %s %3u", | 
 
 
 
 
 
 | 1057 | 
              xd3_rtype_to_string (stream->dec_current2.type, option_print_cpymode), | 
 
 
 
 
 
 | 1058 | 
              (usize_t)stream->dec_current2.size)VE; | 
 
 
 
 
 
 | 1059 | 
  | 
 
 
 
 
 
 | 1060 | 
           if (stream->dec_current2.type >= XD3_CPY) | 
 
 
 
 
 
 | 1061 | 
             { | 
 
 
 
 
 
 | 1062 | 
               VC(UT " @%-6u", (usize_t)stream->dec_current2.addr)VE; | 
 
 
 
 
 
 | 1063 | 
             } | 
 
 
 
 
 
 | 1064 | 
         } | 
 
 
 
 
 
 | 1065 | 
  | 
 
 
 
 
 
 | 1066 | 
       VC(UT "\n")VE; | 
 
 
 
 
 
 | 1067 | 
     } | 
 
 
 
 
 
 | 1068 | 
  | 
 
 
 
 
 
 | 1069 | 
   if (stream->dec_tgtlen != size && (stream->flags & XD3_SKIP_WINDOW) == 0) | 
 
 
 
 
 
 | 1070 | 
     { | 
 
 
 
 
 
 | 1071 | 
       XPR(NT "target window size inconsistency"); | 
 
 
 
 
 
 | 1072 | 
       return XD3_INTERNAL; | 
 
 
 
 
 
 | 1073 | 
     } | 
 
 
 
 
 
 | 1074 | 
  | 
 
 
 
 
 
 | 1075 | 
   if (stream->dec_position != stream->dec_maxpos) | 
 
 
 
 
 
 | 1076 | 
     { | 
 
 
 
 
 
 | 1077 | 
       XPR(NT "target window position inconsistency"); | 
 
 
 
 
 
 | 1078 | 
       return XD3_INTERNAL; | 
 
 
 
 
 
 | 1079 | 
     } | 
 
 
 
 
 
 | 1080 | 
  | 
 
 
 
 
 
 | 1081 | 
   if (stream->addr_sect.buf != stream->addr_sect.buf_max) | 
 
 
 
 
 
 | 1082 | 
     { | 
 
 
 
 
 
 | 1083 | 
       XPR(NT "address section inconsistency"); | 
 
 
 
 
 
 | 1084 | 
       return XD3_INTERNAL; | 
 
 
 
 
 
 | 1085 | 
     } | 
 
 
 
 
 
 | 1086 | 
  | 
 
 
 
 
 
 | 1087 | 
   return 0; | 
 
 
 
 
 
 | 1088 | 
 } | 
 
 
 
 
 
 | 1089 | 
  | 
 
 
 
 
 
 | 1090 | 
 static int | 
 
 
 
 
 
 | 1091 | 
 main_print_vcdiff_file (main_file *xfile, main_file *file, const char *type) | 
 
 
 
 
 
 | 1092 | 
 { | 
 
 
 
 
 
 | 1093 | 
   int ret;  /* Used by above macros */ | 
 
 
 
 
 
 | 1094 | 
   if (file->filename) | 
 
 
 
 
 
 | 1095 | 
     { | 
 
 
 
 
 
 | 1096 | 
       VC(UT "XDELTA filename (%s):     %s\n", type, file->filename)VE; | 
 
 
 
 
 
 | 1097 | 
     } | 
 
 
 
 
 
 | 1098 | 
   if (file->compressor) | 
 
 
 
 
 
 | 1099 | 
     { | 
 
 
 
 
 
 | 1100 | 
       VC(UT "XDELTA ext comp (%s):     %s\n", type, file->compressor->recomp_cmdname)VE; | 
 
 
 
 
 
 | 1101 | 
     } | 
 
 
 
 
 
 | 1102 | 
   return 0; | 
 
 
 
 
 
 | 1103 | 
 } | 
 
 
 
 
 
 | 1104 | 
  | 
 
 
 
 
 
 | 1105 | 
 /* This function prints a VCDIFF input, mainly for debugging purposes. */ | 
 
 
 
 
 
 | 1106 | 
 static int | 
 
 
 
 
 
 | 1107 | 
 main_print_func (xd3_stream* stream, main_file *xfile) | 
 
 
 
 
 
 | 1108 | 
 { | 
 
 
 
 
 
 | 1109 | 
   int ret; | 
 
 
 
 
 
 | 1110 | 
  | 
 
 
 
 
 
 | 1111 | 
   if (xfile->snprintf_buf == NULL) | 
 
 
 
 
 
 | 1112 | 
     { | 
 
 
 
 
 
 | 1113 | 
       if ((xfile->snprintf_buf = main_malloc(SNPRINTF_BUFSIZE)) == NULL) | 
 
 
 
 
 
 | 1114 | 
         { | 
 
 
 
 
 
 | 1115 | 
           return ENOMEM; | 
 
 
 
 
 
 | 1116 | 
         } | 
 
 
 
 
 
 | 1117 | 
     } | 
 
 
 
 
 
 | 1118 | 
  | 
 
 
 
 
 
 | 1119 | 
   if (stream->dec_winstart == 0) | 
 
 
 
 
 
 | 1120 | 
     { | 
 
 
 
 
 
 | 1121 | 
       VC(UT "VCDIFF version:               0\n")VE; | 
 
 
 
 
 
 | 1122 | 
  | 
 
 
 
 
 
 | 1123 | 
       VC(UT "VCDIFF header size:           %d\n", stream->dec_hdrsize)VE; | 
 
 
 
 
 
 | 1124 | 
       VC(UT "VCDIFF header indicator:      ")VE; | 
 
 
 
 
 
 | 1125 | 
       if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0) VC(UT "VCD_SECONDARY ")VE; | 
 
 
 
 
 
 | 1126 | 
       if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) VC(UT "VCD_CODETABLE ")VE; | 
 
 
 
 
 
 | 1127 | 
       if ((stream->dec_hdr_ind & VCD_APPHEADER) != 0) VC(UT "VCD_APPHEADER ")VE; | 
 
 
 
 
 
 | 1128 | 
       if (stream->dec_hdr_ind == 0) VC(UT "none")VE; | 
 
 
 
 
 
 | 1129 | 
       VC(UT "\n")VE; | 
 
 
 
 
 
 | 1130 | 
  | 
 
 
 
 
 
 | 1131 | 
       IF_SEC(VC(UT "VCDIFF secondary compressor:  %s\n", | 
 
 
 
 
 
 | 1132 | 
                 stream->sec_type ? stream->sec_type->name : "none")VE); | 
 
 
 
 
 
 | 1133 | 
       IF_NSEC(VC(UT "VCDIFF secondary compressor: unsupported\n")VE); | 
 
 
 
 
 
 | 1134 | 
  | 
 
 
 
 
 
 | 1135 | 
       if (stream->dec_hdr_ind & VCD_APPHEADER) | 
 
 
 
 
 
 | 1136 | 
         { | 
 
 
 
 
 
 | 1137 | 
           uint8_t *apphead; | 
 
 
 
 
 
 | 1138 | 
           usize_t appheadsz; | 
 
 
 
 
 
 | 1139 | 
           ret = xd3_get_appheader (stream, & apphead, & appheadsz); | 
 
 
 
 
 
 | 1140 | 
  | 
 
 
 
 
 
 | 1141 | 
           if (ret == 0 && appheadsz > 0) | 
 
 
 
 
 
 | 1142 | 
             { | 
 
 
 
 
 
 | 1143 | 
               int sq = option_quiet; | 
 
 
 
 
 
 | 1144 | 
               main_file i, o, s; | 
 
 
 
 
 
 | 1145 | 
               XD3_ASSERT (apphead != NULL); | 
 
 
 
 
 
 | 1146 | 
               VC(UT "VCDIFF application header:    ")VE; | 
 
 
 
 
 
 | 1147 | 
               if ((ret = main_file_write (xfile, apphead, appheadsz, "print")) != 0) { return ret; } | 
 
 
 
 
 
 | 1148 | 
               VC(UT "\n")VE; | 
 
 
 
 
 
 | 1149 | 
  | 
 
 
 
 
 
 | 1150 | 
               main_file_init (& i); | 
 
 
 
 
 
 | 1151 | 
               main_file_init (& o); | 
 
 
 
 
 
 | 1152 | 
               main_file_init (& s); | 
 
 
 
 
 
 | 1153 | 
               option_quiet = 1; | 
 
 
 
 
 
 | 1154 | 
               main_get_appheader (stream, &i, & o, & s); | 
 
 
 
 
 
 | 1155 | 
               option_quiet = sq; | 
 
 
 
 
 
 | 1156 | 
               if ((ret = main_print_vcdiff_file (xfile, & o, "output"))) { return ret; } | 
 
 
 
 
 
 | 1157 | 
               if ((ret = main_print_vcdiff_file (xfile, & s, "source"))) { return ret; } | 
 
 
 
 
 
 | 1158 | 
               main_file_cleanup (& i); | 
 
 
 
 
 
 | 1159 | 
               main_file_cleanup (& o); | 
 
 
 
 
 
 | 1160 | 
               main_file_cleanup (& s); | 
 
 
 
 
 
 | 1161 | 
             } | 
 
 
 
 
 
 | 1162 | 
         } | 
 
 
 
 
 
 | 1163 | 
     } | 
 
 
 
 
 
 | 1164 | 
   else | 
 
 
 
 
 
 | 1165 | 
     { | 
 
 
 
 
 
 | 1166 | 
       VC(UT "\n")VE; | 
 
 
 
 
 
 | 1167 | 
     } | 
 
 
 
 
 
 | 1168 | 
  | 
 
 
 
 
 
 | 1169 | 
   VC(UT "VCDIFF window number:         %"Q"u\n", stream->current_window)VE; | 
 
 
 
 
 
 | 1170 | 
   VC(UT "VCDIFF window indicator:      ")VE; | 
 
 
 
 
 
 | 1171 | 
   if ((stream->dec_win_ind & VCD_SOURCE) != 0) VC(UT "VCD_SOURCE ")VE; | 
 
 
 
 
 
 | 1172 | 
   if ((stream->dec_win_ind & VCD_TARGET) != 0) VC(UT "VCD_TARGET ")VE; | 
 
 
 
 
 
 | 1173 | 
   if ((stream->dec_win_ind & VCD_ADLER32) != 0) VC(UT "VCD_ADLER32 ")VE; | 
 
 
 
 
 
 | 1174 | 
   if (stream->dec_win_ind == 0) VC(UT "none")VE; | 
 
 
 
 
 
 | 1175 | 
   VC(UT "\n")VE; | 
 
 
 
 
 
 | 1176 | 
  | 
 
 
 
 
 
 | 1177 | 
   if ((stream->dec_win_ind & VCD_ADLER32) != 0) | 
 
 
 
 
 
 | 1178 | 
     { | 
 
 
 
 
 
 | 1179 | 
       VC(UT "VCDIFF adler32 checksum:      %08X\n", (usize_t)stream->dec_adler32)VE; | 
 
 
 
 
 
 | 1180 | 
     } | 
 
 
 
 
 
 | 1181 | 
  | 
 
 
 
 
 
 | 1182 | 
   if (stream->dec_del_ind != 0) | 
 
 
 
 
 
 | 1183 | 
     { | 
 
 
 
 
 
 | 1184 | 
       VC(UT "VCDIFF delta indicator:       ")VE; | 
 
 
 
 
 
 | 1185 | 
       if ((stream->dec_del_ind & VCD_DATACOMP) != 0) VC(UT "VCD_DATACOMP ")VE; | 
 
 
 
 
 
 | 1186 | 
       if ((stream->dec_del_ind & VCD_INSTCOMP) != 0) VC(UT "VCD_INSTCOMP ")VE; | 
 
 
 
 
 
 | 1187 | 
       if ((stream->dec_del_ind & VCD_ADDRCOMP) != 0) VC(UT "VCD_ADDRCOMP ")VE; | 
 
 
 
 
 
 | 1188 | 
       if (stream->dec_del_ind == 0) VC(UT "none")VE; | 
 
 
 
 
 
 | 1189 | 
       VC(UT "\n")VE; | 
 
 
 
 
 
 | 1190 | 
     } | 
 
 
 
 
 
 | 1191 | 
  | 
 
 
 
 
 
 | 1192 | 
   if (stream->dec_winstart != 0) | 
 
 
 
 
 
 | 1193 | 
     { | 
 
 
 
 
 
 | 1194 | 
       VC(UT "VCDIFF window at offset:      %"Q"u\n", stream->dec_winstart)VE; | 
 
 
 
 
 
 | 1195 | 
     } | 
 
 
 
 
 
 | 1196 | 
  | 
 
 
 
 
 
 | 1197 | 
   if (SRCORTGT (stream->dec_win_ind)) | 
 
 
 
 
 
 | 1198 | 
     { | 
 
 
 
 
 
 | 1199 | 
       VC(UT "VCDIFF copy window length:    %u\n", (usize_t)stream->dec_cpylen)VE; | 
 
 
 
 
 
 | 1200 | 
       VC(UT "VCDIFF copy window offset:    %"Q"u\n", stream->dec_cpyoff)VE; | 
 
 
 
 
 
 | 1201 | 
     } | 
 
 
 
 
 
 | 1202 | 
  | 
 
 
 
 
 
 | 1203 | 
   VC(UT "VCDIFF delta encoding length: %u\n", (usize_t)stream->dec_enclen)VE; | 
 
 
 
 
 
 | 1204 | 
   VC(UT "VCDIFF target window length:  %u\n", (usize_t)stream->dec_tgtlen)VE; | 
 
 
 
 
 
 | 1205 | 
  | 
 
 
 
 
 
 | 1206 | 
   VC(UT "VCDIFF data section length:   %u\n", (usize_t)stream->data_sect.size)VE; | 
 
 
 
 
 
 | 1207 | 
   VC(UT "VCDIFF inst section length:   %u\n", (usize_t)stream->inst_sect.size)VE; | 
 
 
 
 
 
 | 1208 | 
   VC(UT "VCDIFF addr section length:   %u\n", (usize_t)stream->addr_sect.size)VE; | 
 
 
 
 
 
 | 1209 | 
  | 
 
 
 
 
 
 | 1210 | 
   ret = 0; | 
 
 
 
 
 
 | 1211 | 
   if ((stream->flags & XD3_JUST_HDR) != 0) | 
 
 
 
 
 
 | 1212 | 
     { | 
 
 
 
 
 
 | 1213 | 
       /* Print a header -- finished! */ | 
 
 
 
 
 
 | 1214 | 
       ret = PRINTHDR_SPECIAL; | 
 
 
 
 
 
 | 1215 | 
     } | 
 
 
 
 
 
 | 1216 | 
   else if ((stream->flags & XD3_SKIP_WINDOW) == 0) | 
 
 
 
 
 
 | 1217 | 
     { | 
 
 
 
 
 
 | 1218 | 
       ret = main_print_window (stream, xfile); | 
 
 
 
 
 
 | 1219 | 
     } | 
 
 
 
 
 
 | 1220 | 
  | 
 
 
 
 
 
 | 1221 | 
   return ret; | 
 
 
 
 
 
 | 1222 | 
 } | 
 
 
 
 
 
 | 1223 | 
 #endif /* VCDIFF_TOOLS */ | 
 
 
 
 
 
 | 1224 | 
  | 
 
 
 
 
 
 | 1225 | 
 /****************************************************************************************** | 
 
 
 
 
 
 | 1226 | 
  Input decompression, output recompression | 
 
 
 
 
 
 | 1227 | 
  ******************************************************************************************/ | 
 
 
 
 
 
 | 1228 | 
  | 
 
 
 
 
 
 | 1229 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 1230 | 
 /* This is tricky POSIX-specific code with lots of fork(), pipe(), dup(), waitpid(), and | 
 
 
 
 
 
 | 1231 | 
  * exec() business.  Most of this code originated in PRCS1, which did automatic | 
 
 
 
 
 
 | 1232 | 
  * package-file decompression.  It works with both XD3_POSIX and XD3_STDIO file | 
 
 
 
 
 
 | 1233 | 
  * disciplines. | 
 
 
 
 
 
 | 1234 | 
  * | 
 
 
 
 
 
 | 1235 | 
  * To automatically detect compressed inputs requires a child process to reconstruct the | 
 
 
 
 
 
 | 1236 | 
  * input stream, which was advanced in order to detect compression, because it may not be | 
 
 
 
 
 
 | 1237 | 
  * seekable.  In other words, the main program reads part of the input stream, and if it | 
 
 
 
 
 
 | 1238 | 
  * detects a compressed input it then forks a pipe copier process, which copies the | 
 
 
 
 
 
 | 1239 | 
  * first-read block out of the main-program's memory, then streams the remaining | 
 
 
 
 
 
 | 1240 | 
  * compressed input into the input-decompression pipe. | 
 
 
 
 
 
 | 1241 | 
  */ | 
 
 
 
 
 
 | 1242 | 
  | 
 
 
 
 
 
 | 1243 | 
 #include <unistd.h> | 
 
 
 
 
 
 | 1244 | 
 #include <sys/stat.h> | 
 
 
 
 
 
 | 1245 | 
 #include <sys/wait.h> | 
 
 
 
 
 
 | 1246 | 
  | 
 
 
 
 
 
 | 1247 | 
 /* Remember which pipe FD is which. */ | 
 
 
 
 
 
 | 1248 | 
 #define PIPE_READ_FD  0 | 
 
 
 
 
 
 | 1249 | 
 #define PIPE_WRITE_FD 1 | 
 
 
 
 
 
 | 1250 | 
  | 
 
 
 
 
 
 | 1251 | 
 static pid_t ext_subprocs[2]; | 
 
 
 
 
 
 | 1252 | 
 static char* ext_tmpfile = NULL; | 
 
 
 
 
 
 | 1253 | 
  | 
 
 
 
 
 
 | 1254 | 
 /* Like write(), but makes repeated calls to empty the buffer. */ | 
 
 
 
 
 
 | 1255 | 
 static int | 
 
 
 
 
 
 | 1256 | 
 main_pipe_write (int outfd, const uint8_t *exist_buf, usize_t remain) | 
 
 
 
 
 
 | 1257 | 
 { | 
 
 
 
 
 
 | 1258 | 
   int ret; | 
 
 
 
 
 
 | 1259 | 
  | 
 
 
 
 
 
 | 1260 | 
   if ((ret = xd3_posix_io (outfd, (uint8_t*) exist_buf, remain, (xd3_posix_func*) &write, NULL))) | 
 
 
 
 
 
 | 1261 | 
     { | 
 
 
 
 
 
 | 1262 | 
       XPR(NT "pipe write failed: %s", xd3_mainerror (ret)); | 
 
 
 
 
 
 | 1263 | 
       return ret; | 
 
 
 
 
 
 | 1264 | 
     } | 
 
 
 
 
 
 | 1265 | 
  | 
 
 
 
 
 
 | 1266 | 
   return 0; | 
 
 
 
 
 
 | 1267 | 
 } | 
 
 
 
 
 
 | 1268 | 
  | 
 
 
 
 
 
 | 1269 | 
 /* A simple error-reporting waitpid interface. */ | 
 
 
 
 
 
 | 1270 | 
 static int | 
 
 
 
 
 
 | 1271 | 
 main_waitpid_check(pid_t pid) | 
 
 
 
 
 
 | 1272 | 
 { | 
 
 
 
 
 
 | 1273 | 
   int status; | 
 
 
 
 
 
 | 1274 | 
   int ret = 0; | 
 
 
 
 
 
 | 1275 | 
  | 
 
 
 
 
 
 | 1276 | 
   if (waitpid (pid, & status, 0) < 0) | 
 
 
 
 
 
 | 1277 | 
     { | 
 
 
 
 
 
 | 1278 | 
       ret = get_errno (); | 
 
 
 
 
 
 | 1279 | 
       XPR(NT "compression subprocess: wait: %s\n", xd3_mainerror (ret)); | 
 
 
 
 
 
 | 1280 | 
     } | 
 
 
 
 
 
 | 1281 | 
   else if (! WIFEXITED (status)) | 
 
 
 
 
 
 | 1282 | 
     { | 
 
 
 
 
 
 | 1283 | 
       ret = ECHILD; | 
 
 
 
 
 
 | 1284 | 
       XPR(NT "compression subprocess: signal %d\n", | 
 
 
 
 
 
 | 1285 | 
          WIFSIGNALED (status) ? WTERMSIG (status) : WSTOPSIG (status)); | 
 
 
 
 
 
 | 1286 | 
     } | 
 
 
 
 
 
 | 1287 | 
   else if (WEXITSTATUS (status) != 0) | 
 
 
 
 
 
 | 1288 | 
     { | 
 
 
 
 
 
 | 1289 | 
       ret = ECHILD; | 
 
 
 
 
 
 | 1290 | 
       XPR(NT "compression subprocess: exit %d\n", WEXITSTATUS (status)); | 
 
 
 
 
 
 | 1291 | 
     } | 
 
 
 
 
 
 | 1292 | 
  | 
 
 
 
 
 
 | 1293 | 
   return ret; | 
 
 
 
 
 
 | 1294 | 
 } | 
 
 
 
 
 
 | 1295 | 
  | 
 
 
 
 
 
 | 1296 | 
 /* Wait for any existing child processes to check for abnormal exit. */ | 
 
 
 
 
 
 | 1297 | 
 static int | 
 
 
 
 
 
 | 1298 | 
 main_external_compression_finish (void) | 
 
 
 
 
 
 | 1299 | 
 { | 
 
 
 
 
 
 | 1300 | 
   int i; | 
 
 
 
 
 
 | 1301 | 
   int ret; | 
 
 
 
 
 
 | 1302 | 
  | 
 
 
 
 
 
 | 1303 | 
   for (i = 0; i < 2; i += 1) | 
 
 
 
 
 
 | 1304 | 
     { | 
 
 
 
 
 
 | 1305 | 
       if (! ext_subprocs[i]) { continue; } | 
 
 
 
 
 
 | 1306 | 
  | 
 
 
 
 
 
 | 1307 | 
       if ((ret = main_waitpid_check (ext_subprocs[i]))) | 
 
 
 
 
 
 | 1308 | 
         { | 
 
 
 
 
 
 | 1309 | 
           return ret; | 
 
 
 
 
 
 | 1310 | 
         } | 
 
 
 
 
 
 | 1311 | 
     } | 
 
 
 
 
 
 | 1312 | 
  | 
 
 
 
 
 
 | 1313 | 
   return 0; | 
 
 
 
 
 
 | 1314 | 
 } | 
 
 
 
 
 
 | 1315 | 
  | 
 
 
 
 
 
 | 1316 | 
 /* This runs as a forked process of main_input_decompress_setup() to copy input to the | 
 
 
 
 
 
 | 1317 | 
  * decompression process.  First, the available input is copied out of the existing | 
 
 
 
 
 
 | 1318 | 
  * buffer, then the buffer is reused to continue reading from the compressed input | 
 
 
 
 
 
 | 1319 | 
  * file. */ | 
 
 
 
 
 
 | 1320 | 
 static int | 
 
 
 
 
 
 | 1321 | 
 main_pipe_copier (uint8_t    *pipe_buf, | 
 
 
 
 
 
 | 1322 | 
                   usize_t      pipe_bufsize, | 
 
 
 
 
 
 | 1323 | 
                   usize_t      nread, | 
 
 
 
 
 
 | 1324 | 
                   main_file   *ifile, | 
 
 
 
 
 
 | 1325 | 
                   int         outfd) | 
 
 
 
 
 
 | 1326 | 
 { | 
 
 
 
 
 
 | 1327 | 
   int ret; | 
 
 
 
 
 
 | 1328 | 
  | 
 
 
 
 
 
 | 1329 | 
   for (;;) | 
 
 
 
 
 
 | 1330 | 
     { | 
 
 
 
 
 
 | 1331 | 
       if (nread > 0 && (ret = main_pipe_write (outfd, pipe_buf, nread))) | 
 
 
 
 
 
 | 1332 | 
         { | 
 
 
 
 
 
 | 1333 | 
           return ret; | 
 
 
 
 
 
 | 1334 | 
         } | 
 
 
 
 
 
 | 1335 | 
  | 
 
 
 
 
 
 | 1336 | 
       if (nread < pipe_bufsize) | 
 
 
 
 
 
 | 1337 | 
         { | 
 
 
 
 
 
 | 1338 | 
           break; | 
 
 
 
 
 
 | 1339 | 
         } | 
 
 
 
 
 
 | 1340 | 
  | 
 
 
 
 
 
 | 1341 | 
       if ((ret = main_file_read (ifile, pipe_buf, pipe_bufsize, & nread, "pipe read failed")) < 0) | 
 
 
 
 
 
 | 1342 | 
         { | 
 
 
 
 
 
 | 1343 | 
           return ret; | 
 
 
 
 
 
 | 1344 | 
         } | 
 
 
 
 
 
 | 1345 | 
     } | 
 
 
 
 
 
 | 1346 | 
  | 
 
 
 
 
 
 | 1347 | 
   return 0; | 
 
 
 
 
 
 | 1348 | 
 } | 
 
 
 
 
 
 | 1349 | 
  | 
 
 
 
 
 
 | 1350 | 
 /* This function is called after we have read some amount of data from the input file and | 
 
 
 
 
 
 | 1351 | 
  * detected a compressed input.  Here we start a decompression subprocess by forking | 
 
 
 
 
 
 | 1352 | 
  * twice.  The first process runs the decompression command, the second process copies | 
 
 
 
 
 
 | 1353 | 
  * data to the input of the first. */ | 
 
 
 
 
 
 | 1354 | 
 static int | 
 
 
 
 
 
 | 1355 | 
 main_input_decompress_setup (const main_extcomp     *decomp, | 
 
 
 
 
 
 | 1356 | 
                              main_file              *ifile, | 
 
 
 
 
 
 | 1357 | 
                              uint8_t               *input_buf, | 
 
 
 
 
 
 | 1358 | 
                              usize_t                 input_bufsize, | 
 
 
 
 
 
 | 1359 | 
                              uint8_t               *pipe_buf, | 
 
 
 
 
 
 | 1360 | 
                              usize_t                 pipe_bufsize, | 
 
 
 
 
 
 | 1361 | 
                              usize_t                 pipe_avail, | 
 
 
 
 
 
 | 1362 | 
                              usize_t                *nread) | 
 
 
 
 
 
 | 1363 | 
 { | 
 
 
 
 
 
 | 1364 | 
   int outpipefd[2], inpipefd[2];  /* The two pipes: input and output file descriptors. */ | 
 
 
 
 
 
 | 1365 | 
   int input_fd = -1;              /* The resulting input_fd (output of decompression). */ | 
 
 
 
 
 
 | 1366 | 
   pid_t decomp_id, copier_id;     /* The two subprocs. */ | 
 
 
 
 
 
 | 1367 | 
   int ret; | 
 
 
 
 
 
 | 1368 | 
  | 
 
 
 
 
 
 | 1369 | 
   outpipefd[0] = outpipefd[1] = -1; | 
 
 
 
 
 
 | 1370 | 
   inpipefd[0]  = inpipefd[1]  = -1; | 
 
 
 
 
 
 | 1371 | 
  | 
 
 
 
 
 
 | 1372 | 
   if (pipe (outpipefd) || pipe (inpipefd)) | 
 
 
 
 
 
 | 1373 | 
     { | 
 
 
 
 
 
 | 1374 | 
       XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1375 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1376 | 
     } | 
 
 
 
 
 
 | 1377 | 
  | 
 
 
 
 
 
 | 1378 | 
   if ((decomp_id = fork ()) < 0) | 
 
 
 
 
 
 | 1379 | 
     { | 
 
 
 
 
 
 | 1380 | 
       XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1381 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1382 | 
     } | 
 
 
 
 
 
 | 1383 | 
  | 
 
 
 
 
 
 | 1384 | 
   /* The first child runs the decompression process: */ | 
 
 
 
 
 
 | 1385 | 
   if (decomp_id == 0) | 
 
 
 
 
 
 | 1386 | 
     { | 
 
 
 
 
 
 | 1387 | 
       /* Setup pipes: write to the outpipe, read from the inpipe. */ | 
 
 
 
 
 
 | 1388 | 
       if (dup2 (outpipefd[PIPE_WRITE_FD], STDOUT_FILENO) < 0 || | 
 
 
 
 
 
 | 1389 | 
           dup2 (inpipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || | 
 
 
 
 
 
 | 1390 | 
           close (outpipefd[PIPE_READ_FD]) || | 
 
 
 
 
 
 | 1391 | 
           close (outpipefd[PIPE_WRITE_FD]) || | 
 
 
 
 
 
 | 1392 | 
           close (inpipefd[PIPE_READ_FD]) || | 
 
 
 
 
 
 | 1393 | 
           close (inpipefd[PIPE_WRITE_FD]) || | 
 
 
 
 
 
 | 1394 | 
           execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, decomp->decomp_options, NULL)) | 
 
 
 
 
 
 | 1395 | 
         { | 
 
 
 
 
 
 | 1396 | 
           XPR(NT "child process %s failed to execute: %s\n", decomp->decomp_cmdname, xd3_mainerror (get_errno ())); | 
 
 
 
 
 
 | 1397 | 
         } | 
 
 
 
 
 
 | 1398 | 
  | 
 
 
 
 
 
 | 1399 | 
       _exit (127); | 
 
 
 
 
 
 | 1400 | 
     } | 
 
 
 
 
 
 | 1401 | 
  | 
 
 
 
 
 
 | 1402 | 
   ext_subprocs[0] = decomp_id; | 
 
 
 
 
 
 | 1403 | 
  | 
 
 
 
 
 
 | 1404 | 
   if ((copier_id = fork ()) < 0) | 
 
 
 
 
 
 | 1405 | 
     { | 
 
 
 
 
 
 | 1406 | 
       XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1407 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1408 | 
     } | 
 
 
 
 
 
 | 1409 | 
  | 
 
 
 
 
 
 | 1410 | 
   /* The second child runs the copier process: */ | 
 
 
 
 
 
 | 1411 | 
   if (copier_id == 0) | 
 
 
 
 
 
 | 1412 | 
     { | 
 
 
 
 
 
 | 1413 | 
       int exitval = 0; | 
 
 
 
 
 
 | 1414 | 
  | 
 
 
 
 
 
 | 1415 | 
       if (close (inpipefd[PIPE_READ_FD]) || | 
 
 
 
 
 
 | 1416 | 
           main_pipe_copier (pipe_buf, pipe_bufsize, pipe_avail, ifile, inpipefd[PIPE_WRITE_FD]) || | 
 
 
 
 
 
 | 1417 | 
           close (inpipefd[PIPE_WRITE_FD])) | 
 
 
 
 
 
 | 1418 | 
         { | 
 
 
 
 
 
 | 1419 | 
           XPR(NT "child copier process failed: %s\n", xd3_mainerror (get_errno ())); | 
 
 
 
 
 
 | 1420 | 
           exitval = 1; | 
 
 
 
 
 
 | 1421 | 
         } | 
 
 
 
 
 
 | 1422 | 
  | 
 
 
 
 
 
 | 1423 | 
       _exit (exitval); | 
 
 
 
 
 
 | 1424 | 
     } | 
 
 
 
 
 
 | 1425 | 
  | 
 
 
 
 
 
 | 1426 | 
   ext_subprocs[1] = copier_id; | 
 
 
 
 
 
 | 1427 | 
  | 
 
 
 
 
 
 | 1428 | 
   /* The parent closes both pipes after duplicating the output of compression. */ | 
 
 
 
 
 
 | 1429 | 
   input_fd = dup (outpipefd[PIPE_READ_FD]); | 
 
 
 
 
 
 | 1430 | 
  | 
 
 
 
 
 
 | 1431 | 
   if (input_fd < 0 || | 
 
 
 
 
 
 | 1432 | 
       main_file_close (ifile) || | 
 
 
 
 
 
 | 1433 | 
       close (outpipefd[PIPE_READ_FD]) || | 
 
 
 
 
 
 | 1434 | 
       close (outpipefd[PIPE_WRITE_FD]) || | 
 
 
 
 
 
 | 1435 | 
       close (inpipefd[PIPE_READ_FD]) || | 
 
 
 
 
 
 | 1436 | 
       close (inpipefd[PIPE_WRITE_FD])) | 
 
 
 
 
 
 | 1437 | 
     { | 
 
 
 
 
 
 | 1438 | 
       XPR(NT "dup/close failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1439 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1440 | 
     } | 
 
 
 
 
 
 | 1441 | 
  | 
 
 
 
 
 
 | 1442 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 1443 | 
   /* Note: fdopen() acquires the fd, closes it when finished. */ | 
 
 
 
 
 
 | 1444 | 
   if ((ifile->file = fdopen (input_fd, "r")) == NULL) | 
 
 
 
 
 
 | 1445 | 
     { | 
 
 
 
 
 
 | 1446 | 
       XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1447 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1448 | 
     } | 
 
 
 
 
 
 | 1449 | 
  | 
 
 
 
 
 
 | 1450 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 1451 | 
   ifile->file = input_fd; | 
 
 
 
 
 
 | 1452 | 
 #endif | 
 
 
 
 
 
 | 1453 | 
  | 
 
 
 
 
 
 | 1454 | 
   ifile->compressor = decomp; | 
 
 
 
 
 
 | 1455 | 
  | 
 
 
 
 
 
 | 1456 | 
   /* Now the input file is decompressed. */ | 
 
 
 
 
 
 | 1457 | 
   return main_file_read (ifile, input_buf, input_bufsize, nread, "input decompression failed"); | 
 
 
 
 
 
 | 1458 | 
  | 
 
 
 
 
 
 | 1459 | 
  pipe_cleanup: | 
 
 
 
 
 
 | 1460 | 
   close (input_fd); | 
 
 
 
 
 
 | 1461 | 
   close (outpipefd[PIPE_READ_FD]); | 
 
 
 
 
 
 | 1462 | 
   close (outpipefd[PIPE_WRITE_FD]); | 
 
 
 
 
 
 | 1463 | 
   close (inpipefd[PIPE_READ_FD]); | 
 
 
 
 
 
 | 1464 | 
   close (inpipefd[PIPE_WRITE_FD]); | 
 
 
 
 
 
 | 1465 | 
   return ret; | 
 
 
 
 
 
 | 1466 | 
 } | 
 
 
 
 
 
 | 1467 | 
  | 
 
 
 
 
 
 | 1468 | 
  | 
 
 
 
 
 
 | 1469 | 
 /* This routine is called when the first buffer of input data is read by the main program | 
 
 
 
 
 
 | 1470 | 
  * (unless input decompression is disabled by command-line option).  If it recognizes the | 
 
 
 
 
 
 | 1471 | 
  * magic number of a known input type it invokes decompression. | 
 
 
 
 
 
 | 1472 | 
  * | 
 
 
 
 
 
 | 1473 | 
  * Skips decompression if the decompression type or the file type is RD_NONEXTERNAL. | 
 
 
 
 
 
 | 1474 | 
  * | 
 
 
 
 
 
 | 1475 | 
  * Behaves exactly like main_file_read, otherwise. | 
 
 
 
 
 
 | 1476 | 
  * | 
 
 
 
 
 
 | 1477 | 
  * This function uses a separate buffer to read the first small block of input.  If a | 
 
 
 
 
 
 | 1478 | 
  * compressed input is detected, the separate buffer is passed to the pipe copier.  This | 
 
 
 
 
 
 | 1479 | 
  * avoids using the same size buffer in both cases. */ | 
 
 
 
 
 
 | 1480 | 
 static int | 
 
 
 
 
 
 | 1481 | 
 main_decompress_input_check (main_file   *ifile, | 
 
 
 
 
 
 | 1482 | 
                             uint8_t    *input_buf, | 
 
 
 
 
 
 | 1483 | 
                             usize_t      input_size, | 
 
 
 
 
 
 | 1484 | 
                             usize_t     *nread) | 
 
 
 
 
 
 | 1485 | 
 { | 
 
 
 
 
 
 | 1486 | 
   int i; | 
 
 
 
 
 
 | 1487 | 
   int ret; | 
 
 
 
 
 
 | 1488 | 
   uint8_t check_buf[XD3_ALLOCSIZE]; | 
 
 
 
 
 
 | 1489 | 
   usize_t  check_nread; | 
 
 
 
 
 
 | 1490 | 
  | 
 
 
 
 
 
 | 1491 | 
   if ((ret = main_file_read (ifile, check_buf, min (input_size, XD3_ALLOCSIZE), & check_nread, "input read failed"))) | 
 
 
 
 
 
 | 1492 | 
     { | 
 
 
 
 
 
 | 1493 | 
       return ret; | 
 
 
 
 
 
 | 1494 | 
     } | 
 
 
 
 
 
 | 1495 | 
  | 
 
 
 
 
 
 | 1496 | 
   for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) | 
 
 
 
 
 
 | 1497 | 
     { | 
 
 
 
 
 
 | 1498 | 
       const main_extcomp *decomp = & extcomp_types[i]; | 
 
 
 
 
 
 | 1499 | 
  | 
 
 
 
 
 
 | 1500 | 
       if ((check_nread > decomp->magic_size) && | 
 
 
 
 
 
 | 1501 | 
           /* The following expr skips decompression if we are trying to read a VCDIFF | 
 
 
 
 
 
 | 1502 | 
            * input and that is the magic number. */ | 
 
 
 
 
 
 | 1503 | 
           !((decomp->flags & RD_NONEXTERNAL) && (ifile->flags & RD_NONEXTERNAL)) && | 
 
 
 
 
 
 | 1504 | 
           memcmp (check_buf, decomp->magic, decomp->magic_size) == 0) | 
 
 
 
 
 
 | 1505 | 
         { | 
 
 
 
 
 
 | 1506 | 
           if (! option_quiet) | 
 
 
 
 
 
 | 1507 | 
             { | 
 
 
 
 
 
 | 1508 | 
               XPR(NT "%s | %s %s\n", | 
 
 
 
 
 
 | 1509 | 
                  ifile->filename, | 
 
 
 
 
 
 | 1510 | 
                  decomp->decomp_cmdname, | 
 
 
 
 
 
 | 1511 | 
                  decomp->decomp_options); | 
 
 
 
 
 
 | 1512 | 
             } | 
 
 
 
 
 
 | 1513 | 
  | 
 
 
 
 
 
 | 1514 | 
           return main_input_decompress_setup (decomp, ifile, | 
 
 
 
 
 
 | 1515 | 
                                               input_buf, input_size, | 
 
 
 
 
 
 | 1516 | 
                                               check_buf, XD3_ALLOCSIZE, | 
 
 
 
 
 
 | 1517 | 
                                               check_nread, nread); | 
 
 
 
 
 
 | 1518 | 
         } | 
 
 
 
 
 
 | 1519 | 
     } | 
 
 
 
 
 
 | 1520 | 
  | 
 
 
 
 
 
 | 1521 | 
   /* Now read the rest of the input block. */ | 
 
 
 
 
 
 | 1522 | 
   (*nread) = 0; | 
 
 
 
 
 
 | 1523 | 
  | 
 
 
 
 
 
 | 1524 | 
   if (check_nread == XD3_ALLOCSIZE) | 
 
 
 
 
 
 | 1525 | 
     { | 
 
 
 
 
 
 | 1526 | 
       ret = main_file_read (ifile, input_buf + XD3_ALLOCSIZE, | 
 
 
 
 
 
 | 1527 | 
                             input_size - XD3_ALLOCSIZE, nread, | 
 
 
 
 
 
 | 1528 | 
                             "input read failed"); | 
 
 
 
 
 
 | 1529 | 
     } | 
 
 
 
 
 
 | 1530 | 
  | 
 
 
 
 
 
 | 1531 | 
   memcpy (input_buf, check_buf, check_nread); | 
 
 
 
 
 
 | 1532 | 
  | 
 
 
 
 
 
 | 1533 | 
   (*nread) += check_nread; | 
 
 
 
 
 
 | 1534 | 
  | 
 
 
 
 
 
 | 1535 | 
   return 0; | 
 
 
 
 
 
 | 1536 | 
 } | 
 
 
 
 
 
 | 1537 | 
  | 
 
 
 
 
 
 | 1538 | 
 /* This is called when the source file needs to be decompressed.  We fork/exec a | 
 
 
 
 
 
 | 1539 | 
  * decompression command with the proper input and output to a temporary file. */ | 
 
 
 
 
 
 | 1540 | 
 static int | 
 
 
 
 
 
 | 1541 | 
 main_decompress_source (main_file *sfile, xd3_source *source) | 
 
 
 
 
 
 | 1542 | 
 { | 
 
 
 
 
 
 | 1543 | 
   const main_extcomp *decomp = sfile->compressor; | 
 
 
 
 
 
 | 1544 | 
   pid_t decomp_id;  /* One subproc. */ | 
 
 
 
 
 
 | 1545 | 
   int   input_fd  = -1; | 
 
 
 
 
 
 | 1546 | 
   int   output_fd = -1; | 
 
 
 
 
 
 | 1547 | 
   int   ret; | 
 
 
 
 
 
 | 1548 | 
   char *tmpname = NULL; | 
 
 
 
 
 
 | 1549 | 
   char *tmpdir  = getenv ("TMPDIR"); | 
 
 
 
 
 
 | 1550 | 
   static const char tmpl[] = "/xd3src.XXXXXX"; | 
 
 
 
 
 
 | 1551 | 
  | 
 
 
 
 
 
 | 1552 | 
   /* Make a template for mkstmp() */ | 
 
 
 
 
 
 | 1553 | 
   if (tmpdir == NULL) { tmpdir = "/tmp"; } | 
 
 
 
 
 
 | 1554 | 
   if ((tmpname = main_malloc (strlen (tmpdir) + sizeof (tmpl) + 1)) == NULL) { return ENOMEM; } | 
 
 
 
 
 
 | 1555 | 
   sprintf (tmpname, "%s%s", tmpdir, tmpl); | 
 
 
 
 
 
 | 1556 | 
  | 
 
 
 
 
 
 | 1557 | 
   XD3_ASSERT (ext_tmpfile == NULL); | 
 
 
 
 
 
 | 1558 | 
   ext_tmpfile = tmpname; | 
 
 
 
 
 
 | 1559 | 
  | 
 
 
 
 
 
 | 1560 | 
   /* Open the output FD. */ | 
 
 
 
 
 
 | 1561 | 
   if ((output_fd = mkstemp (tmpname)) < 0) | 
 
 
 
 
 
 | 1562 | 
     { | 
 
 
 
 
 
 | 1563 | 
       XPR(NT "mkstemp failed: %s: %s", tmpname, xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1564 | 
       goto cleanup; | 
 
 
 
 
 
 | 1565 | 
     } | 
 
 
 
 
 
 | 1566 | 
  | 
 
 
 
 
 
 | 1567 | 
   /* Copy the input FD, reset file position. */ | 
 
 
 
 
 
 | 1568 | 
   XD3_ASSERT (main_file_isopen (sfile)); | 
 
 
 
 
 
 | 1569 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 1570 | 
   if ((input_fd = dup (fileno (sfile->file))) < 0) | 
 
 
 
 
 
 | 1571 | 
     { | 
 
 
 
 
 
 | 1572 | 
       XPR(NT "dup failed: %s", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1573 | 
       goto cleanup; | 
 
 
 
 
 
 | 1574 | 
     } | 
 
 
 
 
 
 | 1575 | 
   main_file_close (sfile); | 
 
 
 
 
 
 | 1576 | 
   sfile->file = NULL; | 
 
 
 
 
 
 | 1577 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 1578 | 
   input_fd = sfile->file; | 
 
 
 
 
 
 | 1579 | 
   sfile->file = -1; | 
 
 
 
 
 
 | 1580 | 
 #endif | 
 
 
 
 
 
 | 1581 | 
  | 
 
 
 
 
 
 | 1582 | 
   if ((ret = lseek (input_fd, SEEK_SET, 0)) != 0) | 
 
 
 
 
 
 | 1583 | 
     { | 
 
 
 
 
 
 | 1584 | 
       XPR(NT "lseek failed: : %s", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1585 | 
       goto cleanup; | 
 
 
 
 
 
 | 1586 | 
     } | 
 
 
 
 
 
 | 1587 | 
  | 
 
 
 
 
 
 | 1588 | 
   if ((decomp_id = fork ()) < 0) | 
 
 
 
 
 
 | 1589 | 
     { | 
 
 
 
 
 
 | 1590 | 
       XPR(NT "fork failed: %s", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1591 | 
       goto cleanup; | 
 
 
 
 
 
 | 1592 | 
     } | 
 
 
 
 
 
 | 1593 | 
  | 
 
 
 
 
 
 | 1594 | 
   /* The child runs the decompression process: */ | 
 
 
 
 
 
 | 1595 | 
   if (decomp_id == 0) | 
 
 
 
 
 
 | 1596 | 
     { | 
 
 
 
 
 
 | 1597 | 
       /* Setup pipes: write to the output file, read from the pipe. */ | 
 
 
 
 
 
 | 1598 | 
       if (dup2 (input_fd, STDIN_FILENO) < 0 || | 
 
 
 
 
 
 | 1599 | 
           dup2 (output_fd, STDOUT_FILENO) < 0 || | 
 
 
 
 
 
 | 1600 | 
           execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, decomp->decomp_options, NULL)) | 
 
 
 
 
 
 | 1601 | 
         { | 
 
 
 
 
 
 | 1602 | 
           XPR(NT "child process %s failed to execute: %s\n", | 
 
 
 
 
 
 | 1603 | 
                    decomp->decomp_cmdname, xd3_mainerror (get_errno ())); | 
 
 
 
 
 
 | 1604 | 
         } | 
 
 
 
 
 
 | 1605 | 
  | 
 
 
 
 
 
 | 1606 | 
       _exit (127); | 
 
 
 
 
 
 | 1607 | 
     } | 
 
 
 
 
 
 | 1608 | 
  | 
 
 
 
 
 
 | 1609 | 
   close (input_fd); | 
 
 
 
 
 
 | 1610 | 
   close (output_fd); | 
 
 
 
 
 
 | 1611 | 
   input_fd  = -1; | 
 
 
 
 
 
 | 1612 | 
   output_fd = -1; | 
 
 
 
 
 
 | 1613 | 
  | 
 
 
 
 
 
 | 1614 | 
   /* Then wait for completion. */ | 
 
 
 
 
 
 | 1615 | 
   if ((ret = main_waitpid_check (decomp_id))) | 
 
 
 
 
 
 | 1616 | 
     { | 
 
 
 
 
 
 | 1617 | 
       goto cleanup; | 
 
 
 
 
 
 | 1618 | 
     } | 
 
 
 
 
 
 | 1619 | 
  | 
 
 
 
 
 
 | 1620 | 
   /* Open/stat the decompressed source file. */ | 
 
 
 
 
 
 | 1621 | 
   if ((ret = main_file_open (sfile, tmpname, XO_READ))) { goto cleanup; } | 
 
 
 
 
 
 | 1622 | 
   if ((ret = main_file_stat (sfile, & source->size, 1))) { goto cleanup; } | 
 
 
 
 
 
 | 1623 | 
   return 0; | 
 
 
 
 
 
 | 1624 | 
  | 
 
 
 
 
 
 | 1625 | 
  cleanup: | 
 
 
 
 
 
 | 1626 | 
   close (input_fd); | 
 
 
 
 
 
 | 1627 | 
   close (output_fd); | 
 
 
 
 
 
 | 1628 | 
   if (tmpname) { free (tmpname); } | 
 
 
 
 
 
 | 1629 | 
   ext_tmpfile = NULL; | 
 
 
 
 
 
 | 1630 | 
   return ret; | 
 
 
 
 
 
 | 1631 | 
 } | 
 
 
 
 
 
 | 1632 | 
  | 
 
 
 
 
 
 | 1633 | 
 /* Initiate re-compression of the output stream.  This is easier than input decompression | 
 
 
 
 
 
 | 1634 | 
  * because we know beforehand that the stream will be compressed, whereas the input has | 
 
 
 
 
 
 | 1635 | 
  * already been read when we decide it should be decompressed.  Thus, it only requires one | 
 
 
 
 
 
 | 1636 | 
  * subprocess and one pipe. */ | 
 
 
 
 
 
 | 1637 | 
 static int | 
 
 
 
 
 
 | 1638 | 
 main_recompress_output (main_file *ofile) | 
 
 
 
 
 
 | 1639 | 
 { | 
 
 
 
 
 
 | 1640 | 
   pid_t recomp_id;  /* One subproc. */ | 
 
 
 
 
 
 | 1641 | 
   int   pipefd[2];  /* One pipe. */ | 
 
 
 
 
 
 | 1642 | 
   int   output_fd = -1; | 
 
 
 
 
 
 | 1643 | 
   int   ret; | 
 
 
 
 
 
 | 1644 | 
   const main_extcomp *recomp = ofile->compressor; | 
 
 
 
 
 
 | 1645 | 
  | 
 
 
 
 
 
 | 1646 | 
   pipefd[0] = pipefd[1] = -1; | 
 
 
 
 
 
 | 1647 | 
  | 
 
 
 
 
 
 | 1648 | 
   if (pipe (pipefd)) | 
 
 
 
 
 
 | 1649 | 
     { | 
 
 
 
 
 
 | 1650 | 
       XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1651 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1652 | 
     } | 
 
 
 
 
 
 | 1653 | 
  | 
 
 
 
 
 
 | 1654 | 
   if ((recomp_id = fork ()) < 0) | 
 
 
 
 
 
 | 1655 | 
     { | 
 
 
 
 
 
 | 1656 | 
       XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1657 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1658 | 
     } | 
 
 
 
 
 
 | 1659 | 
  | 
 
 
 
 
 
 | 1660 | 
   /* The child runs the recompression process: */ | 
 
 
 
 
 
 | 1661 | 
   if (recomp_id == 0) | 
 
 
 
 
 
 | 1662 | 
     { | 
 
 
 
 
 
 | 1663 | 
       /* Setup pipes: write to the output file, read from the pipe. */ | 
 
 
 
 
 
 | 1664 | 
       if (dup2 (XFNO (ofile), STDOUT_FILENO) < 0 || | 
 
 
 
 
 
 | 1665 | 
           dup2 (pipefd[PIPE_READ_FD], STDIN_FILENO) < 0 || | 
 
 
 
 
 
 | 1666 | 
           close (pipefd[PIPE_READ_FD]) || | 
 
 
 
 
 
 | 1667 | 
           close (pipefd[PIPE_WRITE_FD]) || | 
 
 
 
 
 
 | 1668 | 
           execlp (recomp->recomp_cmdname, recomp->recomp_cmdname, recomp->recomp_options, NULL)) | 
 
 
 
 
 
 | 1669 | 
         { | 
 
 
 
 
 
 | 1670 | 
           XPR(NT "child process %s failed to execute: %s\n", recomp->recomp_cmdname, xd3_mainerror (get_errno ())); | 
 
 
 
 
 
 | 1671 | 
         } | 
 
 
 
 
 
 | 1672 | 
  | 
 
 
 
 
 
 | 1673 | 
       _exit (127); | 
 
 
 
 
 
 | 1674 | 
     } | 
 
 
 
 
 
 | 1675 | 
  | 
 
 
 
 
 
 | 1676 | 
   ext_subprocs[0] = recomp_id; | 
 
 
 
 
 
 | 1677 | 
  | 
 
 
 
 
 
 | 1678 | 
   /* The parent closes both pipes after duplicating the output-fd for writing to the | 
 
 
 
 
 
 | 1679 | 
    * compression pipe. */ | 
 
 
 
 
 
 | 1680 | 
   output_fd = dup (pipefd[PIPE_WRITE_FD]); | 
 
 
 
 
 
 | 1681 | 
  | 
 
 
 
 
 
 | 1682 | 
   if (output_fd < 0 || | 
 
 
 
 
 
 | 1683 | 
       main_file_close (ofile) || | 
 
 
 
 
 
 | 1684 | 
       close (pipefd[PIPE_READ_FD]) || | 
 
 
 
 
 
 | 1685 | 
       close (pipefd[PIPE_WRITE_FD])) | 
 
 
 
 
 
 | 1686 | 
     { | 
 
 
 
 
 
 | 1687 | 
       XPR(NT "close failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1688 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1689 | 
     } | 
 
 
 
 
 
 | 1690 | 
  | 
 
 
 
 
 
 | 1691 | 
 #if XD3_STDIO | 
 
 
 
 
 
 | 1692 | 
   /* Note: fdopen() acquires the fd, closes it when finished. */ | 
 
 
 
 
 
 | 1693 | 
   if ((ofile->file = fdopen (output_fd, "w")) == NULL) | 
 
 
 
 
 
 | 1694 | 
     { | 
 
 
 
 
 
 | 1695 | 
       XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ())); | 
 
 
 
 
 
 | 1696 | 
       goto pipe_cleanup; | 
 
 
 
 
 
 | 1697 | 
     } | 
 
 
 
 
 
 | 1698 | 
  | 
 
 
 
 
 
 | 1699 | 
 #elif XD3_POSIX | 
 
 
 
 
 
 | 1700 | 
   ofile->file = output_fd; | 
 
 
 
 
 
 | 1701 | 
 #endif | 
 
 
 
 
 
 | 1702 | 
  | 
 
 
 
 
 
 | 1703 | 
   /* Now the output file will be compressed. */ | 
 
 
 
 
 
 | 1704 | 
   return 0; | 
 
 
 
 
 
 | 1705 | 
  | 
 
 
 
 
 
 | 1706 | 
  pipe_cleanup: | 
 
 
 
 
 
 | 1707 | 
   close (output_fd); | 
 
 
 
 
 
 | 1708 | 
   close (pipefd[PIPE_READ_FD]); | 
 
 
 
 
 
 | 1709 | 
   close (pipefd[PIPE_WRITE_FD]); | 
 
 
 
 
 
 | 1710 | 
   return ret; | 
 
 
 
 
 
 | 1711 | 
 } | 
 
 
 
 
 
 | 1712 | 
 #endif /* EXTERNAL_COMPRESSION */ | 
 
 
 
 
 
 | 1713 | 
  | 
 
 
 
 
 
 | 1714 | 
 /* Identify the compressor that was used based on its ident string, which is passed in the | 
 
 
 
 
 
 | 1715 | 
  * application header. */ | 
 
 
 
 
 
 | 1716 | 
 static const main_extcomp* | 
 
 
 
 
 
 | 1717 | 
 main_ident_compressor (const char *ident) | 
 
 
 
 
 
 | 1718 | 
 { | 
 
 
 
 
 
 | 1719 | 
   int i; | 
 
 
 
 
 
 | 1720 | 
  | 
 
 
 
 
 
 | 1721 | 
   for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) | 
 
 
 
 
 
 | 1722 | 
     { | 
 
 
 
 
 
 | 1723 | 
       if (strcmp (extcomp_types[i].ident, ident) == 0) | 
 
 
 
 
 
 | 1724 | 
         { | 
 
 
 
 
 
 | 1725 | 
           return & extcomp_types[i]; | 
 
 
 
 
 
 | 1726 | 
         } | 
 
 
 
 
 
 | 1727 | 
     } | 
 
 
 
 
 
 | 1728 | 
  | 
 
 
 
 
 
 | 1729 | 
   return NULL; | 
 
 
 
 
 
 | 1730 | 
 } | 
 
 
 
 
 
 | 1731 | 
  | 
 
 
 
 
 
 | 1732 | 
 /* Return the main_extcomp record to use for this identifier, if possible. */ | 
 
 
 
 
 
 | 1733 | 
 static const main_extcomp* | 
 
 
 
 
 
 | 1734 | 
 main_get_compressor (const char *ident) | 
 
 
 
 
 
 | 1735 | 
 { | 
 
 
 
 
 
 | 1736 | 
   const main_extcomp *ext = main_ident_compressor (ident); | 
 
 
 
 
 
 | 1737 | 
  | 
 
 
 
 
 
 | 1738 | 
   if (ext == NULL) | 
 
 
 
 
 
 | 1739 | 
     { | 
 
 
 
 
 
 | 1740 | 
       if (! option_quiet) | 
 
 
 
 
 
 | 1741 | 
         { | 
 
 
 
 
 
 | 1742 | 
           XPR(NT "warning: cannot recompress output: " | 
 
 
 
 
 
 | 1743 | 
                    "unrecognized external compression ID: %s\n", ident); | 
 
 
 
 
 
 | 1744 | 
         } | 
 
 
 
 
 
 | 1745 | 
       return NULL; | 
 
 
 
 
 
 | 1746 | 
     } | 
 
 
 
 
 
 | 1747 | 
   else if (! EXTERNAL_COMPRESSION) | 
 
 
 
 
 
 | 1748 | 
     { | 
 
 
 
 
 
 | 1749 | 
       if (! option_quiet) | 
 
 
 
 
 
 | 1750 | 
         { | 
 
 
 
 
 
 | 1751 | 
           XPR(NT "warning: external support not compiled: " | 
 
 
 
 
 
 | 1752 | 
                    "original input was compressed: %s\n", ext->recomp_cmdname); | 
 
 
 
 
 
 | 1753 | 
         } | 
 
 
 
 
 
 | 1754 | 
       return NULL; | 
 
 
 
 
 
 | 1755 | 
     } | 
 
 
 
 
 
 | 1756 | 
   else | 
 
 
 
 
 
 | 1757 | 
     { | 
 
 
 
 
 
 | 1758 | 
       return ext; | 
 
 
 
 
 
 | 1759 | 
     } | 
 
 
 
 
 
 | 1760 | 
 } | 
 
 
 
 
 
 | 1761 | 
  | 
 
 
 
 
 
 | 1762 | 
 /****************************************************************************************** | 
 
 
 
 
 
 | 1763 | 
  APPLICATION HEADER | 
 
 
 
 
 
 | 1764 | 
  ******************************************************************************************/ | 
 
 
 
 
 
 | 1765 | 
  | 
 
 
 
 
 
 | 1766 | 
 #if XD3_ENCODER | 
 
 
 
 
 
 | 1767 | 
 static const char* | 
 
 
 
 
 
 | 1768 | 
 main_apphead_string (const char* x) | 
 
 
 
 
 
 | 1769 | 
 { | 
 
 
 
 
 
 | 1770 | 
   const char *y; | 
 
 
 
 
 
 | 1771 | 
  | 
 
 
 
 
 
 | 1772 | 
   if (x == NULL) { return ""; } | 
 
 
 
 
 
 | 1773 | 
  | 
 
 
 
 
 
 | 1774 | 
   if (strcmp (x, "/dev/stdin") == 0 || | 
 
 
 
 
 
 | 1775 | 
       strcmp (x, "/dev/stdout") == 0 || | 
 
 
 
 
 
 | 1776 | 
       strcmp (x, "/dev/stderr") == 0) { return "-"; } | 
 
 
 
 
 
 | 1777 | 
  | 
 
 
 
 
 
 | 1778 | 
   // TODO: this is not portable | 
 
 
 
 
 
 | 1779 | 
   return (y = strrchr (x, '/')) == NULL ? x : y + 1; | 
 
 
 
 
 
 | 1780 | 
 } | 
 
 
 
 
 
 | 1781 | 
  | 
 
 
 
 
 
 | 1782 | 
 static int | 
 
 
 
 
 
 | 1783 | 
 main_set_appheader (xd3_stream *stream, main_file *input, main_file *sfile) | 
 
 
 
 
 
 | 1784 | 
 { | 
 
 
 
 
 
 | 1785 | 
   /* The user may disable the application header.  Once the appheader is set, this | 
 
 
 
 
 
 | 1786 | 
    * disables setting it again. */ | 
 
 
 
 
 
 | 1787 | 
   if (appheader_used || ! option_use_appheader) { return 0; } | 
 
 
 
 
 
 | 1788 | 
  | 
 
 
 
 
 
 | 1789 | 
   /* The user may specify the application header, otherwise format the default header. */ | 
 
 
 
 
 
 | 1790 | 
   if (option_appheader) | 
 
 
 
 
 
 | 1791 | 
     { | 
 
 
 
 
 
 | 1792 | 
       appheader_used = option_appheader; | 
 
 
 
 
 
 | 1793 | 
     } | 
 
 
 
 
 
 | 1794 | 
   else | 
 
 
 
 
 
 | 1795 | 
     { | 
 
 
 
 
 
 | 1796 | 
       const char *iname; | 
 
 
 
 
 
 | 1797 | 
       const char *icomp; | 
 
 
 
 
 
 | 1798 | 
       const char *sname; | 
 
 
 
 
 
 | 1799 | 
       const char *scomp; | 
 
 
 
 
 
 | 1800 | 
       int len; | 
 
 
 
 
 
 | 1801 | 
  | 
 
 
 
 
 
 | 1802 | 
       iname = main_apphead_string (input->filename); | 
 
 
 
 
 
 | 1803 | 
       icomp = (input->compressor == NULL) ? "" : input->compressor->ident; | 
 
 
 
 
 
 | 1804 | 
       len = strlen (iname) + strlen (icomp) + 2; | 
 
 
 
 
 
 | 1805 | 
  | 
 
 
 
 
 
 | 1806 | 
       if (sfile->filename != NULL) | 
 
 
 
 
 
 | 1807 | 
         { | 
 
 
 
 
 
 | 1808 | 
           sname = main_apphead_string (sfile->filename); | 
 
 
 
 
 
 | 1809 | 
           scomp = (sfile->compressor == NULL) ? "" : sfile->compressor->ident; | 
 
 
 
 
 
 | 1810 | 
           len += strlen (sname) + strlen (scomp) + 2; | 
 
 
 
 
 
 | 1811 | 
         } | 
 
 
 
 
 
 | 1812 | 
       else | 
 
 
 
 
 
 | 1813 | 
         { | 
 
 
 
 
 
 | 1814 | 
           sname = scomp = ""; | 
 
 
 
 
 
 | 1815 | 
         } | 
 
 
 
 
 
 | 1816 | 
  | 
 
 
 
 
 
 | 1817 | 
       if ((appheader_used = main_malloc (len)) == NULL) | 
 
 
 
 
 
 | 1818 | 
         { | 
 
 
 
 
 
 | 1819 | 
           return ENOMEM; | 
 
 
 
 
 
 | 1820 | 
         } | 
 
 
 
 
 
 | 1821 | 
  | 
 
 
 
 
 
 | 1822 | 
       if (sfile->filename == NULL) | 
 
 
 
 
 
 | 1823 | 
         { | 
 
 
 
 
 
 | 1824 | 
           sprintf ((char*)appheader_used, "%s/%s", iname, icomp); | 
 
 
 
 
 
 | 1825 | 
         } | 
 
 
 
 
 
 | 1826 | 
       else | 
 
 
 
 
 
 | 1827 | 
         { | 
 
 
 
 
 
 | 1828 | 
           sprintf ((char*)appheader_used, "%s/%s/%s/%s", iname, icomp, sname, scomp); | 
 
 
 
 
 
 | 1829 | 
         } | 
 
 
 
 
 
 | 1830 | 
     } | 
 
 
 
 
 
 | 1831 | 
  | 
 
 
 
 
 
 | 1832 | 
   xd3_set_appheader (stream, appheader_used, strlen ((char*)appheader_used)); | 
 
 
 
 
 
 | 1833 | 
  | 
 
 
 
 
 
 | 1834 | 
   return 0; | 
 
 
 
 
 
 | 1835 | 
 } | 
 
 
 
 
 
 | 1836 | 
 #endif | 
 
 
 
 
 
 | 1837 | 
  | 
 
 
 
 
 
 | 1838 | 
 static void | 
 
 
 
 
 
 | 1839 | 
 main_get_appheader_params (main_file *file, char **parsed, int output, const char *type, | 
 
 
 
 
 
 | 1840 | 
                            main_file *other) | 
 
 
 
 
 
 | 1841 | 
 { | 
 
 
 
 
 
 | 1842 | 
   /* Set the filename if it was not specified.  If output, option_stdout (-c) overrides. */ | 
 
 
 
 
 
 | 1843 | 
   if (file->filename == NULL && ! (output && option_stdout) && strcmp (parsed[0], "-") != 0) | 
 
 
 
 
 
 | 1844 | 
     { | 
 
 
 
 
 
 | 1845 | 
       file->filename = parsed[0]; | 
 
 
 
 
 
 | 1846 | 
  | 
 
 
 
 
 
 | 1847 | 
       if (other->filename != NULL) { | 
 
 
 
 
 
 | 1848 | 
         /* Take directory from the other file, if it has one. */ | 
 
 
 
 
 
 | 1849 | 
         /* TODO: This results in nonsense names like /dev/foo.tar.gz | 
 
 
 
 
 
 | 1850 | 
          * and probably the filename-default logic interferes with | 
 
 
 
 
 
 | 1851 | 
          * multi-file operation and the standard file extension? | 
 
 
 
 
 
 | 1852 | 
          * Possibly the name header is bad, should be off by default. | 
 
 
 
 
 
 | 1853 | 
          * Possibly we just want to remember external/compression | 
 
 
 
 
 
 | 1854 | 
          * settings. */ | 
 
 
 
 
 
 | 1855 | 
         char *last_slash = strrchr(other->filename, '/'); | 
 
 
 
 
 
 | 1856 | 
  | 
 
 
 
 
 
 | 1857 | 
         if (last_slash != NULL) { | 
 
 
 
 
 
 | 1858 | 
           int dlen = last_slash - other->filename; | 
 
 
 
 
 
 | 1859 | 
  | 
 
 
 
 
 
 | 1860 | 
           XD3_ASSERT(file->filename_copy == NULL); | 
 
 
 
 
 
 | 1861 | 
           file->filename_copy = main_malloc(dlen + 2 + strlen(file->filename)); | 
 
 
 
 
 
 | 1862 | 
  | 
 
 
 
 
 
 | 1863 | 
           strncpy(file->filename_copy, other->filename, dlen); | 
 
 
 
 
 
 | 1864 | 
           file->filename_copy[dlen] = '/'; | 
 
 
 
 
 
 | 1865 | 
           strcpy(file->filename_copy + dlen + 1, parsed[0]); | 
 
 
 
 
 
 | 1866 | 
  | 
 
 
 
 
 
 | 1867 | 
           file->filename = file->filename_copy; | 
 
 
 
 
 
 | 1868 | 
         } | 
 
 
 
 
 
 | 1869 | 
       } | 
 
 
 
 
 
 | 1870 | 
  | 
 
 
 
 
 
 | 1871 | 
       if (! option_quiet) | 
 
 
 
 
 
 | 1872 | 
         { | 
 
 
 
 
 
 | 1873 | 
           XPR(NT "using default %s filename: %s\n", type, file->filename); | 
 
 
 
 
 
 | 1874 | 
         } | 
 
 
 
 
 
 | 1875 | 
     } | 
 
 
 
 
 
 | 1876 | 
  | 
 
 
 
 
 
 | 1877 | 
   /* Set the compressor, initiate de/recompression later. */ | 
 
 
 
 
 
 | 1878 | 
   if (file->compressor == NULL && *parsed[1] != 0) | 
 
 
 
 
 
 | 1879 | 
     { | 
 
 
 
 
 
 | 1880 | 
       file->compressor = main_get_compressor (parsed[1]); | 
 
 
 
 
 
 | 1881 | 
     } | 
 
 
 
 
 
 | 1882 | 
 } | 
 
 
 
 
 
 | 1883 | 
  | 
 
 
 
 
 
 | 1884 | 
 static void | 
 
 
 
 
 
 | 1885 | 
 main_get_appheader (xd3_stream *stream, main_file *ifile, main_file *output, main_file *sfile) | 
 
 
 
 
 
 | 1886 | 
 { | 
 
 
 
 
 
 | 1887 | 
   uint8_t *apphead; | 
 
 
 
 
 
 | 1888 | 
   usize_t appheadsz; | 
 
 
 
 
 
 | 1889 | 
   int ret; | 
 
 
 
 
 
 | 1890 | 
  | 
 
 
 
 
 
 | 1891 | 
   /* The user may disable the application header.  Once the appheader is set, this | 
 
 
 
 
 
 | 1892 | 
    * disables setting it again. */ | 
 
 
 
 
 
 | 1893 | 
   if (! option_use_appheader) { return; } | 
 
 
 
 
 
 | 1894 | 
  | 
 
 
 
 
 
 | 1895 | 
   ret = xd3_get_appheader (stream, & apphead, & appheadsz); | 
 
 
 
 
 
 | 1896 | 
  | 
 
 
 
 
 
 | 1897 | 
   /* Ignore failure, it only means we haven't received a header yet. */ | 
 
 
 
 
 
 | 1898 | 
   if (ret != 0) { return; } | 
 
 
 
 
 
 | 1899 | 
  | 
 
 
 
 
 
 | 1900 | 
   if (appheadsz > 0) | 
 
 
 
 
 
 | 1901 | 
     { | 
 
 
 
 
 
 | 1902 | 
       char *start = (char*)apphead; | 
 
 
 
 
 
 | 1903 | 
       char *slash; | 
 
 
 
 
 
 | 1904 | 
       int   place = 0; | 
 
 
 
 
 
 | 1905 | 
       char *parsed[4]; | 
 
 
 
 
 
 | 1906 | 
  | 
 
 
 
 
 
 | 1907 | 
       memset (parsed, 0, sizeof (parsed)); | 
 
 
 
 
 
 | 1908 | 
  | 
 
 
 
 
 
 | 1909 | 
       while ((slash = strchr (start, '/')) != NULL) | 
 
 
 
 
 
 | 1910 | 
         { | 
 
 
 
 
 
 | 1911 | 
           *slash = 0; | 
 
 
 
 
 
 | 1912 | 
           parsed[place++] = start; | 
 
 
 
 
 
 | 1913 | 
           start = slash + 1; | 
 
 
 
 
 
 | 1914 | 
         } | 
 
 
 
 
 
 | 1915 | 
  | 
 
 
 
 
 
 | 1916 | 
       parsed[place++] = start; | 
 
 
 
 
 
 | 1917 | 
  | 
 
 
 
 
 
 | 1918 | 
       /* First take the output parameters. */ | 
 
 
 
 
 
 | 1919 | 
       if (place == 2 || place == 4) | 
 
 
 
 
 
 | 1920 | 
         { | 
 
 
 
 
 
 | 1921 | 
           main_get_appheader_params (output, parsed, 1, "output", ifile); | 
 
 
 
 
 
 | 1922 | 
         } | 
 
 
 
 
 
 | 1923 | 
  | 
 
 
 
 
 
 | 1924 | 
       /* Then take the source parameters. */ | 
 
 
 
 
 
 | 1925 | 
       if (place == 4) | 
 
 
 
 
 
 | 1926 | 
         { | 
 
 
 
 
 
 | 1927 | 
           main_get_appheader_params (sfile, parsed+2, 0, "source", ifile); | 
 
 
 
 
 
 | 1928 | 
         } | 
 
 
 
 
 
 | 1929 | 
     } | 
 
 
 
 
 
 | 1930 | 
  | 
 
 
 
 
 
 | 1931 | 
   option_use_appheader = 0; | 
 
 
 
 
 
 | 1932 | 
   return; | 
 
 
 
 
 
 | 1933 | 
 } | 
 
 
 
 
 
 | 1934 | 
  | 
 
 
 
 
 
 | 1935 | 
 /****************************************************************************************** | 
 
 
 
 
 
 | 1936 | 
  Main I/O routines | 
 
 
 
 
 
 | 1937 | 
  ******************************************************************************************/ | 
 
 
 
 
 
 | 1938 | 
  | 
 
 
 
 
 
 | 1939 | 
 /* This function acts like the above except it may also try to recognize a compressed | 
 
 
 
 
 
 | 1940 | 
  * input when the first buffer of data is read.  The EXTERNAL_COMPRESSION code is called | 
 
 
 
 
 
 | 1941 | 
  * to search for magic numbers. */ | 
 
 
 
 
 
 | 1942 | 
 static int | 
 
 
 
 
 
 | 1943 | 
 main_read_primary_input (main_file   *ifile, | 
 
 
 
 
 
 | 1944 | 
                          uint8_t    *buf, | 
 
 
 
 
 
 | 1945 | 
                          usize_t      size, | 
 
 
 
 
 
 | 1946 | 
                          usize_t     *nread) | 
 
 
 
 
 
 | 1947 | 
 { | 
 
 
 
 
 
 | 1948 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 1949 | 
   if (option_decompress_inputs && ifile->flags & RD_FIRST) | 
 
 
 
 
 
 | 1950 | 
     { | 
 
 
 
 
 
 | 1951 | 
       ifile->flags &= ~RD_FIRST; | 
 
 
 
 
 
 | 1952 | 
  | 
 
 
 
 
 
 | 1953 | 
       return main_decompress_input_check (ifile, buf, size, nread); | 
 
 
 
 
 
 | 1954 | 
     } | 
 
 
 
 
 
 | 1955 | 
 #endif | 
 
 
 
 
 
 | 1956 | 
  | 
 
 
 
 
 
 | 1957 | 
   return main_file_read (ifile, buf, size, nread, "input read failed"); | 
 
 
 
 
 
 | 1958 | 
 } | 
 
 
 
 
 
 | 1959 | 
  | 
 
 
 
 
 
 | 1960 | 
 /* This function simply writes the stream output buffer, if there is any.  This is used | 
 
 
 
 
 
 | 1961 | 
  * for both encode and decode commands.  (The VCDIFF tools use main_print_func()). */ | 
 
 
 
 
 
 | 1962 | 
 static int | 
 
 
 
 
 
 | 1963 | 
 main_write_output (xd3_stream* stream, main_file *ofile) | 
 
 
 
 
 
 | 1964 | 
 { | 
 
 
 
 
 
 | 1965 | 
   int ret; | 
 
 
 
 
 
 | 1966 | 
  | 
 
 
 
 
 
 | 1967 | 
   if (stream->avail_out > 0 && (ret = main_file_write (ofile, stream->next_out, stream->avail_out, "write failed"))) | 
 
 
 
 
 
 | 1968 | 
     { | 
 
 
 
 
 
 | 1969 | 
       return ret; | 
 
 
 
 
 
 | 1970 | 
     } | 
 
 
 
 
 
 | 1971 | 
  | 
 
 
 
 
 
 | 1972 | 
   return 0; | 
 
 
 
 
 
 | 1973 | 
 } | 
 
 
 
 
 
 | 1974 | 
  | 
 
 
 
 
 
 | 1975 | 
 /* Open the main output file, sets a default file name, initiate recompression.  This | 
 
 
 
 
 
 | 1976 | 
  * function is expected to fprint any error messages. */ | 
 
 
 
 
 
 | 1977 | 
 static int | 
 
 
 
 
 
 | 1978 | 
 main_open_output (xd3_stream *stream, main_file *ofile) | 
 
 
 
 
 
 | 1979 | 
 { | 
 
 
 
 
 
 | 1980 | 
   int ret; | 
 
 
 
 
 
 | 1981 | 
  | 
 
 
 
 
 
 | 1982 | 
   if (ofile->filename == NULL) | 
 
 
 
 
 
 | 1983 | 
     { | 
 
 
 
 
 
 | 1984 | 
       XSTDOUT_XF (ofile); | 
 
 
 
 
 
 | 1985 | 
  | 
 
 
 
 
 
 | 1986 | 
       if (option_verbose > 1) { XPR(NT "using standard output: %s\n", ofile->filename); } | 
 
 
 
 
 
 | 1987 | 
     } | 
 
 
 
 
 
 | 1988 | 
   else | 
 
 
 
 
 
 | 1989 | 
     { | 
 
 
 
 
 
 | 1990 | 
       /* Stat the file to check for overwrite. */ | 
 
 
 
 
 
 | 1991 | 
       if (option_force == 0 && main_file_exists (ofile)) | 
 
 
 
 
 
 | 1992 | 
         { | 
 
 
 
 
 
 | 1993 | 
           XPR(NT "to overwrite output file specify -f: %s\n", ofile->filename); | 
 
 
 
 
 
 | 1994 | 
           return EEXIST; | 
 
 
 
 
 
 | 1995 | 
         } | 
 
 
 
 
 
 | 1996 | 
  | 
 
 
 
 
 
 | 1997 | 
       if ((ret = main_file_open (ofile, ofile->filename, XO_WRITE))) | 
 
 
 
 
 
 | 1998 | 
         { | 
 
 
 
 
 
 | 1999 | 
           return ret; | 
 
 
 
 
 
 | 2000 | 
         } | 
 
 
 
 
 
 | 2001 | 
  | 
 
 
 
 
 
 | 2002 | 
       if (option_verbose > 1) { XPR(NT "output file: %s\n", ofile->filename); } | 
 
 
 
 
 
 | 2003 | 
     } | 
 
 
 
 
 
 | 2004 | 
  | 
 
 
 
 
 
 | 2005 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 2006 | 
   /* Do output recompression. */ | 
 
 
 
 
 
 | 2007 | 
   if (ofile->compressor != NULL && option_recompress_outputs == 1) | 
 
 
 
 
 
 | 2008 | 
     { | 
 
 
 
 
 
 | 2009 | 
       if (! option_quiet) | 
 
 
 
 
 
 | 2010 | 
         { | 
 
 
 
 
 
 | 2011 | 
           XPR(NT "%s %s | %s\n", | 
 
 
 
 
 
 | 2012 | 
              ofile->compressor->recomp_cmdname, | 
 
 
 
 
 
 | 2013 | 
              ofile->compressor->recomp_options, | 
 
 
 
 
 
 | 2014 | 
              ofile->filename); | 
 
 
 
 
 
 | 2015 | 
         } | 
 
 
 
 
 
 | 2016 | 
  | 
 
 
 
 
 
 | 2017 | 
       if ((ret = main_recompress_output (ofile))) | 
 
 
 
 
 
 | 2018 | 
         { | 
 
 
 
 
 
 | 2019 | 
           return ret; | 
 
 
 
 
 
 | 2020 | 
         } | 
 
 
 
 
 
 | 2021 | 
     } | 
 
 
 
 
 
 | 2022 | 
 #endif | 
 
 
 
 
 
 | 2023 | 
  | 
 
 
 
 
 
 | 2024 | 
   return 0; | 
 
 
 
 
 
 | 2025 | 
 } | 
 
 
 
 
 
 | 2026 | 
  | 
 
 
 
 
 
 | 2027 | 
 /* This is called at different times for encoding and decoding.  The encoder calls it | 
 
 
 
 
 
 | 2028 | 
  * immediately, the decoder delays until the application header is received. | 
 
 
 
 
 
 | 2029 | 
  * Stream may be NULL, in which case xd3_set_source is not called. */ | 
 
 
 
 
 
 | 2030 | 
 static int | 
 
 
 
 
 
 | 2031 | 
 main_set_source (xd3_stream *stream, int cmd, main_file *sfile, xd3_source *source) | 
 
 
 
 
 
 | 2032 | 
 { | 
 
 
 
 
 
 | 2033 | 
   int ret = 0, i; | 
 
 
 
 
 
 | 2034 | 
   uint8_t *tmp_buf = NULL; | 
 
 
 
 
 
 | 2035 | 
  | 
 
 
 
 
 
 | 2036 | 
   /* Open it, check for seekability, set required xd3_source fields. */ | 
 
 
 
 
 
 | 2037 | 
   if (allow_fake_source) | 
 
 
 
 
 
 | 2038 | 
     { | 
 
 
 
 
 
 | 2039 | 
       sfile->mode = XO_READ; | 
 
 
 
 
 
 | 2040 | 
       sfile->realname = sfile->filename; | 
 
 
 
 
 
 | 2041 | 
       sfile->nread = 0; | 
 
 
 
 
 
 | 2042 | 
       source->size = UINT64_MAX; | 
 
 
 
 
 
 | 2043 | 
     } | 
 
 
 
 
 
 | 2044 | 
   else | 
 
 
 
 
 
 | 2045 | 
     { | 
 
 
 
 
 
 | 2046 | 
       if ((ret = main_file_open (sfile, sfile->filename, XO_READ)) || | 
 
 
 
 
 
 | 2047 | 
           (ret = main_file_stat (sfile, & source->size, 1))) | 
 
 
 
 
 
 | 2048 | 
         { | 
 
 
 
 
 
 | 2049 | 
           goto error; | 
 
 
 
 
 
 | 2050 | 
         } | 
 
 
 
 
 
 | 2051 | 
     } | 
 
 
 
 
 
 | 2052 | 
  | 
 
 
 
 
 
 | 2053 | 
   source->name     = sfile->filename; | 
 
 
 
 
 
 | 2054 | 
   source->ioh      = sfile; | 
 
 
 
 
 
 | 2055 | 
   source->curblkno = (xoff_t) -1; | 
 
 
 
 
 
 | 2056 | 
   source->curblk   = NULL; | 
 
 
 
 
 
 | 2057 | 
    | 
 
 
 
 
 
 | 2058 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 2059 | 
   if (option_decompress_inputs) | 
 
 
 
 
 
 | 2060 | 
     { | 
 
 
 
 
 
 | 2061 | 
       /* If encoding, read the header to check for decompression. */ | 
 
 
 
 
 
 | 2062 | 
       if (IS_ENCODE (cmd)) | 
 
 
 
 
 
 | 2063 | 
         { | 
 
 
 
 
 
 | 2064 | 
           usize_t nread; | 
 
 
 
 
 
 | 2065 | 
           tmp_buf = main_malloc(XD3_ALLOCSIZE); | 
 
 
 
 
 
 | 2066 | 
  | 
 
 
 
 
 
 | 2067 | 
           if ((ret = main_file_read (sfile, tmp_buf, XD3_ALLOCSIZE, | 
 
 
 
 
 
 | 2068 | 
                                      & nread, "source read failed"))) | 
 
 
 
 
 
 | 2069 | 
             { | 
 
 
 
 
 
 | 2070 | 
               goto error; | 
 
 
 
 
 
 | 2071 | 
             } | 
 
 
 
 
 
 | 2072 | 
  | 
 
 
 
 
 
 | 2073 | 
           /* Check known magic numbers. */ | 
 
 
 
 
 
 | 2074 | 
           for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1) | 
 
 
 
 
 
 | 2075 | 
             { | 
 
 
 
 
 
 | 2076 | 
               const main_extcomp *decomp = & extcomp_types[i]; | 
 
 
 
 
 
 | 2077 | 
  | 
 
 
 
 
 
 | 2078 | 
               if ((nread > decomp->magic_size) && | 
 
 
 
 
 
 | 2079 | 
                   memcmp (tmp_buf, decomp->magic, decomp->magic_size) == 0) | 
 
 
 
 
 
 | 2080 | 
                 { | 
 
 
 
 
 
 | 2081 | 
                   sfile->compressor = decomp; | 
 
 
 
 
 
 | 2082 | 
                   break; | 
 
 
 
 
 
 | 2083 | 
                 } | 
 
 
 
 
 
 | 2084 | 
             } | 
 
 
 
 
 
 | 2085 | 
  | 
 
 
 
 
 
 | 2086 | 
           if (sfile->compressor == NULL) | 
 
 
 
 
 
 | 2087 | 
             { | 
 
 
 
 
 
 | 2088 | 
               if (option_verbose > 2) | 
 
 
 
 
 
 | 2089 | 
                 { | 
 
 
 
 
 
 | 2090 | 
                   XPR(NT "source block 0 read (not compressed)\n"); | 
 
 
 
 
 
 | 2091 | 
                 } | 
 
 
 
 
 
 | 2092 | 
             } | 
 
 
 
 
 
 | 2093 | 
         } | 
 
 
 
 
 
 | 2094 | 
  | 
 
 
 
 
 
 | 2095 | 
       /* In either the encoder or decoder, start decompression. */ | 
 
 
 
 
 
 | 2096 | 
       if (sfile->compressor) | 
 
 
 
 
 
 | 2097 | 
         { | 
 
 
 
 
 
 | 2098 | 
           xoff_t osize = source->size; | 
 
 
 
 
 
 | 2099 | 
  | 
 
 
 
 
 
 | 2100 | 
           if (osize > XD3_NODECOMPRESSSIZE) | 
 
 
 
 
 
 | 2101 | 
             { | 
 
 
 
 
 
 | 2102 | 
               XPR(NT "source file too large for external decompression: %s: %"Q"u\n", | 
 
 
 
 
 
 | 2103 | 
                        sfile->filename, osize); | 
 
 
 
 
 
 | 2104 | 
               ret = XD3_INTERNAL; | 
 
 
 
 
 
 | 2105 | 
               goto error; | 
 
 
 
 
 
 | 2106 | 
             } | 
 
 
 
 
 
 | 2107 | 
  | 
 
 
 
 
 
 | 2108 | 
           if ((ret = main_decompress_source (sfile, source))) | 
 
 
 
 
 
 | 2109 | 
             { | 
 
 
 
 
 
 | 2110 | 
               goto error; | 
 
 
 
 
 
 | 2111 | 
             } | 
 
 
 
 
 
 | 2112 | 
  | 
 
 
 
 
 
 | 2113 | 
           if (! option_quiet) | 
 
 
 
 
 
 | 2114 | 
             { | 
 
 
 
 
 
 | 2115 | 
               char s1[32], s2[32]; | 
 
 
 
 
 
 | 2116 | 
               XPR(NT "%s | %s %s => %s %.1f%% [ %s , %s ]\n", | 
 
 
 
 
 
 | 2117 | 
                  sfile->filename, | 
 
 
 
 
 
 | 2118 | 
                  sfile->compressor->decomp_cmdname, | 
 
 
 
 
 
 | 2119 | 
                  sfile->compressor->decomp_options, | 
 
 
 
 
 
 | 2120 | 
                  sfile->realname, | 
 
 
 
 
 
 | 2121 | 
                  100.0 * source->size / osize, | 
 
 
 
 
 
 | 2122 | 
                  main_format_bcnt (osize, s1), | 
 
 
 
 
 
 | 2123 | 
                  main_format_bcnt (source->size, s2)); | 
 
 
 
 
 
 | 2124 | 
             } | 
 
 
 
 
 
 | 2125 | 
         } | 
 
 
 
 
 
 | 2126 | 
     } | 
 
 
 
 
 
 | 2127 | 
 #endif | 
 
 
 
 
 
 | 2128 | 
  | 
 
 
 
 
 
 | 2129 | 
   /* At this point we know source->size. | 
 
 
 
 
 
 | 2130 | 
    * Source buffer, blksize, LRU init. */ | 
 
 
 
 
 
 | 2131 | 
   if (source->size < option_srcwinsz) | 
 
 
 
 
 
 | 2132 | 
     { | 
 
 
 
 
 
 | 2133 | 
       /* Reduce sizes to actual source size, read whole file */ | 
 
 
 
 
 
 | 2134 | 
       option_srcwinsz = source->size; | 
 
 
 
 
 
 | 2135 | 
       source->blksize = source->size; | 
 
 
 
 
 
 | 2136 | 
       lru_size = 1; | 
 
 
 
 
 
 | 2137 | 
     } | 
 
 
 
 
 
 | 2138 | 
   else | 
 
 
 
 
 
 | 2139 | 
     { | 
 
 
 
 
 
 | 2140 | 
       option_srcwinsz = max(option_srcwinsz, XD3_MINSRCWINSZ); | 
 
 
 
 
 
 | 2141 | 
  | 
 
 
 
 
 
 | 2142 | 
       source->blksize = (option_srcwinsz / LRU_SIZE); | 
 
 
 
 
 
 | 2143 | 
       lru_size = LRU_SIZE; | 
 
 
 
 
 
 | 2144 | 
     } | 
 
 
 
 
 
 | 2145 | 
  | 
 
 
 
 
 
 | 2146 | 
   main_blklru_list_init (& lru_list); | 
 
 
 
 
 
 | 2147 | 
   main_blklru_list_init (& lru_free); | 
 
 
 
 
 
 | 2148 | 
  | 
 
 
 
 
 
 | 2149 | 
   if (option_verbose) | 
 
 
 
 
 
 | 2150 | 
     { | 
 
 
 
 
 
 | 2151 | 
       static char buf[32]; | 
 
 
 
 
 
 | 2152 | 
        | 
 
 
 
 
 
 | 2153 | 
       XPR(NT "source %s winsize %s size %"Q"u\n", | 
 
 
 
 
 
 | 2154 | 
           sfile->filename, main_format_bcnt(option_srcwinsz, buf), source->size); | 
 
 
 
 
 
 | 2155 | 
     } | 
 
 
 
 
 
 | 2156 | 
  | 
 
 
 
 
 
 | 2157 | 
   if (option_verbose > 1) | 
 
 
 
 
 
 | 2158 | 
     { | 
 
 
 
 
 
 | 2159 | 
       XPR(NT "source block size: %u\n", source->blksize); | 
 
 
 
 
 
 | 2160 | 
     } | 
 
 
 
 
 
 | 2161 | 
  | 
 
 
 
 
 
 | 2162 | 
   if ((lru = main_malloc (sizeof (main_blklru) * lru_size)) == NULL) | 
 
 
 
 
 
 | 2163 | 
     { | 
 
 
 
 
 
 | 2164 | 
       ret = ENOMEM; | 
 
 
 
 
 
 | 2165 | 
       goto error; | 
 
 
 
 
 
 | 2166 | 
     } | 
 
 
 
 
 
 | 2167 | 
  | 
 
 
 
 
 
 | 2168 | 
   for (i = 0; i < lru_size; i += 1) | 
 
 
 
 
 
 | 2169 | 
     { | 
 
 
 
 
 
 | 2170 | 
       lru[i].blkno = (xoff_t) -1; | 
 
 
 
 
 
 | 2171 | 
  | 
 
 
 
 
 
 | 2172 | 
       if ((lru[i].blk = main_malloc (source->blksize)) == NULL) | 
 
 
 
 
 
 | 2173 | 
         { | 
 
 
 
 
 
 | 2174 | 
           ret = ENOMEM; | 
 
 
 
 
 
 | 2175 | 
           goto error; | 
 
 
 
 
 
 | 2176 | 
         } | 
 
 
 
 
 
 | 2177 | 
  | 
 
 
 
 
 
 | 2178 | 
       main_blklru_list_push_back (& lru_free, & lru[i]); | 
 
 
 
 
 
 | 2179 | 
     } | 
 
 
 
 
 
 | 2180 | 
  | 
 
 
 
 
 
 | 2181 | 
   if (stream && (ret = xd3_set_source (stream, source))) | 
 
 
 
 
 
 | 2182 | 
     { | 
 
 
 
 
 
 | 2183 | 
       XPR(NT XD3_LIB_ERRMSG (stream, ret)); | 
 
 
 
 
 
 | 2184 | 
       goto error; | 
 
 
 
 
 
 | 2185 | 
     } | 
 
 
 
 
 
 | 2186 | 
  | 
 
 
 
 
 
 | 2187 | 
  error: | 
 
 
 
 
 
 | 2188 | 
   if (tmp_buf != NULL) | 
 
 
 
 
 
 | 2189 | 
     { | 
 
 
 
 
 
 | 2190 | 
       main_free (tmp_buf); | 
 
 
 
 
 
 | 2191 | 
     } | 
 
 
 
 
 
 | 2192 | 
  | 
 
 
 
 
 
 | 2193 | 
   return ret; | 
 
 
 
 
 
 | 2194 | 
 } | 
 
 
 
 
 
 | 2195 | 
  | 
 
 
 
 
 
 | 2196 | 
 static void | 
 
 
 
 
 
 | 2197 | 
 main_set_winsize (main_file *ifile) { | 
 
 
 
 
 
 | 2198 | 
   xoff_t file_size; | 
 
 
 
 
 
 | 2199 | 
  | 
 
 
 
 
 
 | 2200 | 
   if (main_file_stat (ifile, &file_size, 0) == 0) | 
 
 
 
 
 
 | 2201 | 
     { | 
 
 
 
 
 
 | 2202 | 
       option_winsize = (usize_t) min(file_size, (xoff_t) option_winsize); | 
 
 
 
 
 
 | 2203 | 
     } | 
 
 
 
 
 
 | 2204 | 
  | 
 
 
 
 
 
 | 2205 | 
   option_winsize = max(option_winsize, XD3_ALLOCSIZE); | 
 
 
 
 
 
 | 2206 | 
  | 
 
 
 
 
 
 | 2207 | 
   if (option_verbose > 1) | 
 
 
 
 
 
 | 2208 | 
     { | 
 
 
 
 
 
 | 2209 | 
       XPR(NT "input window size: %u\n", option_winsize); | 
 
 
 
 
 
 | 2210 | 
     } | 
 
 
 
 
 
 | 2211 | 
 } | 
 
 
 
 
 
 | 2212 | 
  | 
 
 
 
 
 
 | 2213 | 
 /****************************************************************************************** | 
 
 
 
 
 
 | 2214 | 
  Source routines | 
 
 
 
 
 
 | 2215 | 
  ******************************************************************************************/ | 
 
 
 
 
 
 | 2216 | 
  | 
 
 
 
 
 
 | 2217 | 
 /* This is the callback for reading a block of source.  This function is blocking and it | 
 
 
 
 
 
 | 2218 | 
  * implements a small LRU. | 
 
 
 
 
 
 | 2219 | 
  * | 
 
 
 
 
 
 | 2220 | 
  * Note that it is possible for main_input() to handle getblk requests in a non-blocking | 
 
 
 
 
 
 | 2221 | 
  * manner.  If the callback is NULL then the caller of xd3_*_input() must handle the | 
 
 
 
 
 
 | 2222 | 
  * XD3_GETSRCBLK return value and fill the source in the same way.  See xd3_getblk for | 
 
 
 
 
 
 | 2223 | 
  * details.  To see an example of non-blocking getblk, see xdelta-test.h. */ | 
 
 
 
 
 
 | 2224 | 
 static int | 
 
 
 
 
 
 | 2225 | 
 main_getblk_func (xd3_stream *stream, | 
 
 
 
 
 
 | 2226 | 
                   xd3_source *source, | 
 
 
 
 
 
 | 2227 | 
                   xoff_t      blkno) | 
 
 
 
 
 
 | 2228 | 
 { | 
 
 
 
 
 
 | 2229 | 
   xoff_t      pos   = blkno * source->blksize; | 
 
 
 
 
 
 | 2230 | 
   main_file   *sfile = (main_file*) source->ioh; | 
 
 
 
 
 
 | 2231 | 
   main_blklru *blru  = NULL; | 
 
 
 
 
 
 | 2232 | 
   usize_t      onblk = xd3_bytes_on_srcblk (source, blkno); | 
 
 
 
 
 
 | 2233 | 
   usize_t      nread; | 
 
 
 
 
 
 | 2234 | 
   int         ret; | 
 
 
 
 
 
 | 2235 | 
   int         i; | 
 
 
 
 
 
 | 2236 | 
  | 
 
 
 
 
 
 | 2237 | 
   if (allow_fake_source) | 
 
 
 
 
 
 | 2238 | 
     { | 
 
 
 
 
 
 | 2239 | 
       source->curblkno = blkno; | 
 
 
 
 
 
 | 2240 | 
       source->onblk    = onblk; | 
 
 
 
 
 
 | 2241 | 
       source->curblk   = lru[0].blk; | 
 
 
 
 
 
 | 2242 | 
       return 0; | 
 
 
 
 
 
 | 2243 | 
     } | 
 
 
 
 
 
 | 2244 | 
  | 
 
 
 
 
 
 | 2245 | 
   if (do_not_lru) | 
 
 
 
 
 
 | 2246 | 
     { | 
 
 
 
 
 
 | 2247 | 
       /* Direct lookup assumes sequential scan w/o skipping blocks. */ | 
 
 
 
 
 
 | 2248 | 
       int idx = blkno % lru_size; | 
 
 
 
 
 
 | 2249 | 
       if (lru[idx].blkno == blkno) | 
 
 
 
 
 
 | 2250 | 
         { | 
 
 
 
 
 
 | 2251 | 
           source->curblkno = blkno; | 
 
 
 
 
 
 | 2252 | 
           source->onblk    = onblk; | 
 
 
 
 
 
 | 2253 | 
           source->curblk   = lru[idx].blk; | 
 
 
 
 
 
 | 2254 | 
           lru_hits += 1; | 
 
 
 
 
 
 | 2255 | 
           return 0; | 
 
 
 
 
 
 | 2256 | 
         } | 
 
 
 
 
 
 | 2257 | 
  | 
 
 
 
 
 
 | 2258 | 
       if (lru[idx].blkno != -1LL && | 
 
 
 
 
 
 | 2259 | 
           lru[idx].blkno != blkno - lru_size) | 
 
 
 
 
 
 | 2260 | 
         { | 
 
 
 
 
 
 | 2261 | 
           return XD3_TOOFARBACK; | 
 
 
 
 
 
 | 2262 | 
         } | 
 
 
 
 
 
 | 2263 | 
     } | 
 
 
 
 
 
 | 2264 | 
   else | 
 
 
 
 
 
 | 2265 | 
     { | 
 
 
 
 
 
 | 2266 | 
       /* Sequential search through LRU. */ | 
 
 
 
 
 
 | 2267 | 
       for (i = 0; i < lru_size; i += 1) | 
 
 
 
 
 
 | 2268 | 
         { | 
 
 
 
 
 
 | 2269 | 
           if (lru[i].blkno == blkno) | 
 
 
 
 
 
 | 2270 | 
             { | 
 
 
 
 
 
 | 2271 | 
               main_blklru_list_remove (& lru[i]); | 
 
 
 
 
 
 | 2272 | 
               main_blklru_list_push_back (& lru_list, & lru[i]); | 
 
 
 
 
 
 | 2273 | 
  | 
 
 
 
 
 
 | 2274 | 
               source->curblkno = blkno; | 
 
 
 
 
 
 | 2275 | 
               source->onblk    = onblk; | 
 
 
 
 
 
 | 2276 | 
               source->curblk   = lru[i].blk; | 
 
 
 
 
 
 | 2277 | 
               lru_hits += 1; | 
 
 
 
 
 
 | 2278 | 
               return 0; | 
 
 
 
 
 
 | 2279 | 
             } | 
 
 
 
 
 
 | 2280 | 
         } | 
 
 
 
 
 
 | 2281 | 
     } | 
 
 
 
 
 
 | 2282 | 
  | 
 
 
 
 
 
 | 2283 | 
   if (! main_blklru_list_empty (& lru_free)) | 
 
 
 
 
 
 | 2284 | 
     { | 
 
 
 
 
 
 | 2285 | 
       blru = main_blklru_list_pop_front (& lru_free); | 
 
 
 
 
 
 | 2286 | 
     } | 
 
 
 
 
 
 | 2287 | 
   else if (! main_blklru_list_empty (& lru_list)) | 
 
 
 
 
 
 | 2288 | 
     { | 
 
 
 
 
 
 | 2289 | 
       if (do_not_lru) { | 
 
 
 
 
 
 | 2290 | 
         blru = & lru[blkno % lru_size]; | 
 
 
 
 
 
 | 2291 | 
         main_blklru_list_remove(blru); | 
 
 
 
 
 
 | 2292 | 
       } else { | 
 
 
 
 
 
 | 2293 | 
         blru = main_blklru_list_pop_front (& lru_list); | 
 
 
 
 
 
 | 2294 | 
       } | 
 
 
 
 
 
 | 2295 | 
       lru_misses += 1; | 
 
 
 
 
 
 | 2296 | 
     } | 
 
 
 
 
 
 | 2297 | 
  | 
 
 
 
 
 
 | 2298 | 
   lru_filled += 1; | 
 
 
 
 
 
 | 2299 | 
  | 
 
 
 
 
 
 | 2300 | 
   if ((ret = main_file_seek (sfile, pos))) | 
 
 
 
 
 
 | 2301 | 
     { | 
 
 
 
 
 
 | 2302 | 
       return ret; | 
 
 
 
 
 
 | 2303 | 
     } | 
 
 
 
 
 
 | 2304 | 
  | 
 
 
 
 
 
 | 2305 | 
   if ((ret = main_file_read (sfile, (uint8_t*) blru->blk, source->blksize, | 
 
 
 
 
 
 | 2306 | 
                              & nread, "source read failed"))) | 
 
 
 
 
 
 | 2307 | 
     { | 
 
 
 
 
 
 | 2308 | 
       return ret; | 
 
 
 
 
 
 | 2309 | 
     } | 
 
 
 
 
 
 | 2310 | 
  | 
 
 
 
 
 
 | 2311 | 
   if (nread != onblk) | 
 
 
 
 
 
 | 2312 | 
     { | 
 
 
 
 
 
 | 2313 | 
       XPR(NT "source file size change: %s\n", sfile->filename); | 
 
 
 
 
 
 | 2314 | 
       return XD3_INTERNAL; | 
 
 
 
 
 
 | 2315 | 
     } | 
 
 
 
 
 
 | 2316 | 
  | 
 
 
 
 
 
 | 2317 | 
   main_blklru_list_push_back (& lru_list, blru); | 
 
 
 
 
 
 | 2318 | 
  | 
 
 
 
 
 
 | 2319 | 
   if (option_verbose > 3) | 
 
 
 
 
 
 | 2320 | 
     { | 
 
 
 
 
 
 | 2321 | 
       if (blru->blkno != -1LL) | 
 
 
 
 
 
 | 2322 | 
         { | 
 
 
 
 
 
 | 2323 | 
           XPR(NT "source block %"Q"u ejects %"Q"u (lru_hits=%u, lru_misses=%u, lru_filled=%u)\n", | 
 
 
 
 
 
 | 2324 | 
               blkno, blru->blkno, lru_hits, lru_misses, lru_filled); | 
 
 
 
 
 
 | 2325 | 
         } | 
 
 
 
 
 
 | 2326 | 
       else | 
 
 
 
 
 
 | 2327 | 
         { | 
 
 
 
 
 
 | 2328 | 
           XPR(NT "source block %"Q"u read (lru_hits=%u, lru_misses=%u, lru_filled=%u)\n", | 
 
 
 
 
 
 | 2329 | 
                                           blkno, lru_hits, lru_misses, lru_filled); | 
 
 
 
 
 
 | 2330 | 
         } | 
 
 
 
 
 
 | 2331 | 
     } | 
 
 
 
 
 
 | 2332 | 
  | 
 
 
 
 
 
 | 2333 | 
   blru->blkno      = blkno; | 
 
 
 
 
 
 | 2334 | 
   source->curblk   = blru->blk; | 
 
 
 
 
 
 | 2335 | 
   source->curblkno = blkno; | 
 
 
 
 
 
 | 2336 | 
   source->onblk    = onblk; | 
 
 
 
 
 
 | 2337 | 
  | 
 
 
 
 
 
 | 2338 | 
   return 0; | 
 
 
 
 
 
 | 2339 | 
 } | 
 
 
 
 
 
 | 2340 | 
  | 
 
 
 
 
 
 | 2341 | 
 /****************************************************************************************** | 
 
 
 
 
 
 | 2342 | 
  Main routines | 
 
 
 
 
 
 | 2343 | 
  ******************************************************************************************/ | 
 
 
 
 
 
 | 2344 | 
  | 
 
 
 
 
 
 | 2345 | 
 /* This is a generic input function.  It calls the xd3_encode_input or xd3_decode_input | 
 
 
 
 
 
 | 2346 | 
  * functions and makes calls to the various input handling routines above, which | 
 
 
 
 
 
 | 2347 | 
  * coordinate external decompression. | 
 
 
 
 
 
 | 2348 | 
  */ | 
 
 
 
 
 
 | 2349 | 
 static int | 
 
 
 
 
 
 | 2350 | 
 main_input (xd3_cmd     cmd, | 
 
 
 
 
 
 | 2351 | 
             main_file   *ifile, | 
 
 
 
 
 
 | 2352 | 
             main_file   *ofile, | 
 
 
 
 
 
 | 2353 | 
             main_file   *sfile) | 
 
 
 
 
 
 | 2354 | 
 { | 
 
 
 
 
 
 | 2355 | 
   int        ret; | 
 
 
 
 
 
 | 2356 | 
   xd3_stream stream; | 
 
 
 
 
 
 | 2357 | 
   usize_t    nread; | 
 
 
 
 
 
 | 2358 | 
   int        stream_flags = 0; | 
 
 
 
 
 
 | 2359 | 
   xd3_config config; | 
 
 
 
 
 
 | 2360 | 
   xd3_source source; | 
 
 
 
 
 
 | 2361 | 
   xoff_t     last_total_in = 0; | 
 
 
 
 
 
 | 2362 | 
   xoff_t     last_total_out = 0; | 
 
 
 
 
 
 | 2363 | 
   long       start_time; | 
 
 
 
 
 
 | 2364 | 
   int        stdout_only = 0; | 
 
 
 
 
 
 | 2365 | 
  | 
 
 
 
 
 
 | 2366 | 
   int (*input_func) (xd3_stream*); | 
 
 
 
 
 
 | 2367 | 
   int (*output_func) (xd3_stream*, main_file *); | 
 
 
 
 
 
 | 2368 | 
  | 
 
 
 
 
 
 | 2369 | 
   memset (& source, 0, sizeof (source)); | 
 
 
 
 
 
 | 2370 | 
   memset (& config, 0, sizeof (config)); | 
 
 
 
 
 
 | 2371 | 
  | 
 
 
 
 
 
 | 2372 | 
   config.alloc = main_alloc; | 
 
 
 
 
 
 | 2373 | 
   config.freef = main_free1; | 
 
 
 
 
 
 | 2374 | 
   config.sec_data.ngroups = 1; | 
 
 
 
 
 
 | 2375 | 
   config.sec_addr.ngroups = 1; | 
 
 
 
 
 
 | 2376 | 
   config.sec_inst.ngroups = 1; | 
 
 
 
 
 
 | 2377 | 
   config.iopt_size = option_iopt_size; | 
 
 
 
 
 
 | 2378 | 
   config.sprevsz = option_sprevsz; | 
 
 
 
 
 
 | 2379 | 
  | 
 
 
 
 
 
 | 2380 | 
   do_not_lru = 0; | 
 
 
 
 
 
 | 2381 | 
  | 
 
 
 
 
 
 | 2382 | 
   start_time = get_millisecs_now (); | 
 
 
 
 
 
 | 2383 | 
  | 
 
 
 
 
 
 | 2384 | 
   /* main_input setup. */ | 
 
 
 
 
 
 | 2385 | 
   switch ((int) cmd) | 
 
 
 
 
 
 | 2386 | 
     { | 
 
 
 
 
 
 | 2387 | 
 #if VCDIFF_TOOLS | 
 
 
 
 
 
 | 2388 | 
            if (1) { case CMD_PRINTHDR:   stream_flags = XD3_JUST_HDR; } | 
 
 
 
 
 
 | 2389 | 
       else if (1) { case CMD_PRINTHDRS:  stream_flags = XD3_SKIP_WINDOW; } | 
 
 
 
 
 
 | 2390 | 
       else        { case CMD_PRINTDELTA: stream_flags = XD3_SKIP_EMIT; } | 
 
 
 
 
 
 | 2391 | 
       ifile->flags |= RD_NONEXTERNAL; | 
 
 
 
 
 
 | 2392 | 
       input_func    = xd3_decode_input; | 
 
 
 
 
 
 | 2393 | 
       output_func   = main_print_func; | 
 
 
 
 
 
 | 2394 | 
       stream_flags |= XD3_ADLER32_NOVER; | 
 
 
 
 
 
 | 2395 | 
       stdout_only   = 1; | 
 
 
 
 
 
 | 2396 | 
       break; | 
 
 
 
 
 
 | 2397 | 
 #endif | 
 
 
 
 
 
 | 2398 | 
 #if XD3_ENCODER | 
 
 
 
 
 
 | 2399 | 
     case CMD_ENCODE: | 
 
 
 
 
 
 | 2400 | 
       do_not_lru  = 1; | 
 
 
 
 
 
 | 2401 | 
       input_func  = xd3_encode_input; | 
 
 
 
 
 
 | 2402 | 
       output_func = main_write_output; | 
 
 
 
 
 
 | 2403 | 
  | 
 
 
 
 
 
 | 2404 | 
       if (option_use_checksum) { stream_flags |= XD3_ADLER32; } | 
 
 
 
 
 
 | 2405 | 
       if (option_use_secondary) | 
 
 
 
 
 
 | 2406 | 
         { | 
 
 
 
 
 
 | 2407 | 
           /* The default secondary compressor is DJW, if it's compiled, being used, etc. */ | 
 
 
 
 
 
 | 2408 | 
           if (option_secondary == NULL) | 
 
 
 
 
 
 | 2409 | 
             { | 
 
 
 
 
 
 | 2410 | 
               if (SECONDARY_DJW) { stream_flags |= XD3_SEC_DJW; } | 
 
 
 
 
 
 | 2411 | 
             } | 
 
 
 
 
 
 | 2412 | 
           else | 
 
 
 
 
 
 | 2413 | 
             { | 
 
 
 
 
 
 | 2414 | 
               if (strcmp (option_secondary, "fgk") == 0 && SECONDARY_FGK) | 
 
 
 
 
 
 | 2415 | 
                 { | 
 
 
 
 
 
 | 2416 | 
                   stream_flags |= XD3_SEC_FGK; | 
 
 
 
 
 
 | 2417 | 
                 } | 
 
 
 
 
 
 | 2418 | 
               else if (strcmp (option_secondary, "djw") == 0 && SECONDARY_DJW) | 
 
 
 
 
 
 | 2419 | 
                 { | 
 
 
 
 
 
 | 2420 | 
                   stream_flags |= XD3_SEC_DJW; | 
 
 
 
 
 
 | 2421 | 
                 } | 
 
 
 
 
 
 | 2422 | 
               else | 
 
 
 
 
 
 | 2423 | 
                 { | 
 
 
 
 
 
 | 2424 | 
                   XPR(NT "unrecognized secondary compressor type: %s\n", option_secondary); | 
 
 
 
 
 
 | 2425 | 
                   return EXIT_FAILURE; | 
 
 
 
 
 
 | 2426 | 
                 } | 
 
 
 
 
 
 | 2427 | 
             } | 
 
 
 
 
 
 | 2428 | 
         } | 
 
 
 
 
 
 | 2429 | 
       if (option_no_compress)      { stream_flags |= XD3_NOCOMPRESS; } | 
 
 
 
 
 
 | 2430 | 
       if (option_use_altcodetable) { stream_flags |= XD3_ALT_CODE_TABLE; } | 
 
 
 
 
 
 | 2431 | 
       if (option_smatch_config) | 
 
 
 
 
 
 | 2432 | 
         { | 
 
 
 
 
 
 | 2433 | 
           char *s = option_smatch_config, *e; | 
 
 
 
 
 
 | 2434 | 
           int values[XD3_SOFTCFG_VARCNT]; | 
 
 
 
 
 
 | 2435 | 
           int got; | 
 
 
 
 
 
 | 2436 | 
  | 
 
 
 
 
 
 | 2437 | 
           config.smatch_cfg = XD3_SMATCH_SOFT; | 
 
 
 
 
 
 | 2438 | 
  | 
 
 
 
 
 
 | 2439 | 
           for (got = 0; got < XD3_SOFTCFG_VARCNT; got += 1, s = e + 1) | 
 
 
 
 
 
 | 2440 | 
             { | 
 
 
 
 
 
 | 2441 | 
               values[got] = strtol (s, &e, 10); | 
 
 
 
 
 
 | 2442 | 
  | 
 
 
 
 
 
 | 2443 | 
               if ((values[got] < 0) || | 
 
 
 
 
 
 | 2444 | 
                   (e == s) || | 
 
 
 
 
 
 | 2445 | 
                   (got < XD3_SOFTCFG_VARCNT-1 && *e == 0) || | 
 
 
 
 
 
 | 2446 | 
                   (got == XD3_SOFTCFG_VARCNT-1 && *e != 0)) | 
 
 
 
 
 
 | 2447 | 
                 { | 
 
 
 
 
 
 | 2448 | 
                   XPR(NT "invalid string match specifier (-C) %d: %s\n", | 
 
 
 
 
 
 | 2449 | 
                       got, s); | 
 
 
 
 
 
 | 2450 | 
                   return EXIT_FAILURE; | 
 
 
 
 
 
 | 2451 | 
                 } | 
 
 
 
 
 
 | 2452 | 
             } | 
 
 
 
 
 
 | 2453 | 
  | 
 
 
 
 
 
 | 2454 | 
           config.smatcher_soft.large_look    = values[0]; | 
 
 
 
 
 
 | 2455 | 
           config.smatcher_soft.large_step    = values[1]; | 
 
 
 
 
 
 | 2456 | 
           config.smatcher_soft.small_look    = values[2]; | 
 
 
 
 
 
 | 2457 | 
           config.smatcher_soft.small_chain   = values[3]; | 
 
 
 
 
 
 | 2458 | 
           config.smatcher_soft.small_lchain  = values[4]; | 
 
 
 
 
 
 | 2459 | 
           config.smatcher_soft.max_lazy      = values[5]; | 
 
 
 
 
 
 | 2460 | 
           config.smatcher_soft.long_enough   = values[6]; | 
 
 
 
 
 
 | 2461 | 
         } | 
 
 
 
 
 
 | 2462 | 
       else | 
 
 
 
 
 
 | 2463 | 
         { | 
 
 
 
 
 
 | 2464 | 
           if (option_verbose > 1) | 
 
 
 
 
 
 | 2465 | 
             { | 
 
 
 
 
 
 | 2466 | 
               XPR(NT "compression level: %d\n", option_level); | 
 
 
 
 
 
 | 2467 | 
             } | 
 
 
 
 
 
 | 2468 | 
           if (option_level == 0) | 
 
 
 
 
 
 | 2469 | 
             { | 
 
 
 
 
 
 | 2470 | 
               stream_flags |= XD3_NOCOMPRESS; | 
 
 
 
 
 
 | 2471 | 
               config.smatch_cfg = XD3_SMATCH_FASTEST; | 
 
 
 
 
 
 | 2472 | 
             } | 
 
 
 
 
 
 | 2473 | 
           else if (option_level == 1) { config.smatch_cfg = XD3_SMATCH_FASTEST; } | 
 
 
 
 
 
 | 2474 | 
           else if (option_level <= 5) { config.smatch_cfg = XD3_SMATCH_FAST; } | 
 
 
 
 
 
 | 2475 | 
           else if (option_level == 6) { config.smatch_cfg = XD3_SMATCH_DEFAULT; } | 
 
 
 
 
 
 | 2476 | 
           else                        { config.smatch_cfg = XD3_SMATCH_SLOW; } | 
 
 
 
 
 
 | 2477 | 
         } | 
 
 
 
 
 
 | 2478 | 
       break; | 
 
 
 
 
 
 | 2479 | 
 #endif | 
 
 
 
 
 
 | 2480 | 
     case CMD_DECODE: | 
 
 
 
 
 
 | 2481 | 
       if (option_use_checksum == 0) { stream_flags |= XD3_ADLER32_NOVER; } | 
 
 
 
 
 
 | 2482 | 
       stream_flags  = 0; | 
 
 
 
 
 
 | 2483 | 
       ifile->flags |= RD_NONEXTERNAL; | 
 
 
 
 
 
 | 2484 | 
       input_func    = xd3_decode_input; | 
 
 
 
 
 
 | 2485 | 
       output_func   = main_write_output; | 
 
 
 
 
 
 | 2486 | 
       break; | 
 
 
 
 
 
 | 2487 | 
     default: | 
 
 
 
 
 
 | 2488 | 
       XPR(NT "internal error\n"); | 
 
 
 
 
 
 | 2489 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 2490 | 
     } | 
 
 
 
 
 
 | 2491 | 
  | 
 
 
 
 
 
 | 2492 | 
   main_set_winsize (ifile); | 
 
 
 
 
 
 | 2493 | 
  | 
 
 
 
 
 
 | 2494 | 
   if ((main_bdata = main_malloc (option_winsize)) == NULL) | 
 
 
 
 
 
 | 2495 | 
     { | 
 
 
 
 
 
 | 2496 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 2497 | 
     } | 
 
 
 
 
 
 | 2498 | 
  | 
 
 
 
 
 
 | 2499 | 
   if (IS_ENCODE (cmd)) | 
 
 
 
 
 
 | 2500 | 
     { | 
 
 
 
 
 
 | 2501 | 
       /* When encoding, open the source file, possibly decompress it.  The decoder delays | 
 
 
 
 
 
 | 2502 | 
        * this step until XD3_GOTHEADER. */ | 
 
 
 
 
 
 | 2503 | 
       if (sfile->filename != NULL && (ret = main_set_source (NULL, cmd, sfile, & source))) | 
 
 
 
 
 
 | 2504 | 
         { | 
 
 
 
 
 
 | 2505 | 
           return EXIT_FAILURE; | 
 
 
 
 
 
 | 2506 | 
         } | 
 
 
 
 
 
 | 2507 | 
     } | 
 
 
 
 
 
 | 2508 | 
  | 
 
 
 
 
 
 | 2509 | 
   config.winsize = option_winsize; | 
 
 
 
 
 
 | 2510 | 
   config.srcwin_maxsz = option_srcwinsz; | 
 
 
 
 
 
 | 2511 | 
   config.getblk = main_getblk_func; | 
 
 
 
 
 
 | 2512 | 
   config.flags = stream_flags; | 
 
 
 
 
 
 | 2513 | 
  | 
 
 
 
 
 
 | 2514 | 
   if ((ret = xd3_config_stream (& stream, & config))) | 
 
 
 
 
 
 | 2515 | 
     { | 
 
 
 
 
 
 | 2516 | 
       XPR(NT XD3_LIB_ERRMSG (& stream, ret)); | 
 
 
 
 
 
 | 2517 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 2518 | 
     } | 
 
 
 
 
 
 | 2519 | 
  | 
 
 
 
 
 
 | 2520 | 
   if (IS_ENCODE (cmd) && sfile->filename != NULL && | 
 
 
 
 
 
 | 2521 | 
       (ret = xd3_set_source (& stream, & source))) | 
 
 
 
 
 
 | 2522 | 
     { | 
 
 
 
 
 
 | 2523 | 
       XPR(NT XD3_LIB_ERRMSG (& stream, ret)); | 
 
 
 
 
 
 | 2524 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 2525 | 
     } | 
 
 
 
 
 
 | 2526 | 
  | 
 
 
 
 
 
 | 2527 | 
   /* This times each window. */ | 
 
 
 
 
 
 | 2528 | 
   get_millisecs_since (); | 
 
 
 
 
 
 | 2529 | 
  | 
 
 
 
 
 
 | 2530 | 
   /* Main input loop. */ | 
 
 
 
 
 
 | 2531 | 
   do | 
 
 
 
 
 
 | 2532 | 
     { | 
 
 
 
 
 
 | 2533 | 
       xoff_t input_offset; | 
 
 
 
 
 
 | 2534 | 
       xoff_t input_remain; | 
 
 
 
 
 
 | 2535 | 
       usize_t try_read; | 
 
 
 
 
 
 | 2536 | 
  | 
 
 
 
 
 
 | 2537 | 
       input_offset = ifile->nread; | 
 
 
 
 
 
 | 2538 | 
  | 
 
 
 
 
 
 | 2539 | 
       input_remain = XOFF_T_MAX - input_offset; | 
 
 
 
 
 
 | 2540 | 
  | 
 
 
 
 
 
 | 2541 | 
       try_read = (usize_t) min ((xoff_t) config.winsize, input_remain); | 
 
 
 
 
 
 | 2542 | 
  | 
 
 
 
 
 
 | 2543 | 
       if ((ret = main_read_primary_input (ifile, main_bdata, try_read, & nread))) | 
 
 
 
 
 
 | 2544 | 
         { | 
 
 
 
 
 
 | 2545 | 
           return EXIT_FAILURE; | 
 
 
 
 
 
 | 2546 | 
         } | 
 
 
 
 
 
 | 2547 | 
  | 
 
 
 
 
 
 | 2548 | 
       /* If we've reached EOF tell the stream to flush. */ | 
 
 
 
 
 
 | 2549 | 
       if (nread < try_read) | 
 
 
 
 
 
 | 2550 | 
         { | 
 
 
 
 
 
 | 2551 | 
           stream_flags |= XD3_FLUSH; | 
 
 
 
 
 
 | 2552 | 
           xd3_set_flags (& stream, stream_flags); | 
 
 
 
 
 
 | 2553 | 
         } | 
 
 
 
 
 
 | 2554 | 
  | 
 
 
 
 
 
 | 2555 | 
 #if XD3_ENCODER | 
 
 
 
 
 
 | 2556 | 
       /* After the first main_read_primary_input completes, we know all the information | 
 
 
 
 
 
 | 2557 | 
        * needed to encode the application header. */ | 
 
 
 
 
 
 | 2558 | 
       if (cmd == CMD_ENCODE && (ret = main_set_appheader (& stream, ifile, sfile))) | 
 
 
 
 
 
 | 2559 | 
         { | 
 
 
 
 
 
 | 2560 | 
           return EXIT_FAILURE; | 
 
 
 
 
 
 | 2561 | 
         } | 
 
 
 
 
 
 | 2562 | 
 #endif | 
 
 
 
 
 
 | 2563 | 
       xd3_avail_input (& stream, main_bdata, nread); | 
 
 
 
 
 
 | 2564 | 
  | 
 
 
 
 
 
 | 2565 | 
       /* If we read zero bytes after encoding at least one window... */ | 
 
 
 
 
 
 | 2566 | 
       if (nread == 0 && stream.current_window > 0) { | 
 
 
 
 
 
 | 2567 | 
         break; | 
 
 
 
 
 
 | 2568 | 
       } | 
 
 
 
 
 
 | 2569 | 
  | 
 
 
 
 
 
 | 2570 | 
     again: | 
 
 
 
 
 
 | 2571 | 
       ret = input_func (& stream); | 
 
 
 
 
 
 | 2572 | 
  | 
 
 
 
 
 
 | 2573 | 
       switch (ret) | 
 
 
 
 
 
 | 2574 | 
         { | 
 
 
 
 
 
 | 2575 | 
         case XD3_INPUT: | 
 
 
 
 
 
 | 2576 | 
           continue; | 
 
 
 
 
 
 | 2577 | 
  | 
 
 
 
 
 
 | 2578 | 
         case XD3_GOTHEADER: | 
 
 
 
 
 
 | 2579 | 
           { | 
 
 
 
 
 
 | 2580 | 
             XD3_ASSERT (stream.current_window == 0); | 
 
 
 
 
 
 | 2581 | 
  | 
 
 
 
 
 
 | 2582 | 
             /* Need to process the appheader as soon as possible.  It may contain a | 
 
 
 
 
 
 | 2583 | 
              * suggested default filename/decompression routine for the ofile, and it may | 
 
 
 
 
 
 | 2584 | 
              * contain default/decompression routine for the sources. */ | 
 
 
 
 
 
 | 2585 | 
             if (cmd == CMD_DECODE) | 
 
 
 
 
 
 | 2586 | 
               { | 
 
 
 
 
 
 | 2587 | 
                 int have_src = sfile->filename != NULL; | 
 
 
 
 
 
 | 2588 | 
                 int need_src = xd3_decoder_needs_source (& stream); | 
 
 
 
 
 
 | 2589 | 
                 int recv_src; | 
 
 
 
 
 
 | 2590 | 
  | 
 
 
 
 
 
 | 2591 | 
                 /* May need to set the sfile->filename if none was given. */ | 
 
 
 
 
 
 | 2592 | 
                 main_get_appheader (& stream, ifile, ofile, sfile); | 
 
 
 
 
 
 | 2593 | 
  | 
 
 
 
 
 
 | 2594 | 
                 recv_src = sfile->filename != NULL; | 
 
 
 
 
 
 | 2595 | 
  | 
 
 
 
 
 
 | 2596 | 
                 /* Check if the user expected a source to be required although it was not. */ | 
 
 
 
 
 
 | 2597 | 
                 if (have_src && ! need_src && ! option_quiet) | 
 
 
 
 
 
 | 2598 | 
                   { | 
 
 
 
 
 
 | 2599 | 
                     XPR(NT "warning: output window %"Q"u does not copy source\n", stream.current_window); | 
 
 
 
 
 
 | 2600 | 
                   } | 
 
 
 
 
 
 | 2601 | 
  | 
 
 
 
 
 
 | 2602 | 
                 /* Check if we have no source name and need one. */ | 
 
 
 
 
 
 | 2603 | 
                 /* TODO: this doesn't fire due to cpyblocks_ calculation check? */ | 
 
 
 
 
 
 | 2604 | 
                 if (need_src && ! recv_src) | 
 
 
 
 
 
 | 2605 | 
                   { | 
 
 
 
 
 
 | 2606 | 
                     XPR(NT "input requires a source file, use -s\n"); | 
 
 
 
 
 
 | 2607 | 
                     return EXIT_FAILURE; | 
 
 
 
 
 
 | 2608 | 
                   } | 
 
 
 
 
 
 | 2609 | 
  | 
 
 
 
 
 
 | 2610 | 
                 /* Now open the source file. */ | 
 
 
 
 
 
 | 2611 | 
                 if (need_src && (ret = main_set_source (& stream, cmd, sfile, & source))) | 
 
 
 
 
 
 | 2612 | 
                   { | 
 
 
 
 
 
 | 2613 | 
                     return EXIT_FAILURE; | 
 
 
 
 
 
 | 2614 | 
                   } | 
 
 
 
 
 
 | 2615 | 
               } | 
 
 
 
 
 
 | 2616 | 
             else if (cmd == CMD_PRINTHDR || | 
 
 
 
 
 
 | 2617 | 
                      cmd == CMD_PRINTHDRS || | 
 
 
 
 
 
 | 2618 | 
                      cmd == CMD_PRINTDELTA) | 
 
 
 
 
 
 | 2619 | 
               { | 
 
 
 
 
 
 | 2620 | 
                 if (xd3_decoder_needs_source (& stream) && sfile->filename == NULL) | 
 
 
 
 
 
 | 2621 | 
                   { | 
 
 
 
 
 
 | 2622 | 
                     allow_fake_source = 1; | 
 
 
 
 
 
 | 2623 | 
                     sfile->filename = "<placeholder>"; | 
 
 
 
 
 
 | 2624 | 
                     main_set_source (& stream, cmd, sfile, & source); | 
 
 
 
 
 
 | 2625 | 
                   } | 
 
 
 
 
 
 | 2626 | 
               } | 
 
 
 
 
 
 | 2627 | 
           } | 
 
 
 
 
 
 | 2628 | 
         /* FALLTHROUGH */ | 
 
 
 
 
 
 | 2629 | 
         case XD3_WINSTART: | 
 
 
 
 
 
 | 2630 | 
           { | 
 
 
 
 
 
 | 2631 | 
             /* e.g., set or unset XD3_SKIP_WINDOW. */ | 
 
 
 
 
 
 | 2632 | 
             /* xd3_set_flags (& stream, stream_flags); */ | 
 
 
 
 
 
 | 2633 | 
             goto again; | 
 
 
 
 
 
 | 2634 | 
           } | 
 
 
 
 
 
 | 2635 | 
  | 
 
 
 
 
 
 | 2636 | 
         case XD3_OUTPUT: | 
 
 
 
 
 
 | 2637 | 
           { | 
 
 
 
 
 
 | 2638 | 
             if (option_no_output == 0) | 
 
 
 
 
 
 | 2639 | 
               { | 
 
 
 
 
 
 | 2640 | 
                 /* Defer opening the output file until the stream produces its first | 
 
 
 
 
 
 | 2641 | 
                  * output for both encoder and decoder, this way we delay long enough for | 
 
 
 
 
 
 | 2642 | 
                  * the decoder to receive the application header.  (Or longer if there are | 
 
 
 
 
 
 | 2643 | 
                  * skipped windows, but I can't think of any reason not to delay open.) */ | 
 
 
 
 
 
 | 2644 | 
  | 
 
 
 
 
 
 | 2645 | 
                 if (! main_file_isopen (ofile) && (ret = main_open_output (& stream, ofile)) != 0) | 
 
 
 
 
 
 | 2646 | 
                   { | 
 
 
 
 
 
 | 2647 | 
                     return EXIT_FAILURE; | 
 
 
 
 
 
 | 2648 | 
                   } | 
 
 
 
 
 
 | 2649 | 
                 if ((ret = output_func (& stream, ofile)) && (ret != PRINTHDR_SPECIAL)) | 
 
 
 
 
 
 | 2650 | 
                   { | 
 
 
 
 
 
 | 2651 | 
                     return EXIT_FAILURE; | 
 
 
 
 
 
 | 2652 | 
                   } | 
 
 
 
 
 
 | 2653 | 
                 if (ret == PRINTHDR_SPECIAL) | 
 
 
 
 
 
 | 2654 | 
                   { | 
 
 
 
 
 
 | 2655 | 
                     xd3_abort_stream (& stream); | 
 
 
 
 
 
 | 2656 | 
                     ret = EXIT_SUCCESS; | 
 
 
 
 
 
 | 2657 | 
                     goto done; | 
 
 
 
 
 
 | 2658 | 
                   } | 
 
 
 
 
 
 | 2659 | 
                 ret = 0; | 
 
 
 
 
 
 | 2660 | 
               } | 
 
 
 
 
 
 | 2661 | 
  | 
 
 
 
 
 
 | 2662 | 
             xd3_consume_output (& stream); | 
 
 
 
 
 
 | 2663 | 
             goto again; | 
 
 
 
 
 
 | 2664 | 
           } | 
 
 
 
 
 
 | 2665 | 
  | 
 
 
 
 
 
 | 2666 | 
         case XD3_WINFINISH: | 
 
 
 
 
 
 | 2667 | 
           { | 
 
 
 
 
 
 | 2668 | 
             if (IS_ENCODE (cmd) || cmd == CMD_DECODE) | 
 
 
 
 
 
 | 2669 | 
               { | 
 
 
 
 
 
 | 2670 | 
                 if (! option_quiet && IS_ENCODE (cmd) && main_file_isopen (sfile)) | 
 
 
 
 
 
 | 2671 | 
                   { | 
 
 
 
 
 
 | 2672 | 
                     /* Warn when no source copies are found */ | 
 
 
 
 
 
 | 2673 | 
                     if (! xd3_encoder_used_source (& stream)) | 
 
 
 
 
 
 | 2674 | 
                       { | 
 
 
 
 
 
 | 2675 | 
                         XPR(NT "warning: input window %"Q"u..%"Q"u has no source copies\n", | 
 
 
 
 
 
 | 2676 | 
                             stream.current_window * option_winsize, | 
 
 
 
 
 
 | 2677 | 
                             (stream.current_window+1) * option_winsize); | 
 
 
 
 
 
 | 2678 | 
                       } | 
 
 
 
 
 
 | 2679 | 
                      | 
 
 
 
 
 
 | 2680 | 
                     /* Limited instruction buffer size affects source copies */ | 
 
 
 
 
 
 | 2681 | 
                     if (option_verbose > 1 && stream.i_slots_used > stream.iopt_size) | 
 
 
 
 
 
 | 2682 | 
                       { | 
 
 
 
 
 
 | 2683 | 
                         XPR(NT "warning: input position %"Q"u overflowed instruction buffer, " | 
 
 
 
 
 
 | 2684 | 
                             "needed %u (vs. %u), consider raising -I\n", | 
 
 
 
 
 
 | 2685 | 
                             stream.current_window * option_winsize, | 
 
 
 
 
 
 | 2686 | 
                             stream.i_slots_used, stream.iopt_size); | 
 
 
 
 
 
 | 2687 | 
                       } | 
 
 
 
 
 
 | 2688 | 
                   } | 
 
 
 
 
 
 | 2689 | 
  | 
 
 
 
 
 
 | 2690 | 
                 if (option_verbose) | 
 
 
 
 
 
 | 2691 | 
                   { | 
 
 
 
 
 
 | 2692 | 
                     char rrateavg[32], wrateavg[32], tm[32]; | 
 
 
 
 
 
 | 2693 | 
                     char rdb[32], wdb[32]; | 
 
 
 
 
 
 | 2694 | 
                     char trdb[32], twdb[32]; | 
 
 
 
 
 
 | 2695 | 
                     long millis = get_millisecs_since (); | 
 
 
 
 
 
 | 2696 | 
                     usize_t this_read = (usize_t)(stream.total_in - last_total_in); | 
 
 
 
 
 
 | 2697 | 
                     usize_t this_write = (usize_t)(stream.total_out - last_total_out); | 
 
 
 
 
 
 | 2698 | 
                     last_total_in = stream.total_in; | 
 
 
 
 
 
 | 2699 | 
                     last_total_out = stream.total_out; | 
 
 
 
 
 
 | 2700 | 
  | 
 
 
 
 
 
 | 2701 | 
                     if (option_verbose > 1) | 
 
 
 
 
 
 | 2702 | 
                       { | 
 
 
 
 
 
 | 2703 | 
                         XPR(NT "%"Q"u: in %s (%s): out %s (%s): total in %s: out %s: %s\n", | 
 
 
 
 
 
 | 2704 | 
                             stream.current_window, | 
 
 
 
 
 
 | 2705 | 
                             main_format_bcnt (this_read, rdb), | 
 
 
 
 
 
 | 2706 | 
                             main_format_rate (this_read, millis, rrateavg), | 
 
 
 
 
 
 | 2707 | 
                             main_format_bcnt (this_write, wdb), | 
 
 
 
 
 
 | 2708 | 
                             main_format_rate (this_write, millis, wrateavg), | 
 
 
 
 
 
 | 2709 | 
                             main_format_bcnt (stream.total_in, trdb), | 
 
 
 
 
 
 | 2710 | 
                             main_format_bcnt (stream.total_out, twdb), | 
 
 
 
 
 
 | 2711 | 
                             main_format_millis (millis, tm)); | 
 
 
 
 
 
 | 2712 | 
                       } | 
 
 
 
 
 
 | 2713 | 
                     else | 
 
 
 
 
 
 | 2714 | 
                       { | 
 
 
 
 
 
 | 2715 | 
                         XPR(NT "%"Q"u: in %s: out %s: total in %s: out %s: %s\n", | 
 
 
 
 
 
 | 2716 | 
                             stream.current_window, | 
 
 
 
 
 
 | 2717 | 
                             main_format_bcnt (this_read, rdb), | 
 
 
 
 
 
 | 2718 | 
                             main_format_bcnt (this_write, wdb), | 
 
 
 
 
 
 | 2719 | 
                             main_format_bcnt (stream.total_in, trdb), | 
 
 
 
 
 
 | 2720 | 
                             main_format_bcnt (stream.total_out, twdb), | 
 
 
 
 
 
 | 2721 | 
                             main_format_millis (millis, tm)); | 
 
 
 
 
 
 | 2722 | 
                       } | 
 
 
 
 
 
 | 2723 | 
                   } | 
 
 
 
 
 
 | 2724 | 
               } | 
 
 
 
 
 
 | 2725 | 
             goto again; | 
 
 
 
 
 
 | 2726 | 
           } | 
 
 
 
 
 
 | 2727 | 
  | 
 
 
 
 
 
 | 2728 | 
         default: | 
 
 
 
 
 
 | 2729 | 
           /* input_func() error */ | 
 
 
 
 
 
 | 2730 | 
           XPR(NT XD3_LIB_ERRMSG (& stream, ret)); | 
 
 
 
 
 
 | 2731 | 
           return EXIT_FAILURE; | 
 
 
 
 
 
 | 2732 | 
         } | 
 
 
 
 
 
 | 2733 | 
     } | 
 
 
 
 
 
 | 2734 | 
   while (nread == config.winsize); | 
 
 
 
 
 
 | 2735 | 
 done: | 
 
 
 
 
 
 | 2736 | 
   /* Close the inputs. (ifile must be open, sfile may be open) */ | 
 
 
 
 
 
 | 2737 | 
   main_file_close (ifile); | 
 
 
 
 
 
 | 2738 | 
   main_file_close (sfile); | 
 
 
 
 
 
 | 2739 | 
  | 
 
 
 
 
 
 | 2740 | 
   /* If output file is not open yet because of delayed-open, it means we never encountered | 
 
 
 
 
 
 | 2741 | 
    * a window in the delta, but it could have had a VCDIFF header?  TODO: solve this | 
 
 
 
 
 
 | 2742 | 
    * elsewhere.  For now, it prints "nothing to output" below, but the check doesn't | 
 
 
 
 
 
 | 2743 | 
    * happen in case of option_no_output.  */ | 
 
 
 
 
 
 | 2744 | 
   if (! option_no_output) | 
 
 
 
 
 
 | 2745 | 
     { | 
 
 
 
 
 
 | 2746 | 
       if (!stdout_only && ! main_file_isopen (ofile)) | 
 
 
 
 
 
 | 2747 | 
         { | 
 
 
 
 
 
 | 2748 | 
           XPR(NT "nothing to output: %s\n", ifile->filename); | 
 
 
 
 
 
 | 2749 | 
           return EXIT_FAILURE; | 
 
 
 
 
 
 | 2750 | 
         } | 
 
 
 
 
 
 | 2751 | 
  | 
 
 
 
 
 
 | 2752 | 
       /* Have to close the output before calling main_external_compression_finish, or else it hangs. */ | 
 
 
 
 
 
 | 2753 | 
       if (main_file_close (ofile) != 0) | 
 
 
 
 
 
 | 2754 | 
         { | 
 
 
 
 
 
 | 2755 | 
           return EXIT_FAILURE; | 
 
 
 
 
 
 | 2756 | 
         } | 
 
 
 
 
 
 | 2757 | 
     } | 
 
 
 
 
 
 | 2758 | 
  | 
 
 
 
 
 
 | 2759 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 2760 | 
   if ((ret = main_external_compression_finish ())) | 
 
 
 
 
 
 | 2761 | 
     { | 
 
 
 
 
 
 | 2762 | 
       XPR(NT "external compression commands failed\n"); | 
 
 
 
 
 
 | 2763 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 2764 | 
     } | 
 
 
 
 
 
 | 2765 | 
 #endif | 
 
 
 
 
 
 | 2766 | 
  | 
 
 
 
 
 
 | 2767 | 
   if ((ret = xd3_close_stream (& stream))) | 
 
 
 
 
 
 | 2768 | 
     { | 
 
 
 
 
 
 | 2769 | 
       XPR(NT XD3_LIB_ERRMSG (& stream, ret)); | 
 
 
 
 
 
 | 2770 | 
       return EXIT_FAILURE; | 
 
 
 
 
 
 | 2771 | 
     } | 
 
 
 
 
 
 | 2772 | 
  | 
 
 
 
 
 
 | 2773 | 
   if (option_verbose > 1) | 
 
 
 
 
 
 | 2774 | 
     { | 
 
 
 
 
 
 | 2775 | 
       XPR(NT "scanner configuration: %s\n", stream.smatcher.name); | 
 
 
 
 
 
 | 2776 | 
       XPR(NT "target hash table size: %u\n", stream.small_hash.size); | 
 
 
 
 
 
 | 2777 | 
       if (sfile->filename != NULL) | 
 
 
 
 
 
 | 2778 | 
         { | 
 
 
 
 
 
 | 2779 | 
           XPR(NT "source hash table size: %u\n", stream.large_hash.size); | 
 
 
 
 
 
 | 2780 | 
         } | 
 
 
 
 
 
 | 2781 | 
     } | 
 
 
 
 
 
 | 2782 | 
  | 
 
 
 
 
 
 | 2783 | 
   if (option_verbose > 2) | 
 
 
 
 
 
 | 2784 | 
     { | 
 
 
 
 
 
 | 2785 | 
       XPR(NT "source copies: %"Q"u (%"Q"u bytes)\n", stream.n_scpy, stream.l_scpy); | 
 
 
 
 
 
 | 2786 | 
       XPR(NT "target copies: %"Q"u (%"Q"u bytes)\n", stream.n_tcpy, stream.l_tcpy); | 
 
 
 
 
 
 | 2787 | 
       XPR(NT "adds: %"Q"u (%"Q"u bytes)\n", stream.n_add, stream.l_add); | 
 
 
 
 
 
 | 2788 | 
       XPR(NT "runs: %"Q"u (%"Q"u bytes)\n", stream.n_run, stream.l_run); | 
 
 
 
 
 
 | 2789 | 
     } | 
 
 
 
 
 
 | 2790 | 
  | 
 
 
 
 
 
 | 2791 | 
   xd3_free_stream (& stream); | 
 
 
 
 
 
 | 2792 | 
  | 
 
 
 
 
 
 | 2793 | 
   if (option_verbose) | 
 
 
 
 
 
 | 2794 | 
     { | 
 
 
 
 
 
 | 2795 | 
       char tm[32]; | 
 
 
 
 
 
 | 2796 | 
       long end_time = get_millisecs_now (); | 
 
 
 
 
 
 | 2797 | 
       XPR(NT "finished in %s; input %"Q"u output %"Q"u bytes  (%0.2f%%)\n", | 
 
 
 
 
 
 | 2798 | 
           main_format_millis (end_time - start_time, tm), | 
 
 
 
 
 
 | 2799 | 
           ifile->nread, ofile->nwrite, | 
 
 
 
 
 
 | 2800 | 
           100.0 * ofile->nwrite / ifile->nread); | 
 
 
 
 
 
 | 2801 | 
     } | 
 
 
 
 
 
 | 2802 | 
  | 
 
 
 
 
 
 | 2803 | 
   return EXIT_SUCCESS; | 
 
 
 
 
 
 | 2804 | 
 } | 
 
 
 
 
 
 | 2805 | 
  | 
 
 
 
 
 
 | 2806 | 
 /* free memory before exit, reset single-use variables. */ | 
 
 
 
 
 
 | 2807 | 
 static void | 
 
 
 
 
 
 | 2808 | 
 main_cleanup (void) | 
 
 
 
 
 
 | 2809 | 
 { | 
 
 
 
 
 
 | 2810 | 
   int i; | 
 
 
 
 
 
 | 2811 | 
  | 
 
 
 
 
 
 | 2812 | 
   if (appheader_used != NULL && | 
 
 
 
 
 
 | 2813 | 
       appheader_used != option_appheader) | 
 
 
 
 
 
 | 2814 | 
     { | 
 
 
 
 
 
 | 2815 | 
       main_free (appheader_used); | 
 
 
 
 
 
 | 2816 | 
       appheader_used = NULL; | 
 
 
 
 
 
 | 2817 | 
     } | 
 
 
 
 
 
 | 2818 | 
  | 
 
 
 
 
 
 | 2819 | 
   main_free (main_bdata); | 
 
 
 
 
 
 | 2820 | 
   main_bdata = NULL; | 
 
 
 
 
 
 | 2821 | 
  | 
 
 
 
 
 
 | 2822 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 2823 | 
   main_free (ext_tmpfile); | 
 
 
 
 
 
 | 2824 | 
   ext_tmpfile = NULL; | 
 
 
 
 
 
 | 2825 | 
 #endif | 
 
 
 
 
 
 | 2826 | 
  | 
 
 
 
 
 
 | 2827 | 
   for (i = 0; lru && i < lru_size; i += 1) | 
 
 
 
 
 
 | 2828 | 
     { | 
 
 
 
 
 
 | 2829 | 
       main_free (lru[i].blk); | 
 
 
 
 
 
 | 2830 | 
     } | 
 
 
 
 
 
 | 2831 | 
  | 
 
 
 
 
 
 | 2832 | 
   main_free (lru); | 
 
 
 
 
 
 | 2833 | 
   lru = NULL; | 
 
 
 
 
 
 | 2834 | 
  | 
 
 
 
 
 
 | 2835 | 
   lru_hits = 0; | 
 
 
 
 
 
 | 2836 | 
   lru_misses = 0; | 
 
 
 
 
 
 | 2837 | 
   lru_filled = 0; | 
 
 
 
 
 
 | 2838 | 
  | 
 
 
 
 
 
 | 2839 | 
   XD3_ASSERT (main_mallocs == 0); | 
 
 
 
 
 
 | 2840 | 
 } | 
 
 
 
 
 
 | 2841 | 
  | 
 
 
 
 
 
 | 2842 | 
 static void | 
 
 
 
 
 
 | 2843 | 
 setup_environment (int argc, | 
 
 
 
 
 
 | 2844 | 
                    char **argv, | 
 
 
 
 
 
 | 2845 | 
                    int *argc_out, | 
 
 
 
 
 
 | 2846 | 
                    char ***argv_out, | 
 
 
 
 
 
 | 2847 | 
                    char ***argv_free, | 
 
 
 
 
 
 | 2848 | 
                    char **env_free) | 
 
 
 
 
 
 | 2849 | 
 { | 
 
 
 
 
 
 | 2850 | 
   int n, i, i0; | 
 
 
 
 
 
 | 2851 | 
   char *p, *v = getenv("XDELTA"); | 
 
 
 
 
 
 | 2852 | 
   if (v == NULL) { | 
 
 
 
 
 
 | 2853 | 
     (*argc_out) = argc; | 
 
 
 
 
 
 | 2854 | 
     (*argv_out) = argv; | 
 
 
 
 
 
 | 2855 | 
     (*argv_free) = NULL; | 
 
 
 
 
 
 | 2856 | 
     (*env_free) = NULL; | 
 
 
 
 
 
 | 2857 | 
     return; | 
 
 
 
 
 
 | 2858 | 
   } | 
 
 
 
 
 
 | 2859 | 
  | 
 
 
 
 
 
 | 2860 | 
   (*env_free) = main_malloc(strlen(v) + 1); | 
 
 
 
 
 
 | 2861 | 
   strcpy(*env_free, v); | 
 
 
 
 
 
 | 2862 | 
  | 
 
 
 
 
 
 | 2863 | 
   /* Space needed for extra args, at least # of spaces */ | 
 
 
 
 
 
 | 2864 | 
   n = argc + 1; | 
 
 
 
 
 
 | 2865 | 
   for (p = *env_free; *p != 0; ) { | 
 
 
 
 
 
 | 2866 | 
     if (*p++ == ' ') { | 
 
 
 
 
 
 | 2867 | 
       n++; | 
 
 
 
 
 
 | 2868 | 
     } | 
 
 
 
 
 
 | 2869 | 
   } | 
 
 
 
 
 
 | 2870 | 
  | 
 
 
 
 
 
 | 2871 | 
   (*argv_free) = main_malloc(sizeof(char*) * (n + 1)); | 
 
 
 
 
 
 | 2872 | 
   (*argv_out) = (*argv_free); | 
 
 
 
 
 
 | 2873 | 
   (*argv_out)[0] = argv[0]; | 
 
 
 
 
 
 | 2874 | 
   (*argv_out)[n] = NULL; | 
 
 
 
 
 
 | 2875 | 
  | 
 
 
 
 
 
 | 2876 | 
   i = 1; | 
 
 
 
 
 
 | 2877 | 
   for (p = *env_free; *p != 0; ) { | 
 
 
 
 
 
 | 2878 | 
     (*argv_out)[i++] = p; | 
 
 
 
 
 
 | 2879 | 
     while (*p != ' ' && *p != 0) { | 
 
 
 
 
 
 | 2880 | 
       p++; | 
 
 
 
 
 
 | 2881 | 
     } | 
 
 
 
 
 
 | 2882 | 
     while (*p == ' ') { | 
 
 
 
 
 
 | 2883 | 
       *p++ = 0; | 
 
 
 
 
 
 | 2884 | 
     } | 
 
 
 
 
 
 | 2885 | 
   } | 
 
 
 
 
 
 | 2886 | 
  | 
 
 
 
 
 
 | 2887 | 
   for (i0 = 1; i0 < argc; i0++) { | 
 
 
 
 
 
 | 2888 | 
     (*argv_out)[i++] = argv[i0]; | 
 
 
 
 
 
 | 2889 | 
   } | 
 
 
 
 
 
 | 2890 | 
  | 
 
 
 
 
 
 | 2891 | 
   /* Counting spaces is an upper bound, argv stays NULL terminated. */ | 
 
 
 
 
 
 | 2892 | 
   (*argc_out) = i; | 
 
 
 
 
 
 | 2893 | 
   while (i <= n) { | 
 
 
 
 
 
 | 2894 | 
     (*argv_out)[i++] = NULL; | 
 
 
 
 
 
 | 2895 | 
   } | 
 
 
 
 
 
 | 2896 | 
 } | 
 
 
 
 
 
 | 2897 | 
  | 
 
 
 
 
 
 | 2898 | 
 int | 
 
 
 
 
 
 | 2899 | 
 #if PYTHON_MODULE || SWIG_MODULE | 
 
 
 
 
 
 | 2900 | 
 xd3_main_cmdline (int argc, char **argv) | 
 
 
 
 
 
 | 2901 | 
 #else | 
 
 
 
 
 
 | 2902 | 
 main (int argc, char **argv) | 
 
 
 
 
 
 | 2903 | 
 #endif | 
 
 
 
 
 
 | 2904 | 
 { | 
 
 
 
 
 
 | 2905 | 
   xd3_cmd cmd; | 
 
 
 
 
 
 | 2906 | 
   main_file ifile; | 
 
 
 
 
 
 | 2907 | 
   main_file ofile; | 
 
 
 
 
 
 | 2908 | 
   main_file sfile; | 
 
 
 
 
 
 | 2909 | 
   static const char *flags = "0123456789cdefhnqvDJNORTVs:B:C:E:F:I:L:O:M:P:W:A::S::"; | 
 
 
 
 
 
 | 2910 | 
   int my_optind; | 
 
 
 
 
 
 | 2911 | 
   char *my_optarg; | 
 
 
 
 
 
 | 2912 | 
   char *my_optstr; | 
 
 
 
 
 
 | 2913 | 
   char *sfilename; | 
 
 
 
 
 
 | 2914 | 
   int env_argc; | 
 
 
 
 
 
 | 2915 | 
   char **env_argv; | 
 
 
 
 
 
 | 2916 | 
   char **free_argv;  /* malloc() in setup_environment() */ | 
 
 
 
 
 
 | 2917 | 
   char *free_value;  /* malloc() in setup_environment() */ | 
 
 
 
 
 
 | 2918 | 
   int ret; | 
 
 
 
 
 
 | 2919 | 
  | 
 
 
 
 
 
 | 2920 | 
 #ifdef _WIN32 | 
 
 
 
 
 
 | 2921 | 
   GetStartupInfo(&winStartupInfo); | 
 
 
 
 
 
 | 2922 | 
   setvbuf(stderr, NULL, _IONBF, 0);  /* Do not buffer stderr */ | 
 
 
 
 
 
 | 2923 | 
 #endif | 
 
 
 
 
 
 | 2924 | 
  | 
 
 
 
 
 
 | 2925 | 
   main_file_init (& ifile); | 
 
 
 
 
 
 | 2926 | 
   main_file_init (& ofile); | 
 
 
 
 
 
 | 2927 | 
   main_file_init (& sfile); | 
 
 
 
 
 
 | 2928 | 
  | 
 
 
 
 
 
 | 2929 | 
   reset_defaults(); | 
 
 
 
 
 
 | 2930 | 
  | 
 
 
 
 
 
 | 2931 | 
   free_argv = NULL; | 
 
 
 
 
 
 | 2932 | 
   free_value = NULL; | 
 
 
 
 
 
 | 2933 | 
   setup_environment(argc, argv, &env_argc, &env_argv, &free_argv, &free_value); | 
 
 
 
 
 
 | 2934 | 
   cmd = CMD_NONE; | 
 
 
 
 
 
 | 2935 | 
   sfilename = NULL; | 
 
 
 
 
 
 | 2936 | 
   my_optind = 1; | 
 
 
 
 
 
 | 2937 | 
   argv = env_argv; | 
 
 
 
 
 
 | 2938 | 
   argc = env_argc; | 
 
 
 
 
 
 | 2939 | 
   program_name = env_argv[0]; | 
 
 
 
 
 
 | 2940 | 
   extcomp_types[0].recomp_cmdname = program_name; | 
 
 
 
 
 
 | 2941 | 
   extcomp_types[0].decomp_cmdname = program_name; | 
 
 
 
 
 
 | 2942 | 
  takearg: | 
 
 
 
 
 
 | 2943 | 
   my_optarg = NULL; | 
 
 
 
 
 
 | 2944 | 
   my_optstr = argv[my_optind]; | 
 
 
 
 
 
 | 2945 | 
   /* This doesn't use getopt() because it makes trouble for -P & python which reenter | 
 
 
 
 
 
 | 2946 | 
    * main() and thus care about freeing all memory.  I never had much trust for getopt | 
 
 
 
 
 
 | 2947 | 
    * anyway, it's too opaque.  This implements a fairly standard non-long-option getopt | 
 
 
 
 
 
 | 2948 | 
    * with support for named operations (e.g., "xdelta3 [encode|decode|printhdr...] < in > | 
 
 
 
 
 
 | 2949 | 
    * out"). */ | 
 
 
 
 
 
 | 2950 | 
   if (my_optstr) | 
 
 
 
 
 
 | 2951 | 
     { | 
 
 
 
 
 
 | 2952 | 
       if (*my_optstr == '-')    { my_optstr += 1; } | 
 
 
 
 
 
 | 2953 | 
       else if (cmd == CMD_NONE) { goto nonflag; } | 
 
 
 
 
 
 | 2954 | 
       else                      { my_optstr = NULL; } | 
 
 
 
 
 
 | 2955 | 
     } | 
 
 
 
 
 
 | 2956 | 
   while (my_optstr) | 
 
 
 
 
 
 | 2957 | 
     { | 
 
 
 
 
 
 | 2958 | 
       char *s; | 
 
 
 
 
 
 | 2959 | 
       my_optarg = NULL; | 
 
 
 
 
 
 | 2960 | 
       if ((ret = *my_optstr++) == 0) { my_optind += 1; goto takearg; } | 
 
 
 
 
 
 | 2961 | 
  | 
 
 
 
 
 
 | 2962 | 
       /* Option handling: first check for one ':' following the option in flags, then | 
 
 
 
 
 
 | 2963 | 
        * check for two.  The syntax allows: | 
 
 
 
 
 
 | 2964 | 
        * | 
 
 
 
 
 
 | 2965 | 
        * 1. -Afoo                   defines optarg="foo" | 
 
 
 
 
 
 | 2966 | 
        * 2. -A foo                  defines optarg="foo" | 
 
 
 
 
 
 | 2967 | 
        * 3. -A ""                   defines optarg="" (allows optional empty-string) | 
 
 
 
 
 
 | 2968 | 
        * 4. -A [EOA or -moreargs]   error (mandatory case) | 
 
 
 
 
 
 | 2969 | 
        * 5. -A [EOA -moreargs]      defines optarg=NULL (optional case) | 
 
 
 
 
 
 | 2970 | 
        * 6. -A=foo                  defines optarg="foo" | 
 
 
 
 
 
 | 2971 | 
        * 7. -A=                     defines optarg="" (mandatory case) | 
 
 
 
 
 
 | 2972 | 
        * 8. -A=                     defines optarg=NULL (optional case) | 
 
 
 
 
 
 | 2973 | 
        * | 
 
 
 
 
 
 | 2974 | 
        * See tests in test_command_line_arguments(). | 
 
 
 
 
 
 | 2975 | 
        */ | 
 
 
 
 
 
 | 2976 | 
       s = strchr (flags, ret); | 
 
 
 
 
 
 | 2977 | 
       if (s && s[1] && s[1] == ':') | 
 
 
 
 
 
 | 2978 | 
         { | 
 
 
 
 
 
 | 2979 | 
           int eqcase = 0; | 
 
 
 
 
 
 | 2980 | 
           int option = s[2] && s[2] == ':'; | 
 
 
 
 
 
 | 2981 | 
  | 
 
 
 
 
 
 | 2982 | 
           /* Case 1, set optarg to the remaining characters. */ | 
 
 
 
 
 
 | 2983 | 
           my_optarg = my_optstr; | 
 
 
 
 
 
 | 2984 | 
           my_optstr = ""; | 
 
 
 
 
 
 | 2985 | 
  | 
 
 
 
 
 
 | 2986 | 
           /* Case 2-5 */ | 
 
 
 
 
 
 | 2987 | 
           if (*my_optarg == 0) | 
 
 
 
 
 
 | 2988 | 
             { | 
 
 
 
 
 
 | 2989 | 
               /* Condition 4-5 */ | 
 
 
 
 
 
 | 2990 | 
               int have_arg = my_optind < (argc - 1) && *argv[my_optind+1] != '-'; | 
 
 
 
 
 
 | 2991 | 
  | 
 
 
 
 
 
 | 2992 | 
               if (! have_arg) | 
 
 
 
 
 
 | 2993 | 
                 { | 
 
 
 
 
 
 | 2994 | 
                   if (! option) | 
 
 
 
 
 
 | 2995 | 
                   { | 
 
 
 
 
 
 | 2996 | 
                     /* Case 4 */ | 
 
 
 
 
 
 | 2997 | 
                     XPR(NT "-%c: requires an argument\n", ret); | 
 
 
 
 
 
 | 2998 | 
                     ret = EXIT_FAILURE; | 
 
 
 
 
 
 | 2999 | 
                     goto cleanup; | 
 
 
 
 
 
 | 3000 | 
                   } | 
 
 
 
 
 
 | 3001 | 
                   /* Case 5. */ | 
 
 
 
 
 
 | 3002 | 
                   my_optarg = NULL; | 
 
 
 
 
 
 | 3003 | 
                 } | 
 
 
 
 
 
 | 3004 | 
               else | 
 
 
 
 
 
 | 3005 | 
                 { | 
 
 
 
 
 
 | 3006 | 
                   /* Case 2-3. */ | 
 
 
 
 
 
 | 3007 | 
                   my_optarg = argv[++my_optind]; | 
 
 
 
 
 
 | 3008 | 
                 } | 
 
 
 
 
 
 | 3009 | 
             } | 
 
 
 
 
 
 | 3010 | 
           /* Case 6-8. */ | 
 
 
 
 
 
 | 3011 | 
           else if (*my_optarg == '=') | 
 
 
 
 
 
 | 3012 | 
             { | 
 
 
 
 
 
 | 3013 | 
               /* Remove the = in all cases. */ | 
 
 
 
 
 
 | 3014 | 
               my_optarg += 1; | 
 
 
 
 
 
 | 3015 | 
               eqcase = 1; | 
 
 
 
 
 
 | 3016 | 
  | 
 
 
 
 
 
 | 3017 | 
               if (option && *my_optarg == 0) | 
 
 
 
 
 
 | 3018 | 
                 { | 
 
 
 
 
 
 | 3019 | 
                   /* Case 8. */ | 
 
 
 
 
 
 | 3020 | 
                   my_optarg = NULL; | 
 
 
 
 
 
 | 3021 | 
                 } | 
 
 
 
 
 
 | 3022 | 
             } | 
 
 
 
 
 
 | 3023 | 
         } | 
 
 
 
 
 
 | 3024 | 
  | 
 
 
 
 
 
 | 3025 | 
       switch (ret) | 
 
 
 
 
 
 | 3026 | 
         { | 
 
 
 
 
 
 | 3027 | 
         /* case: if no '-' was found, maybe check for a command name. */ | 
 
 
 
 
 
 | 3028 | 
         nonflag: | 
 
 
 
 
 
 | 3029 | 
                if (strcmp (my_optstr, "decode") == 0) { cmd = CMD_DECODE; } | 
 
 
 
 
 
 | 3030 | 
           else if (strcmp (my_optstr, "encode") == 0) | 
 
 
 
 
 
 | 3031 | 
             { | 
 
 
 
 
 
 | 3032 | 
 #if XD3_ENCODER | 
 
 
 
 
 
 | 3033 | 
               cmd = CMD_ENCODE; | 
 
 
 
 
 
 | 3034 | 
 #else | 
 
 
 
 
 
 | 3035 | 
               XPR(NT "encoder support not compiled\n"); | 
 
 
 
 
 
 | 3036 | 
               return EXIT_FAILURE; | 
 
 
 
 
 
 | 3037 | 
 #endif | 
 
 
 
 
 
 | 3038 | 
             } | 
 
 
 
 
 
 | 3039 | 
           else if (strcmp (my_optstr, "config") == 0) { cmd = CMD_CONFIG; } | 
 
 
 
 
 
 | 3040 | 
 #if REGRESSION_TEST | 
 
 
 
 
 
 | 3041 | 
           else if (strcmp (my_optstr, "test") == 0) { cmd = CMD_TEST; } | 
 
 
 
 
 
 | 3042 | 
 #endif | 
 
 
 
 
 
 | 3043 | 
 #if VCDIFF_TOOLS | 
 
 
 
 
 
 | 3044 | 
           else if (strcmp (my_optstr, "printhdr") == 0) { cmd = CMD_PRINTHDR; } | 
 
 
 
 
 
 | 3045 | 
           else if (strcmp (my_optstr, "printhdrs") == 0) { cmd = CMD_PRINTHDRS; } | 
 
 
 
 
 
 | 3046 | 
           else if (strcmp (my_optstr, "printdelta") == 0) { cmd = CMD_PRINTDELTA; } | 
 
 
 
 
 
 | 3047 | 
 #endif | 
 
 
 
 
 
 | 3048 | 
  | 
 
 
 
 
 
 | 3049 | 
           /* If no option was found and still no command, let the default command be | 
 
 
 
 
 
 | 3050 | 
            * encode.  The remaining args are treated as filenames. */ | 
 
 
 
 
 
 | 3051 | 
           if (cmd == CMD_NONE) | 
 
 
 
 
 
 | 3052 | 
             { | 
 
 
 
 
 
 | 3053 | 
               cmd = CMD_DEFAULT; | 
 
 
 
 
 
 | 3054 | 
               my_optstr = NULL; | 
 
 
 
 
 
 | 3055 | 
               break; | 
 
 
 
 
 
 | 3056 | 
             } | 
 
 
 
 
 
 | 3057 | 
           else | 
 
 
 
 
 
 | 3058 | 
             { | 
 
 
 
 
 
 | 3059 | 
               /* But if we find a command name, continue the getopt loop. */ | 
 
 
 
 
 
 | 3060 | 
               my_optind += 1; | 
 
 
 
 
 
 | 3061 | 
               goto takearg; | 
 
 
 
 
 
 | 3062 | 
             } | 
 
 
 
 
 
 | 3063 | 
  | 
 
 
 
 
 
 | 3064 | 
           /* gzip-like options */ | 
 
 
 
 
 
 | 3065 | 
         case '0': case '1': case '2': case '3': case '4': | 
 
 
 
 
 
 | 3066 | 
         case '5': case '6': case '7': case '8': case '9': | 
 
 
 
 
 
 | 3067 | 
           option_level = ret - '0'; | 
 
 
 
 
 
 | 3068 | 
           break; | 
 
 
 
 
 
 | 3069 | 
         case 'f': option_force = 1; break; | 
 
 
 
 
 
 | 3070 | 
         case 'v': option_verbose += 1; option_quiet = 0; break; | 
 
 
 
 
 
 | 3071 | 
         case 'q': option_quiet = 1; option_verbose = 0; break; | 
 
 
 
 
 
 | 3072 | 
         case 'c': option_stdout = 1; break; | 
 
 
 
 
 
 | 3073 | 
         case 'd': | 
 
 
 
 
 
 | 3074 | 
           if (cmd == CMD_NONE) { cmd = CMD_DECODE; } | 
 
 
 
 
 
 | 3075 | 
           else { ret = main_help (); goto exit; } | 
 
 
 
 
 
 | 3076 | 
           break; | 
 
 
 
 
 
 | 3077 | 
         case 'e': | 
 
 
 
 
 
 | 3078 | 
 #if XD3_ENCODER | 
 
 
 
 
 
 | 3079 | 
           if (cmd == CMD_NONE) { cmd = CMD_ENCODE; } | 
 
 
 
 
 
 | 3080 | 
           else { ret = main_help (); goto exit; } | 
 
 
 
 
 
 | 3081 | 
           break; | 
 
 
 
 
 
 | 3082 | 
 #else | 
 
 
 
 
 
 | 3083 | 
           XPR(NT "encoder support not compiled\n"); | 
 
 
 
 
 
 | 3084 | 
           return EXIT_FAILURE; | 
 
 
 
 
 
 | 3085 | 
 #endif | 
 
 
 
 
 
 | 3086 | 
  | 
 
 
 
 
 
 | 3087 | 
         case 'n': option_use_checksum = 0; break; | 
 
 
 
 
 
 | 3088 | 
         case 'N': option_no_compress = 1; break; | 
 
 
 
 
 
 | 3089 | 
         case 'T': option_use_altcodetable = 1; break; | 
 
 
 
 
 
 | 3090 | 
         case 'C': option_smatch_config = my_optarg; break; | 
 
 
 
 
 
 | 3091 | 
         case 'J': option_no_output = 1; break; | 
 
 
 
 
 
 | 3092 | 
         case 'S': if (my_optarg == NULL) { option_use_secondary = 0; } | 
 
 
 
 
 
 | 3093 | 
                   else { option_use_secondary = 1; option_secondary = my_optarg; } break; | 
 
 
 
 
 
 | 3094 | 
         case 'A': if (my_optarg == NULL) { option_use_appheader = 0; } | 
 
 
 
 
 
 | 3095 | 
                   else { option_appheader = (uint8_t*) my_optarg; } break; | 
 
 
 
 
 
 | 3096 | 
         case 'B': | 
 
 
 
 
 
 | 3097 | 
           if ((ret = main_atou (my_optarg, & option_srcwinsz, XD3_MINSRCWINSZ, | 
 
 
 
 
 
 | 3098 | 
                                 0, 'B'))) | 
 
 
 
 
 
 | 3099 | 
             { | 
 
 
 
 
 
 | 3100 | 
               goto exit; | 
 
 
 
 
 
 | 3101 | 
             } | 
 
 
 
 
 
 | 3102 | 
           break; | 
 
 
 
 
 
 | 3103 | 
         case 'I': | 
 
 
 
 
 
 | 3104 | 
           if ((ret = main_atou (my_optarg, & option_iopt_size, 0, | 
 
 
 
 
 
 | 3105 | 
                                 0, 'I'))) | 
 
 
 
 
 
 | 3106 | 
             { | 
 
 
 
 
 
 | 3107 | 
               goto exit; | 
 
 
 
 
 
 | 3108 | 
             } | 
 
 
 
 
 
 | 3109 | 
           break; | 
 
 
 
 
 
 | 3110 | 
         case 'P': | 
 
 
 
 
 
 | 3111 | 
           if ((ret = main_atou (my_optarg, & option_sprevsz, 0, | 
 
 
 
 
 
 | 3112 | 
                                 0, 'P'))) | 
 
 
 
 
 
 | 3113 | 
             { | 
 
 
 
 
 
 | 3114 | 
               goto exit; | 
 
 
 
 
 
 | 3115 | 
             } | 
 
 
 
 
 
 | 3116 | 
           break; | 
 
 
 
 
 
 | 3117 | 
         case 'W': | 
 
 
 
 
 
 | 3118 | 
           if ((ret = main_atou (my_optarg, & option_winsize, XD3_ALLOCSIZE, | 
 
 
 
 
 
 | 3119 | 
                                 XD3_HARDMAXWINSIZE, 'W'))) | 
 
 
 
 
 
 | 3120 | 
           { | 
 
 
 
 
 
 | 3121 | 
             goto exit; | 
 
 
 
 
 
 | 3122 | 
           } | 
 
 
 
 
 
 | 3123 | 
           break; | 
 
 
 
 
 
 | 3124 | 
         case 'D': | 
 
 
 
 
 
 | 3125 | 
 #if EXTERNAL_COMPRESSION == 0 | 
 
 
 
 
 
 | 3126 | 
           if (option_verbose > 0) | 
 
 
 
 
 
 | 3127 | 
             { | 
 
 
 
 
 
 | 3128 | 
               XPR(NT "warning: -D option ignored, " | 
 
 
 
 
 
 | 3129 | 
                        "external compression support was not compiled\n"); | 
 
 
 
 
 
 | 3130 | 
             } | 
 
 
 
 
 
 | 3131 | 
 #else | 
 
 
 
 
 
 | 3132 | 
           option_decompress_inputs  = 0; | 
 
 
 
 
 
 | 3133 | 
 #endif | 
 
 
 
 
 
 | 3134 | 
           break; | 
 
 
 
 
 
 | 3135 | 
         case 'R': | 
 
 
 
 
 
 | 3136 | 
 #if EXTERNAL_COMPRESSION == 0 | 
 
 
 
 
 
 | 3137 | 
           if (option_verbose > 0) | 
 
 
 
 
 
 | 3138 | 
             { | 
 
 
 
 
 
 | 3139 | 
               XPR(NT "warning: -R option ignored, " | 
 
 
 
 
 
 | 3140 | 
                        "external compression support was not compiled\n"); | 
 
 
 
 
 
 | 3141 | 
             } | 
 
 
 
 
 
 | 3142 | 
 #else | 
 
 
 
 
 
 | 3143 | 
           option_recompress_outputs = 0; | 
 
 
 
 
 
 | 3144 | 
 #endif | 
 
 
 
 
 
 | 3145 | 
           break; | 
 
 
 
 
 
 | 3146 | 
         case 's': | 
 
 
 
 
 
 | 3147 | 
           if (sfilename != NULL) | 
 
 
 
 
 
 | 3148 | 
             { | 
 
 
 
 
 
 | 3149 | 
               XPR(NT "specify only one source file\n"); | 
 
 
 
 
 
 | 3150 | 
               goto cleanup; | 
 
 
 
 
 
 | 3151 | 
             } | 
 
 
 
 
 
 | 3152 | 
  | 
 
 
 
 
 
 | 3153 | 
           sfilename = my_optarg; | 
 
 
 
 
 
 | 3154 | 
           break; | 
 
 
 
 
 
 | 3155 | 
  | 
 
 
 
 
 
 | 3156 | 
         case 'V': | 
 
 
 
 
 
 | 3157 | 
           ret = main_version (); goto exit; | 
 
 
 
 
 
 | 3158 | 
         default: | 
 
 
 
 
 
 | 3159 | 
           ret = main_help (); goto exit; | 
 
 
 
 
 
 | 3160 | 
         } | 
 
 
 
 
 
 | 3161 | 
     } | 
 
 
 
 
 
 | 3162 | 
  | 
 
 
 
 
 
 | 3163 | 
   option_source_filename = sfilename; | 
 
 
 
 
 
 | 3164 | 
  | 
 
 
 
 
 
 | 3165 | 
   /* In case there were no arguments, set the default command. */ | 
 
 
 
 
 
 | 3166 | 
   if (cmd == CMD_NONE) { cmd = CMD_DEFAULT; } | 
 
 
 
 
 
 | 3167 | 
  | 
 
 
 
 
 
 | 3168 | 
   argc -= my_optind; | 
 
 
 
 
 
 | 3169 | 
   argv += my_optind; | 
 
 
 
 
 
 | 3170 | 
  | 
 
 
 
 
 
 | 3171 | 
   /* There may be up to two more arguments. */ | 
 
 
 
 
 
 | 3172 | 
   if (argc > 2) | 
 
 
 
 
 
 | 3173 | 
     { | 
 
 
 
 
 
 | 3174 | 
       XPR(NT "too many filenames: %s ...\n", argv[2]); | 
 
 
 
 
 
 | 3175 | 
       ret = EXIT_FAILURE; | 
 
 
 
 
 
 | 3176 | 
       goto cleanup; | 
 
 
 
 
 
 | 3177 | 
     } | 
 
 
 
 
 
 | 3178 | 
  | 
 
 
 
 
 
 | 3179 | 
   ifile.flags    = RD_FIRST; | 
 
 
 
 
 
 | 3180 | 
   sfile.flags    = RD_FIRST; | 
 
 
 
 
 
 | 3181 | 
   sfile.filename = option_source_filename; | 
 
 
 
 
 
 | 3182 | 
  | 
 
 
 
 
 
 | 3183 | 
   /* The infile takes the next argument, if there is one.  But if not, infile is set to | 
 
 
 
 
 
 | 3184 | 
    * stdin. */ | 
 
 
 
 
 
 | 3185 | 
   if (argc > 0) | 
 
 
 
 
 
 | 3186 | 
     { | 
 
 
 
 
 
 | 3187 | 
       ifile.filename = argv[0]; | 
 
 
 
 
 
 | 3188 | 
  | 
 
 
 
 
 
 | 3189 | 
       if ((ret = main_file_open (& ifile, ifile.filename, XO_READ))) | 
 
 
 
 
 
 | 3190 | 
         { | 
 
 
 
 
 
 | 3191 | 
           goto cleanup; | 
 
 
 
 
 
 | 3192 | 
         } | 
 
 
 
 
 
 | 3193 | 
     } | 
 
 
 
 
 
 | 3194 | 
   else | 
 
 
 
 
 
 | 3195 | 
     { | 
 
 
 
 
 
 | 3196 | 
       XSTDIN_XF (& ifile); | 
 
 
 
 
 
 | 3197 | 
     } | 
 
 
 
 
 
 | 3198 | 
  | 
 
 
 
 
 
 | 3199 | 
   /* The ofile takes the following argument, if there is one.  But if not, it is left NULL | 
 
 
 
 
 
 | 3200 | 
    * until the application header is processed.  It will be set in main_open_output. */ | 
 
 
 
 
 
 | 3201 | 
   if (argc > 1) | 
 
 
 
 
 
 | 3202 | 
     { | 
 
 
 
 
 
 | 3203 | 
       /* Check for conflicting arguments. */ | 
 
 
 
 
 
 | 3204 | 
       if (option_stdout && ! option_quiet) | 
 
 
 
 
 
 | 3205 | 
         { | 
 
 
 
 
 
 | 3206 | 
           XPR(NT "warning: -c option overrides output filename: %s\n", argv[1]); | 
 
 
 
 
 
 | 3207 | 
         } | 
 
 
 
 
 
 | 3208 | 
  | 
 
 
 
 
 
 | 3209 | 
       if (! option_stdout) { ofile.filename = argv[1]; } | 
 
 
 
 
 
 | 3210 | 
     } | 
 
 
 
 
 
 | 3211 | 
  | 
 
 
 
 
 
 | 3212 | 
   switch (cmd) | 
 
 
 
 
 
 | 3213 | 
     { | 
 
 
 
 
 
 | 3214 | 
     case CMD_PRINTHDR: | 
 
 
 
 
 
 | 3215 | 
     case CMD_PRINTHDRS: | 
 
 
 
 
 
 | 3216 | 
     case CMD_PRINTDELTA: | 
 
 
 
 
 
 | 3217 | 
 #if XD3_ENCODER | 
 
 
 
 
 
 | 3218 | 
     case CMD_ENCODE: | 
 
 
 
 
 
 | 3219 | 
 #endif | 
 
 
 
 
 
 | 3220 | 
     case CMD_DECODE: | 
 
 
 
 
 
 | 3221 | 
       ret = main_input (cmd, & ifile, & ofile, & sfile); | 
 
 
 
 
 
 | 3222 | 
       break; | 
 
 
 
 
 
 | 3223 | 
  | 
 
 
 
 
 
 | 3224 | 
 #if REGRESSION_TEST | 
 
 
 
 
 
 | 3225 | 
     case CMD_TEST: | 
 
 
 
 
 
 | 3226 | 
       ret = xd3_selftest (); | 
 
 
 
 
 
 | 3227 | 
       break; | 
 
 
 
 
 
 | 3228 | 
 #endif | 
 
 
 
 
 
 | 3229 | 
  | 
 
 
 
 
 
 | 3230 | 
     case CMD_CONFIG: | 
 
 
 
 
 
 | 3231 | 
       ret = main_config (); | 
 
 
 
 
 
 | 3232 | 
       break; | 
 
 
 
 
 
 | 3233 | 
  | 
 
 
 
 
 
 | 3234 | 
     default: | 
 
 
 
 
 
 | 3235 | 
       ret = main_help (); | 
 
 
 
 
 
 | 3236 | 
       break; | 
 
 
 
 
 
 | 3237 | 
     } | 
 
 
 
 
 
 | 3238 | 
  | 
 
 
 
 
 
 | 3239 | 
 #if EXTERNAL_COMPRESSION | 
 
 
 
 
 
 | 3240 | 
   if (ext_tmpfile != NULL) | 
 
 
 
 
 
 | 3241 | 
     { | 
 
 
 
 
 
 | 3242 | 
       unlink (ext_tmpfile); | 
 
 
 
 
 
 | 3243 | 
     } | 
 
 
 
 
 
 | 3244 | 
 #endif | 
 
 
 
 
 
 | 3245 | 
  | 
 
 
 
 
 
 | 3246 | 
   if (0) | 
 
 
 
 
 
 | 3247 | 
     { | 
 
 
 
 
 
 | 3248 | 
     cleanup: | 
 
 
 
 
 
 | 3249 | 
       ret = EXIT_FAILURE; | 
 
 
 
 
 
 | 3250 | 
     exit: | 
 
 
 
 
 
 | 3251 | 
       (void)0; | 
 
 
 
 
 
 | 3252 | 
     } | 
 
 
 
 
 
 | 3253 | 
  | 
 
 
 
 
 
 | 3254 | 
   main_file_cleanup (& ifile); | 
 
 
 
 
 
 | 3255 | 
   main_file_cleanup (& ofile); | 
 
 
 
 
 
 | 3256 | 
   main_file_cleanup (& sfile); | 
 
 
 
 
 
 | 3257 | 
  | 
 
 
 
 
 
 | 3258 | 
   main_free (free_argv); | 
 
 
 
 
 
 | 3259 | 
   main_free (free_value); | 
 
 
 
 
 
 | 3260 | 
  | 
 
 
 
 
 
 | 3261 | 
   main_cleanup (); | 
 
 
 
 
 
 | 3262 | 
  | 
 
 
 
 
 
 | 3263 | 
   fflush (stdout); | 
 
 
 
 
 
 | 3264 | 
   fflush (stderr); | 
 
 
 
 
 
 | 3265 | 
   return ret; | 
 
 
 
 
 
 | 3266 | 
 } | 
 
 
 
 
 
 | 3267 | 
  | 
 
 
 
 
 
 | 3268 | 
 static int | 
 
 
 
 
 
 | 3269 | 
 main_help (void) | 
 
 
 
 
 
 | 3270 | 
 { | 
 
 
 
 
 
 | 3271 | 
   /* Note: update wiki when command-line features change */ | 
 
 
 
 
 
 | 3272 | 
   main_version (); | 
 
 
 
 
 
 | 3273 | 
   DP(RINT "usage: xdelta3 [command/options] [input [output]]\n"); | 
 
 
 
 
 
 | 3274 | 
   DP(RINT "special command names:\n"); | 
 
 
 
 
 
 | 3275 | 
   DP(RINT "    config      prints xdelta3 configuration\n"); | 
 
 
 
 
 
 | 3276 | 
   DP(RINT "    decode      decompress the input\n"); | 
 
 
 
 
 
 | 3277 | 
   DP(RINT "    encode      compress the input%s\n", XD3_ENCODER ? "" : " [Not compiled]"); | 
 
 
 
 
 
 | 3278 | 
 #if REGRESSION_TEST | 
 
 
 
 
 
 | 3279 | 
   DP(RINT "    test        run the builtin tests\n"); | 
 
 
 
 
 
 | 3280 | 
 #endif | 
 
 
 
 
 
 | 3281 | 
 #if VCDIFF_TOOLS | 
 
 
 
 
 
 | 3282 | 
   DP(RINT "special commands for VCDIFF inputs:\n"); | 
 
 
 
 
 
 | 3283 | 
   DP(RINT "    printdelta  print information about the entire delta\n"); | 
 
 
 
 
 
 | 3284 | 
   DP(RINT "    printhdr    print information about the first window\n"); | 
 
 
 
 
 
 | 3285 | 
   DP(RINT "    printhdrs   print information about all windows\n"); | 
 
 
 
 
 
 | 3286 | 
 #endif | 
 
 
 
 
 
 | 3287 | 
   DP(RINT "standard options:\n"); | 
 
 
 
 
 
 | 3288 | 
   DP(RINT "   -0 .. -9     compression level\n"); | 
 
 
 
 
 
 | 3289 | 
   DP(RINT "   -c           use stdout\n"); | 
 
 
 
 
 
 | 3290 | 
   DP(RINT "   -d           decompress\n"); | 
 
 
 
 
 
 | 3291 | 
   DP(RINT "   -e           compress%s\n", XD3_ENCODER ? "" : " [Not compiled]"); | 
 
 
 
 
 
 | 3292 | 
   DP(RINT "   -f           force overwrite\n"); | 
 
 
 
 
 
 | 3293 | 
   DP(RINT "   -h           show help\n"); | 
 
 
 
 
 
 | 3294 | 
   DP(RINT "   -q           be quiet\n"); | 
 
 
 
 
 
 | 3295 | 
   DP(RINT "   -v           be verbose (max 2)\n"); | 
 
 
 
 
 
 | 3296 | 
   DP(RINT "   -V           show version\n"); | 
 
 
 
 
 
 | 3297 | 
  | 
 
 
 
 
 
 | 3298 | 
   DP(RINT "memory options:\n"); | 
 
 
 
 
 
 | 3299 | 
   DP(RINT "   -B bytes     source window size\n"); | 
 
 
 
 
 
 | 3300 | 
   DP(RINT "   -W bytes     input window size\n"); | 
 
 
 
 
 
 | 3301 | 
   DP(RINT "   -P size      compression duplicates window\n"); | 
 
 
 
 
 
 | 3302 | 
   DP(RINT "   -I size      instruction buffer size (0 = unlimited)\n"); | 
 
 
 
 
 
 | 3303 | 
  | 
 
 
 
 
 
 | 3304 | 
   DP(RINT "compression options:\n"); | 
 
 
 
 
 
 | 3305 | 
   DP(RINT "   -s source    source file to copy from (if any)\n"); | 
 
 
 
 
 
 | 3306 | 
   DP(RINT "   -S [djw|fgk] enable/disable secondary compression\n"); | 
 
 
 
 
 
 | 3307 | 
   DP(RINT "   -N           disable small string-matching compression\n"); | 
 
 
 
 
 
 | 3308 | 
   DP(RINT "   -D           disable external decompression (encode/decode)\n"); | 
 
 
 
 
 
 | 3309 | 
   DP(RINT "   -R           disable external recompression (decode)\n"); | 
 
 
 
 
 
 | 3310 | 
   DP(RINT "   -n           disable checksum (encode/decode)\n"); | 
 
 
 
 
 
 | 3311 | 
   DP(RINT "   -C           soft config (encode, undocumented)\n"); | 
 
 
 
 
 
 | 3312 | 
   DP(RINT "   -A [apphead] disable/provide application header (encode)\n"); | 
 
 
 
 
 
 | 3313 | 
  | 
 
 
 
 
 
 | 3314 | 
 #if XD3_DEBUG > 0 | 
 
 
 
 
 
 | 3315 | 
   DP(RINT "developer options:\n"); | 
 
 
 
 
 
 | 3316 | 
   DP(RINT "   -J           disable output (check/compute only)\n"); | 
 
 
 
 
 
 | 3317 | 
   DP(RINT "   -P           repeat count (for profiling)\n"); | 
 
 
 
 
 
 | 3318 | 
   DP(RINT "   -T           use alternate code table\n"); | 
 
 
 
 
 
 | 3319 | 
 #endif | 
 
 
 
 
 
 | 3320 | 
  | 
 
 
 
 
 
 | 3321 | 
   DP(RINT "the XDELTA environment variable may contain extra args:\n"); | 
 
 
 
 
 
 | 3322 | 
   DP(RINT "   XDELTA=\"-s source-x.y.tar.gz\" \\\n"); | 
 
 
 
 
 
 | 3323 | 
   DP(RINT "   tar --use-compress-program=xdelta3 \\\n"); | 
 
 
 
 
 
 | 3324 | 
   DP(RINT "       -cf target-x.z.tar.gz.vcdiff target-x.y/\n"); | 
 
 
 
 
 
 | 3325 | 
   return EXIT_FAILURE; | 
 
 
 
 
 
 | 3326 | 
 } | 
 
 
 
 
 
 | 3327 | 
  |