"Fossies" - the Fresh Open Source Software Archive

Member "xdelta3-3.0.11/xdelta3-test.h" (11 Nov 2015, 79629 Bytes) of package /linux/misc/xdelta3-3.0.11.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "xdelta3-test.h" see the Fossies "Dox" file reference documentation.

    1 /* xdelta 3 - delta compression tools and library Copyright (C) 2001,
    2  * 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012.
    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 public-domain Mersenne Twister code,
   21  * attributed to Michael Brundage.  Thanks!
   22  * http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation.html
   23  */
   24 static const uint32_t TEST_SEED1 = 5489UL;
   25 #define MT_LEN 624
   26 #define MT_IA 397
   27 static const uint32_t UPPER_MASK = 0x80000000;
   28 static const uint32_t LOWER_MASK = 0x7FFFFFFF;
   29 static const uint32_t MATRIX_A = 0x9908B0DF;
   30 
   31 #ifndef SHELL_TESTS
   32 #define SHELL_TESTS 1
   33 #endif
   34 
   35 typedef struct mtrand mtrand;
   36 
   37 struct mtrand {
   38   int mt_index_;
   39   uint32_t mt_buffer_[MT_LEN];
   40 };
   41 
   42 int test_compare_files (const char* tgt, const char *rec);
   43 void mt_init(mtrand *mt, uint32_t seed);
   44 uint32_t mt_random (mtrand *mt);
   45 int test_setup (void);
   46 
   47 void mt_init(mtrand *mt, uint32_t seed) {
   48   int i;
   49   mt->mt_buffer_[0] = seed;
   50   mt->mt_index_ = MT_LEN;
   51   for (i = 1; i < MT_LEN; i++) {
   52     /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
   53     /* In the previous versions, MSBs of the seed affect   */
   54     /* only MSBs of the array mt[].                        */
   55     /* 2002/01/09 modified by Makoto Matsumoto             */
   56     mt->mt_buffer_[i] =
   57     (1812433253UL * (mt->mt_buffer_[i-1] ^
   58              (mt->mt_buffer_[i-1] >> 30)) + i);
   59   }
   60 }
   61 
   62 uint32_t mt_random (mtrand *mt) {
   63   uint32_t y;
   64   unsigned long mag01[2];
   65   mag01[0] = 0;
   66   mag01[1] = MATRIX_A;
   67 
   68   if (mt->mt_index_ >= MT_LEN) {
   69     int kk;
   70 
   71     for (kk = 0; kk < MT_LEN - MT_IA; kk++) {
   72       y = (mt->mt_buffer_[kk] & UPPER_MASK) |
   73     (mt->mt_buffer_[kk + 1] & LOWER_MASK);
   74       mt->mt_buffer_[kk] = mt->mt_buffer_[kk + MT_IA] ^
   75     (y >> 1) ^ mag01[y & 0x1UL];
   76     }
   77     for (;kk < MT_LEN - 1; kk++) {
   78       y = (mt->mt_buffer_[kk] & UPPER_MASK) |
   79     (mt->mt_buffer_[kk + 1] & LOWER_MASK);
   80       mt->mt_buffer_[kk] = mt->mt_buffer_[kk + (MT_IA - MT_LEN)] ^
   81     (y >> 1) ^ mag01[y & 0x1UL];
   82     }
   83     y = (mt->mt_buffer_[MT_LEN - 1] & UPPER_MASK) |
   84       (mt->mt_buffer_[0] & LOWER_MASK);
   85     mt->mt_buffer_[MT_LEN - 1] = mt->mt_buffer_[MT_IA - 1] ^
   86       (y >> 1) ^ mag01[y & 0x1UL];
   87     mt->mt_index_ = 0;
   88   }
   89 
   90   y = mt->mt_buffer_[mt->mt_index_++];
   91 
   92   y ^= (y >> 11);
   93   y ^= (y << 7) & 0x9d2c5680UL;
   94   y ^= (y << 15) & 0xefc60000UL;
   95   y ^= (y >> 18);
   96 
   97   return y;
   98 }
   99 
  100 static mtrand static_mtrand;
  101 
  102 #include <math.h>
  103 
  104 static uint32_t
  105 mt_exp_rand (uint32_t mean, uint32_t max_value)
  106 {
  107   double mean_d = mean;
  108   double erand  = log (1.0 / (mt_random (&static_mtrand) /
  109                   (double)UINT32_MAX));
  110   uint32_t x = (uint32_t) (mean_d * erand + 0.5);
  111 
  112   return xd3_min (x, max_value);
  113 }
  114 
  115 #if SHELL_TESTS
  116 #include <sys/wait.h>
  117 #endif
  118 
  119 #define MSG_IS(x) (stream->msg != NULL && strcmp ((x), stream->msg) == 0)
  120 
  121 static const usize_t TWO_MEGS_AND_DELTA = (3 << 20);
  122 static const usize_t ADDR_CACHE_ROUNDS = 10000;
  123 
  124 static const usize_t TEST_FILE_MEAN   = 16384;
  125 static const double TEST_ADD_MEAN     = 128;
  126 static const double TEST_ADD_MAX      = 512;
  127 static const double TEST_ADD_RATIO    = 0.1;
  128 static const double TEST_EPSILON      = 0.25;
  129 
  130 #define TESTBUFSIZE (1024 * 16)
  131 
  132 #define TESTFILESIZE (1024)
  133 
  134 static char   TEST_TARGET_FILE[TESTFILESIZE];
  135 static char   TEST_SOURCE_FILE[TESTFILESIZE];
  136 static char   TEST_DELTA_FILE[TESTFILESIZE];
  137 static char   TEST_RECON_FILE[TESTFILESIZE];
  138 static char   TEST_RECON2_FILE[TESTFILESIZE];
  139 static char   TEST_COPY_FILE[TESTFILESIZE];
  140 static char   TEST_NOPERM_FILE[TESTFILESIZE];
  141 
  142 #define CHECK(cond) if (!(cond)) { XPR(NT "check failure: " #cond); abort(); }
  143 
  144 #if SHELL_TESTS
  145 /* Use a fixed soft config so that test values are fixed.  See also
  146  * test_compress_text(). */
  147 static const char* test_softcfg_str = "-C9,3,4,8,2,36,70";
  148 #endif
  149 
  150 /***********************************************************************
  151  TEST HELPERS
  152  ***********************************************************************/
  153 
  154 static void DOT (void) { XPR(NTR "."); }
  155 static int do_cmd (xd3_stream *stream, const char *buf)
  156 {
  157   int ret;
  158   if ((ret = system (buf)) != 0)
  159     {
  160       if (WIFEXITED (ret))
  161     {
  162       stream->msg = "command exited non-zero";
  163       IF_DEBUG1 (XPR(NT "command was: %s\n", buf));
  164     }
  165       else
  166     {
  167       stream->msg = "abnormal command termination";
  168     }
  169       return ret;
  170     }
  171   return 0;
  172 }
  173 
  174 static int do_fail (xd3_stream *stream, const char *buf)
  175 {
  176   int ret;
  177   ret = system (buf);
  178   if (! WIFEXITED (ret) || WEXITSTATUS (ret) != 1)
  179     {
  180       stream->msg = "command should have not succeeded";
  181       XPR(NT "command was %s\n", buf);
  182       return XD3_INTERNAL;
  183     }
  184   return 0;
  185 }
  186 
  187 /* Test that the exponential distribution actually produces its mean. */
  188 static int
  189 test_random_numbers (xd3_stream *stream, int ignore)
  190 {
  191   usize_t i;
  192   usize_t sum = 0;
  193   usize_t mean = 50;
  194   usize_t n_rounds = 1000000;
  195   double average, error;
  196   double allowed_error = 0.1;
  197 
  198   mt_init (& static_mtrand, 0x9f73f7fe);
  199 
  200   for (i = 0; i < n_rounds; i += 1)
  201     {
  202       sum += mt_exp_rand (mean, USIZE_T_MAX);
  203     }
  204 
  205   average = (double) sum / (double) n_rounds;
  206   error   = average - (double) mean;
  207 
  208   if (error < allowed_error && error > -allowed_error)
  209     {
  210       return 0;
  211     }
  212 
  213   /*XPR(NT "error is %f\n", error);*/
  214   stream->msg = "random distribution looks broken";
  215   return XD3_INTERNAL;
  216 }
  217 
  218 static int
  219 test_printf_xoff (xd3_stream *stream, int ignore)
  220 {
  221   char buf[64];
  222   xoff_t x = XOFF_T_MAX;
  223   snprintf_func (buf, sizeof(buf), "%"Q"u", x);
  224   const char *expect = XD3_USE_LARGEFILE64 ?
  225     "18446744073709551615" : "4294967295";
  226   if (strcmp (buf, expect) == 0) {
  227     return 0;
  228   }
  229   return XD3_INTERNAL;
  230 }
  231 
  232 static void
  233 test_unlink (char* file)
  234 {
  235   int ret;
  236   if (file != NULL && *file != 0 &&
  237       (ret = unlink (file)) != 0 && errno != ENOENT)
  238     {
  239       XPR(NT "unlink %s failed: %s\n", file, strerror(ret));
  240     }
  241 }
  242 
  243 static void
  244 test_cleanup (void)
  245 {
  246 #if 1
  247   test_unlink (TEST_TARGET_FILE);
  248   test_unlink (TEST_SOURCE_FILE);
  249   test_unlink (TEST_DELTA_FILE);
  250   test_unlink (TEST_RECON_FILE);
  251   test_unlink (TEST_RECON2_FILE);
  252   test_unlink (TEST_COPY_FILE);
  253   test_unlink (TEST_NOPERM_FILE);
  254 #endif
  255 }
  256 
  257 int test_setup (void)
  258 {
  259   static int x = 0;
  260   pid_t pid = getpid();
  261   x++;
  262 
  263   test_cleanup();
  264 
  265   snprintf_func (TEST_TARGET_FILE, TESTFILESIZE,
  266          "/tmp/xdtest.%d.target.%d", pid, x);
  267   snprintf_func (TEST_SOURCE_FILE, TESTFILESIZE,
  268          "/tmp/xdtest.%d.source.%d", pid, x);
  269   snprintf_func (TEST_DELTA_FILE, TESTFILESIZE,
  270          "/tmp/xdtest.%d.delta.%d", pid, x);
  271   snprintf_func (TEST_RECON_FILE, TESTFILESIZE,
  272          "/tmp/xdtest.%d.recon.%d", pid, x);
  273   snprintf_func (TEST_RECON2_FILE, TESTFILESIZE,
  274          "/tmp/xdtest.%d.recon2.%d", pid, x);
  275   snprintf_func (TEST_COPY_FILE, TESTFILESIZE,
  276          "/tmp/xdtest.%d.copy.%d", pid, x);
  277   snprintf_func (TEST_NOPERM_FILE, TESTFILESIZE,
  278          "/tmp/xdtest.%d.noperm.%d", pid, x);
  279 
  280   test_cleanup();
  281   return 0;
  282 }
  283 
  284 static int
  285 test_make_inputs (xd3_stream *stream, xoff_t *ss_out, xoff_t *ts_out)
  286 {
  287   usize_t ts = (mt_random (&static_mtrand) % TEST_FILE_MEAN) +
  288     TEST_FILE_MEAN / 2;
  289   usize_t ss = (mt_random (&static_mtrand) % TEST_FILE_MEAN) +
  290     TEST_FILE_MEAN / 2;
  291   uint8_t *buf = (uint8_t*) malloc (ts + ss), *sbuf = buf, *tbuf = buf + ss;
  292   usize_t sadd = 0, sadd_max = (usize_t)(ss * TEST_ADD_RATIO);
  293   FILE  *tf = NULL, *sf = NULL;
  294   usize_t i, j;
  295   int ret;
  296 
  297   if (buf == NULL) { return ENOMEM; }
  298 
  299   if ((tf = fopen (TEST_TARGET_FILE, "w")) == NULL ||
  300       (ss_out != NULL && (sf = fopen (TEST_SOURCE_FILE, "w")) == NULL))
  301     {
  302       stream->msg = "write failed";
  303       ret = get_errno ();
  304       goto failure;
  305     }
  306 
  307   if (ss_out != NULL)
  308     {
  309       for (i = 0; i < ss; )
  310     {
  311       sbuf[i++] = (uint8_t) mt_random (&static_mtrand);
  312     }
  313     }
  314 
  315   /* Then modify the data to produce copies, everything not copied is
  316    * an add.  The following logic produces the TEST_ADD_RATIO.  The
  317    * variable SADD contains the number of adds so far, which should
  318    * not exceed SADD_MAX. */
  319 
  320   /* XPR(NT "ss = %u ts = %u\n", ss, ts); */
  321   for (i = 0; i < ts; )
  322     {
  323       usize_t left = ts - i;
  324       usize_t next = mt_exp_rand ((uint32_t) TEST_ADD_MEAN,
  325                   (uint32_t) TEST_ADD_MAX);
  326       usize_t add_left = sadd_max - sadd;
  327       double add_prob = (left == 0) ? 0 : (add_left / (double) left);
  328       int do_copy;
  329 
  330       next = xd3_min (left, next);
  331       do_copy = (next > add_left ||
  332          (mt_random (&static_mtrand) / \
  333           (double)USIZE_T_MAX) >= add_prob);
  334 
  335       if (ss_out == NULL)
  336     {
  337       do_copy &= (i > 0);
  338     }
  339       else
  340     {
  341       do_copy &= (ss - next) > 0;
  342     }
  343 
  344       if (do_copy)
  345     {
  346       /* Copy */
  347       size_t offset = mt_random (&static_mtrand) % ((ss_out == NULL) ?
  348                             i :
  349                             (ss - next));
  350       /* XPR(NT "[%u] copy %u at %u ", i, next, offset); */
  351 
  352       for (j = 0; j < next; j += 1)
  353         {
  354           char c = ((ss_out == NULL) ? tbuf : sbuf)[offset + j];
  355           /* XPR(NT "%x%x", (c >> 4) & 0xf, c & 0xf); */
  356           tbuf[i++] = c;
  357         }
  358       /* XPR(NT "\n"); */
  359     }
  360       else
  361     {
  362       /* Add */
  363       /* XPR(NT "[%u] add %u ", i, next); */
  364       for (j = 0; j < next; j += 1)
  365         {
  366           char c = (char) mt_random (&static_mtrand);
  367           /* XPR(NT "%x%x", (c >> 4) & 0xf, c & 0xf); */
  368           tbuf[i++] = c;
  369         }
  370       /* XPR(NT "\n"); */
  371       sadd += next;
  372     }
  373     }
  374 
  375   /* XPR(NT "sadd = %u max = %u\n", sadd, sadd_max); */
  376 
  377   if ((fwrite (tbuf, 1, ts, tf) != ts) ||
  378       (ss_out != NULL && (fwrite (sbuf, 1, ss, sf) != ss)))
  379     {
  380       stream->msg = "write failed";
  381       ret = get_errno ();
  382       goto failure;
  383     }
  384 
  385   if ((ret = fclose (tf)) || (ss_out != NULL && (ret = fclose (sf))))
  386     {
  387       stream->msg = "close failed";
  388       ret = get_errno ();
  389       goto failure;
  390     }
  391 
  392   if (ts_out) { (*ts_out) = ts; }
  393   if (ss_out) { (*ss_out) = ss; }
  394 
  395  failure:
  396   free (buf);
  397   return ret;
  398 }
  399 
  400 int
  401 test_compare_files (const char* tgt, const char *rec)
  402 {
  403   FILE *orig, *recons;
  404   static uint8_t obuf[TESTBUFSIZE], rbuf[TESTBUFSIZE];
  405   xoff_t offset = 0;
  406   size_t i;
  407   size_t oc, rc;
  408   xoff_t diffs = 0;
  409 
  410   if ((orig = fopen (tgt, "r")) == NULL)
  411     {
  412       XPR(NT "open %s failed\n", tgt);
  413       return get_errno ();
  414     }
  415 
  416   if ((recons = fopen (rec, "r")) == NULL)
  417     {
  418       XPR(NT "open %s failed\n", rec);
  419       return get_errno ();
  420     }
  421 
  422   for (;;)
  423     {
  424       oc = fread (obuf, 1, TESTBUFSIZE, orig);
  425       rc = fread (rbuf, 1, TESTBUFSIZE, recons);
  426 
  427       if (oc != rc)
  428     {
  429       return XD3_INTERNAL;
  430     }
  431 
  432       if (oc == 0)
  433     {
  434       break;
  435     }
  436 
  437       for (i = 0; i < oc; i += 1)
  438     {
  439       if (obuf[i] != rbuf[i])
  440         {
  441           XPR(NT "byte %u (read %u @ %"Q"u) %d != %d\n",
  442           (int)i, (int)oc, offset, obuf[i], rbuf[i]);
  443           diffs++;
  444           return XD3_INTERNAL;
  445         }
  446     }
  447 
  448       offset += oc;
  449     }
  450 
  451     fclose (orig);
  452     fclose (recons);
  453     if (diffs != 0)
  454       {
  455     return XD3_INTERNAL;
  456       }
  457     return 0;
  458 }
  459 
  460 static int
  461 test_copy_to (const char *from, const char *to)
  462 {
  463   char buf[TESTBUFSIZE];
  464   int ret;
  465 
  466   snprintf_func (buf, TESTBUFSIZE, "cp -f %s %s", from, to);
  467 
  468   if ((ret = system (buf)) != 0)
  469     {
  470       return XD3_INTERNAL;
  471     }
  472 
  473   return 0;
  474 }
  475 
  476 static int
  477 test_save_copy (const char *origname)
  478 {
  479   return test_copy_to(origname, TEST_COPY_FILE);
  480 }
  481 
  482 static int
  483 test_file_size (const char* file, xoff_t *size)
  484 {
  485   struct stat sbuf;
  486   int ret;
  487   (*size) = 0;
  488 
  489   if (stat (file, & sbuf) < 0)
  490     {
  491       ret = get_errno ();
  492       XPR(NT "stat failed: %s: %s\n", file, strerror (ret));
  493       return ret;
  494     }
  495 
  496   if (! S_ISREG (sbuf.st_mode))
  497     {
  498       ret = XD3_INTERNAL;
  499       XPR(NT "not a regular file: %s: %s\n", file, strerror (ret));
  500       return ret;
  501     }
  502 
  503   (*size) = sbuf.st_size;
  504   return 0;
  505 }
  506 
  507 /***********************************************************************
  508  READ OFFSET
  509  ***********************************************************************/
  510 
  511 /* Common test for read_integer errors: encodes a 64-bit value and
  512  * then attempts to read as a 32-bit value.  If TRUNC is non-zero,
  513  * attempts to get errors by shortening the input, otherwise it should
  514  * overflow.  Expects XD3_INTERNAL and MSG. */
  515 static int
  516 test_read_integer_error (xd3_stream *stream, usize_t trunto, const char *msg)
  517 {
  518   uint64_t eval = 1ULL << 34;
  519   uint32_t rval;
  520   xd3_output *buf = NULL;
  521   const uint8_t *max;
  522   const uint8_t *inp;
  523   int ret;
  524 
  525   buf = xd3_alloc_output (stream, buf);
  526 
  527   if ((ret = xd3_emit_uint64_t (stream, & buf, eval)))
  528     {
  529       goto fail;
  530     }
  531 
  532  again:
  533 
  534   inp = buf->base;
  535   max = buf->base + buf->next - trunto;
  536 
  537   if ((ret = xd3_read_uint32_t (stream, & inp, max, & rval)) !=
  538       XD3_INVALID_INPUT ||
  539       !MSG_IS (msg))
  540     {
  541       ret = XD3_INTERNAL;
  542     }
  543   else if (trunto && trunto < buf->next)
  544     {
  545       trunto += 1;
  546       goto again;
  547     }
  548   else
  549     {
  550       ret = 0;
  551     }
  552 
  553  fail:
  554   xd3_free_output (stream, buf);
  555   return ret;
  556 }
  557 
  558 /* Test integer overflow using the above routine. */
  559 static int
  560 test_decode_integer_overflow (xd3_stream *stream, int unused)
  561 {
  562   return test_read_integer_error (stream, 0, "overflow in read_intger");
  563 }
  564 
  565 /* Test integer EOI using the above routine. */
  566 static int
  567 test_decode_integer_end_of_input (xd3_stream *stream, int unused)
  568 {
  569   return test_read_integer_error (stream, 1, "end-of-input in read_integer");
  570 }
  571 
  572 /* Test that emit_integer/decode_integer/sizeof_integer/read_integer
  573  * work on correct inputs.  Tests powers of (2^7), plus or minus, up
  574  * to the maximum value. */
  575 #define TEST_ENCODE_DECODE_INTEGER(TYPE,ONE,MAX) \
  576   xd3_output *rbuf = NULL; \
  577   xd3_output *dbuf = NULL; \
  578   TYPE values[64]; \
  579   usize_t nvalues = 0; \
  580   usize_t i; \
  581   int ret = 0; \
  582  \
  583   for (i = 0; i < (sizeof (TYPE) * 8); i += 7) \
  584     { \
  585       values[nvalues++] = (ONE << i) - ONE; \
  586       values[nvalues++] = (ONE << i); \
  587       values[nvalues++] = (ONE << i) + ONE; \
  588     } \
  589  \
  590   values[nvalues++] = MAX-ONE; \
  591   values[nvalues++] = MAX; \
  592  \
  593   rbuf = xd3_alloc_output (stream, rbuf); \
  594   dbuf = xd3_alloc_output (stream, dbuf); \
  595  \
  596   for (i = 0; i < nvalues; i += 1) \
  597     { \
  598       const uint8_t *max; \
  599       const uint8_t *inp; \
  600       TYPE val;         \
  601  \
  602       DOT (); \
  603       rbuf->next = 0; \
  604  \
  605       if ((ret = xd3_emit_ ## TYPE (stream, & rbuf, values[i])) || \
  606       (ret = xd3_emit_ ## TYPE (stream, & dbuf, values[i]))) \
  607     { \
  608       goto fail; \
  609     } \
  610  \
  611       inp = rbuf->base; \
  612       max = rbuf->base + rbuf->next; \
  613  \
  614       if (rbuf->next != xd3_sizeof_ ## TYPE (values[i])) \
  615     { \
  616       ret = XD3_INTERNAL; \
  617       goto fail; \
  618     } \
  619  \
  620       if ((ret = xd3_read_ ## TYPE (stream, & inp, max, & val))) \
  621     { \
  622       goto fail; \
  623     } \
  624  \
  625       if (val != values[i]) \
  626     { \
  627       ret = XD3_INTERNAL; \
  628       goto fail; \
  629     } \
  630  \
  631       DOT (); \
  632     } \
  633  \
  634   stream->next_in  = dbuf->base; \
  635   stream->avail_in = dbuf->next; \
  636  \
  637   for (i = 0; i < nvalues; i += 1) \
  638     { \
  639       TYPE val; \
  640  \
  641       if ((ret = xd3_decode_ ## TYPE (stream, & val))) \
  642         { \
  643           goto fail; \
  644         } \
  645  \
  646       if (val != values[i]) \
  647         { \
  648           ret = XD3_INTERNAL; \
  649           goto fail; \
  650         } \
  651     } \
  652  \
  653   if (stream->avail_in != 0) \
  654     { \
  655       ret = XD3_INTERNAL; \
  656       goto fail; \
  657     } \
  658  \
  659  fail: \
  660   xd3_free_output (stream, rbuf); \
  661   xd3_free_output (stream, dbuf); \
  662  \
  663   return ret
  664 
  665 static int
  666 test_encode_decode_uint32_t (xd3_stream *stream, int unused)
  667 {
  668   TEST_ENCODE_DECODE_INTEGER(uint32_t,1U,UINT32_MAX);
  669 }
  670 
  671 static int
  672 test_encode_decode_uint64_t (xd3_stream *stream, int unused)
  673 {
  674   TEST_ENCODE_DECODE_INTEGER(uint64_t,1ULL,UINT64_MAX);
  675 }
  676 
  677 static int
  678 test_usize_t_overflow (xd3_stream *stream, int unused)
  679 {
  680   if (USIZE_T_OVERFLOW (USIZE_T_MAX, 0)) { goto fail; }
  681   if (USIZE_T_OVERFLOW (0, USIZE_T_MAX)) { goto fail; }
  682   if (USIZE_T_OVERFLOW (USIZE_T_MAX / 2, USIZE_T_MAX / 2)) { goto fail; }
  683   if (USIZE_T_OVERFLOW (USIZE_T_MAX / 2, USIZE_T_MAX / 2 + 1)) { goto fail; }
  684 
  685   if (! USIZE_T_OVERFLOW (USIZE_T_MAX, 1)) { goto fail; }
  686   if (! USIZE_T_OVERFLOW (1, USIZE_T_MAX)) { goto fail; }
  687   if (! USIZE_T_OVERFLOW (USIZE_T_MAX / 2 + 1, USIZE_T_MAX / 2 + 1)) { goto fail; }
  688 
  689   return 0;
  690 
  691  fail:
  692   stream->msg = "incorrect overflow computation";
  693   return XD3_INTERNAL;
  694 }
  695 
  696 static int
  697 test_forward_match (xd3_stream *stream, int unused)
  698 {
  699   usize_t i;
  700   uint8_t buf1[256], buf2[256];
  701 
  702   memset(buf1, 0, 256);
  703   memset(buf2, 0, 256);
  704 
  705   for (i = 0; i < 256; i++)
  706     {
  707       CHECK(xd3_forward_match(buf1, buf2, i) == (int)i);
  708     }
  709 
  710   for (i = 0; i < 255; i++)
  711     {
  712       buf2[i] = 1;
  713       CHECK(xd3_forward_match(buf1, buf2, 256) == (int)i);
  714       buf2[i] = 0;
  715     }
  716 
  717   return 0;
  718 }
  719 
  720 /***********************************************************************
  721  Address cache
  722  ***********************************************************************/
  723 
  724 static int
  725 test_address_cache (xd3_stream *stream, int unused)
  726 {
  727   int ret;
  728   usize_t i;
  729   usize_t offset;
  730   usize_t *addrs;
  731   uint8_t *big_buf, *buf_max;
  732   const uint8_t *buf;
  733   xd3_output *outp;
  734   uint8_t *modes;
  735   int mode_counts[16];
  736 
  737   stream->acache.s_near = stream->code_table_desc->near_modes;
  738   stream->acache.s_same = stream->code_table_desc->same_modes;
  739 
  740   if ((ret = xd3_encode_init_partial (stream))) { return ret; }
  741 
  742   addrs = (usize_t*) xd3_alloc (stream, sizeof (usize_t), ADDR_CACHE_ROUNDS);
  743   modes = (uint8_t*) xd3_alloc (stream, sizeof (uint8_t), ADDR_CACHE_ROUNDS);
  744 
  745   memset (mode_counts, 0, sizeof (mode_counts));
  746   memset (modes, 0, ADDR_CACHE_ROUNDS);
  747 
  748   addrs[0] = 0;
  749 
  750   mt_init (& static_mtrand, 0x9f73f7fc);
  751 
  752   /* First pass: encode addresses */
  753   xd3_init_cache (& stream->acache);
  754 
  755   for (offset = 1; offset < ADDR_CACHE_ROUNDS; offset += 1)
  756     {
  757       double p;
  758       usize_t addr;
  759       usize_t prev_i;
  760       usize_t nearby;
  761 
  762       p         = (mt_random (&static_mtrand) / (double)USIZE_T_MAX);
  763       prev_i    = mt_random (&static_mtrand) % offset;
  764       nearby    = (mt_random (&static_mtrand) % 256) % offset;
  765       nearby    = xd3_max (1U, nearby);
  766 
  767       if (p < 0.1)      { addr = addrs[offset-nearby]; }
  768       else if (p < 0.4) { addr = xd3_min (addrs[prev_i] + nearby, offset-1); }
  769       else              { addr = prev_i; }
  770 
  771       if ((ret = xd3_encode_address (stream, addr, offset, & modes[offset]))) { return ret; }
  772 
  773       addrs[offset] = addr;
  774       mode_counts[modes[offset]] += 1;
  775     }
  776 
  777   /* Copy addresses into a contiguous buffer. */
  778   big_buf = (uint8_t*) xd3_alloc (stream, xd3_sizeof_output (ADDR_HEAD (stream)), 1);
  779 
  780   for (offset = 0, outp = ADDR_HEAD (stream); outp != NULL; offset += outp->next, outp = outp->next_page)
  781     {
  782       memcpy (big_buf + offset, outp->base, outp->next);
  783     }
  784 
  785   buf_max = big_buf + offset;
  786   buf     = big_buf;
  787 
  788   /* Second pass: decode addresses */
  789   xd3_init_cache (& stream->acache);
  790 
  791   for (offset = 1; offset < ADDR_CACHE_ROUNDS; offset += 1)
  792     {
  793       uint32_t addr;
  794 
  795       if ((ret = xd3_decode_address (stream, offset, modes[offset], & buf, buf_max, & addr))) { return ret; }
  796 
  797       if (addr != addrs[offset])
  798     {
  799       stream->msg = "incorrect decoded address";
  800       return XD3_INTERNAL;
  801     }
  802     }
  803 
  804   /* Check that every byte, mode was used. */
  805   if (buf != buf_max)
  806     {
  807       stream->msg = "address bytes not used";
  808       return XD3_INTERNAL;
  809     }
  810 
  811   for (i = 0; i < (2 + stream->acache.s_same + stream->acache.s_near); i += 1)
  812     {
  813       if (mode_counts[i] == 0)
  814     {
  815       stream->msg = "address mode not used";
  816       return XD3_INTERNAL;
  817     }
  818     }
  819 
  820   xd3_free (stream, modes);
  821   xd3_free (stream, addrs);
  822   xd3_free (stream, big_buf);
  823 
  824   return 0;
  825 }
  826 
  827 /***********************************************************************
  828  Encode and decode with single bit error
  829  ***********************************************************************/
  830 
  831 /* It compresses from 256 to around 185 bytes.
  832  * Avoids matching addresses that are a single-bit difference.
  833  * Avoids matching address 0. */
  834 static const uint8_t test_text[] =
  835 "this is a story\n"
  836 "abouttttttttttt\n"
  837 "- his is a stor\n"
  838 "- about nothing "
  839 " all. boutique -"
  840 "his story is a -"
  841 "about           "
  842 "what happens all"
  843 " the time what -"
  844 "am I ttttttt the"
  845 " person said, so"
  846 " what, per son -"
  847 " gory story is -"
  848 " about nothing -"
  849 "tttttt to test -"
  850 "his sto nothing";
  851 
  852 static const uint8_t test_apphead[] = "header test";
  853 
  854 static int
  855 test_compress_text (xd3_stream  *stream,
  856             uint8_t     *encoded,
  857             usize_t     *encoded_size)
  858 {
  859   int ret;
  860   xd3_config cfg;
  861   int oflags = stream->flags;
  862   int flags = stream->flags | XD3_FLUSH;
  863 
  864   xd3_free_stream (stream);
  865   xd3_init_config (& cfg, flags);
  866 
  867   /* This configuration is fixed so that the "expected non-error" the counts in
  868    * decompress_single_bit_errors are too.  See test_coftcfg_str. */
  869   cfg.smatch_cfg = XD3_SMATCH_SOFT;
  870   cfg.smatcher_soft.name = "test";
  871   cfg.smatcher_soft.large_look = 64; /* no source, not used */
  872   cfg.smatcher_soft.large_step = 64; /* no source, not used */
  873   cfg.smatcher_soft.small_look = 4;
  874   cfg.smatcher_soft.small_chain = 128;
  875   cfg.smatcher_soft.small_lchain = 16;
  876   cfg.smatcher_soft.max_lazy = 8;
  877   cfg.smatcher_soft.long_enough = 128;
  878 
  879   xd3_config_stream (stream, & cfg);
  880 
  881   (*encoded_size) = 0;
  882 
  883   xd3_set_appheader (stream, test_apphead,
  884              (usize_t) strlen ((char*) test_apphead));
  885 
  886   if ((ret = xd3_encode_stream (stream, test_text, sizeof (test_text),
  887                 encoded, encoded_size, 4*sizeof (test_text)))) { goto fail; }
  888 
  889   if ((ret = xd3_close_stream (stream))) { goto fail; }
  890 
  891  fail:
  892   xd3_free_stream (stream);
  893   xd3_init_config (& cfg, oflags);
  894   xd3_config_stream (stream, & cfg);
  895   return ret;
  896 }
  897 
  898 static int
  899 test_decompress_text (xd3_stream *stream, uint8_t *enc, usize_t enc_size, usize_t test_desize)
  900 {
  901   xd3_config cfg;
  902   char decoded[sizeof (test_text)];
  903   uint8_t *apphead;
  904   usize_t apphead_size;
  905   usize_t decoded_size;
  906   const char *msg;
  907   int  ret;
  908   usize_t pos = 0;
  909   int flags = stream->flags;
  910   usize_t take;
  911 
  912  input:
  913   /* Test decoding test_desize input bytes at a time */
  914   take = xd3_min (enc_size - pos, test_desize);
  915   CHECK(take > 0);
  916 
  917   xd3_avail_input (stream, enc + pos, take);
  918  again:
  919   ret = xd3_decode_input (stream);
  920 
  921   pos += take;
  922   take = 0;
  923 
  924   switch (ret)
  925     {
  926     case XD3_OUTPUT:
  927       break;
  928     case XD3_WINSTART:
  929     case XD3_GOTHEADER:
  930       goto again;
  931     case XD3_INPUT:
  932       if (pos < enc_size) { goto input; }
  933       /* else fallthrough */
  934     case XD3_WINFINISH:
  935     default:
  936       goto fail;
  937     }
  938 
  939   CHECK(ret == XD3_OUTPUT);
  940   CHECK(pos == enc_size);
  941 
  942   if (stream->avail_out != sizeof (test_text))
  943     {
  944       stream->msg = "incorrect output size";
  945       ret = XD3_INTERNAL;
  946       goto fail;
  947     }
  948 
  949   decoded_size = stream->avail_out;
  950   memcpy (decoded, stream->next_out, stream->avail_out);
  951 
  952   xd3_consume_output (stream);
  953 
  954   if ((ret = xd3_get_appheader (stream, & apphead, & apphead_size))) { goto fail; }
  955 
  956   if (apphead_size != strlen ((char*) test_apphead) ||
  957       memcmp (apphead, test_apphead, strlen ((char*) test_apphead)) != 0)
  958     {
  959       stream->msg = "incorrect appheader";
  960       ret = XD3_INTERNAL;
  961       goto fail;
  962     }
  963 
  964   if ((ret = xd3_decode_input (stream)) != XD3_WINFINISH ||
  965       (ret = xd3_close_stream (stream)) != 0)
  966     {
  967       goto fail;
  968     }
  969 
  970   if (decoded_size != sizeof (test_text) ||
  971       memcmp (decoded, test_text, sizeof (test_text)) != 0)
  972     {
  973       stream->msg = "incorrect output text";
  974       ret = EIO;
  975     }
  976 
  977  fail:
  978   msg = stream->msg;
  979   xd3_free_stream (stream);
  980   xd3_init_config (& cfg, flags);
  981   xd3_config_stream (stream, & cfg);
  982   stream->msg = msg;
  983 
  984   return ret;
  985 }
  986 
  987 static int
  988 test_decompress_single_bit_error (xd3_stream *stream, int expected_non_failures)
  989 {
  990   int ret;
  991   usize_t i;
  992   uint8_t encoded[4*sizeof (test_text)]; /* make room for alt code table */
  993   usize_t  encoded_size;
  994   int non_failures = 0;
  995   int cksum = (stream->flags & XD3_ADLER32) != 0;
  996 
  997 //#define DEBUG_TEST_FAILURES
  998 #ifndef DEBUG_TEST_FAILURES
  999 #define TEST_FAILURES()
 1000 #else
 1001   /* For checking non-failure cases by hand, enable this macro and run
 1002    * xdelta printdelta with print_cpymode disabled.  Every non-failure
 1003    * should change a copy address mode, which doesn't cause a failure
 1004    * because the address cache starts out with all zeros.
 1005 
 1006     ./xdelta3 test
 1007     for i in test_text.xz.*; do ./xdelta3 printdelta $i > $i.out;
 1008     diff $i.out test_text.xz.0.out; done
 1009 
 1010    */
 1011   system ("rm -rf test_text.*");
 1012   {
 1013     char buf[TESTBUFSIZE];
 1014     FILE *f;
 1015     snprintf_func (buf, TESTBUFSIZE, "test_text");
 1016     f = fopen (buf, "w");
 1017     fwrite (test_text,1,sizeof (test_text),f);
 1018     fclose (f);
 1019   }
 1020 #define TEST_FAILURES()                                         \
 1021   do {                                                          \
 1022     char buf[TESTBUFSIZE];                      \
 1023     FILE *f;                                                    \
 1024     snprintf_func (buf, TESTBUFSIZE, "test_text.xz.%d", non_failures);  \
 1025     f = fopen (buf, "w");                                       \
 1026     fwrite (encoded,1,encoded_size,f);                          \
 1027     fclose (f);                                                 \
 1028   } while (0)
 1029 #endif
 1030 
 1031   stream->sec_data.inefficient = 1;
 1032   stream->sec_inst.inefficient = 1;
 1033   stream->sec_addr.inefficient = 1;
 1034 
 1035   /* Encode text, test correct input */
 1036   if ((ret = test_compress_text (stream, encoded, & encoded_size)))
 1037     {
 1038       /*stream->msg = "without error: encode failure";*/
 1039       return ret;
 1040     }
 1041 
 1042   if ((ret = test_decompress_text (stream, encoded, encoded_size,
 1043                    sizeof (test_text) / 4)))
 1044     {
 1045       /*stream->msg = "without error: decode failure";*/
 1046       return ret;
 1047     }
 1048 
 1049   TEST_FAILURES();
 1050 
 1051   for (i = 0; i < encoded_size*8; i += 1)
 1052     {
 1053       /* Single bit error. */
 1054       encoded[i/8] ^= 1 << (i%8);
 1055 
 1056       if ((ret = test_decompress_text (stream, encoded,
 1057                        encoded_size, sizeof (test_text))) == 0)
 1058     {
 1059       non_failures += 1;
 1060 #ifdef DEBUG_TEST_FAILURES
 1061       XPR(NT "%u[%u] non-failure %u\n", i/8, i%8, non_failures);
 1062 #endif
 1063       TEST_FAILURES();
 1064     }
 1065       else
 1066     {
 1067       /*XPR(NT "%u[%u] failure: %s\n", i/8, i%8, stream->msg);*/
 1068     }
 1069 
 1070       /* decompress_text returns EIO when the final memcmp() fails, but that
 1071        * should never happen with checksumming on. */
 1072       if (cksum && ret == EIO)
 1073     {
 1074       /*XPR(NT "%u[%u] cksum mismatch\n", i/8, i%8);*/
 1075       stream->msg = "checksum mismatch";
 1076       return XD3_INTERNAL;
 1077     }
 1078 
 1079       /* Undo single bit error. */
 1080       encoded[i/8] ^= 1 << (i%8);
 1081     }
 1082 
 1083   /* Test correct input again */
 1084   if ((ret = test_decompress_text (stream, encoded, encoded_size, 1)))
 1085     {
 1086       /*stream->msg = "without error: decode failure";*/
 1087       return ret;
 1088     }
 1089 
 1090   /* Check expected non-failures */
 1091   if (non_failures > expected_non_failures)
 1092     {
 1093       XPR(NT "non-failures %u > expected %u",
 1094      non_failures, expected_non_failures);
 1095       stream->msg = "incorrect";
 1096       return XD3_INTERNAL;
 1097     }
 1098 
 1099   DOT ();
 1100 
 1101   return 0;
 1102 }
 1103 
 1104 /***********************************************************************
 1105  Secondary compression tests
 1106  ***********************************************************************/
 1107 
 1108 #if SECONDARY_ANY
 1109 typedef int (*sec_dist_func) (xd3_stream *stream, xd3_output *data);
 1110 
 1111 static int sec_dist_func1 (xd3_stream *stream, xd3_output *data);
 1112 static int sec_dist_func2 (xd3_stream *stream, xd3_output *data);
 1113 static int sec_dist_func3 (xd3_stream *stream, xd3_output *data);
 1114 static int sec_dist_func4 (xd3_stream *stream, xd3_output *data);
 1115 static int sec_dist_func5 (xd3_stream *stream, xd3_output *data);
 1116 static int sec_dist_func6 (xd3_stream *stream, xd3_output *data);
 1117 static int sec_dist_func7 (xd3_stream *stream, xd3_output *data);
 1118 static int sec_dist_func8 (xd3_stream *stream, xd3_output *data);
 1119 static int sec_dist_func9 (xd3_stream *stream, xd3_output *data);
 1120 static int sec_dist_func10 (xd3_stream *stream, xd3_output *data);
 1121 static int sec_dist_func11 (xd3_stream *stream, xd3_output *data);
 1122 
 1123 static sec_dist_func sec_dists[] =
 1124 {
 1125   sec_dist_func1,
 1126   sec_dist_func2,
 1127   sec_dist_func3,
 1128   sec_dist_func4,
 1129   sec_dist_func5,
 1130   sec_dist_func6,
 1131   sec_dist_func7,
 1132   sec_dist_func8,
 1133   sec_dist_func9,
 1134   sec_dist_func10,
 1135   sec_dist_func11,
 1136 };
 1137 
 1138 /* Test ditsribution: 100 bytes of the same character (13). */
 1139 static int
 1140 sec_dist_func1 (xd3_stream *stream, xd3_output *data)
 1141 {
 1142   int i, ret;
 1143   for (i = 0; i < 100; i += 1)
 1144     {
 1145       if ((ret = xd3_emit_byte (stream, & data, 13))) { return ret; }
 1146     }
 1147   return 0;
 1148 }
 1149 
 1150 /* Test ditsribution: uniform covering half the alphabet. */
 1151 static int
 1152 sec_dist_func2 (xd3_stream *stream, xd3_output *data)
 1153 {
 1154   int i, ret;
 1155   for (i = 0; i < ALPHABET_SIZE; i += 1)
 1156     {
 1157       if ((ret = xd3_emit_byte (stream, & data, i%(ALPHABET_SIZE/2)))) { return ret; }
 1158     }
 1159   return 0;
 1160 }
 1161 
 1162 /* Test ditsribution: uniform covering the entire alphabet. */
 1163 static int
 1164 sec_dist_func3 (xd3_stream *stream, xd3_output *data)
 1165 {
 1166   int i, ret;
 1167   for (i = 0; i < ALPHABET_SIZE; i += 1)
 1168     {
 1169       if ((ret = xd3_emit_byte (stream, & data, i%ALPHABET_SIZE))) { return ret; }
 1170     }
 1171   return 0;
 1172 }
 1173 
 1174 /* Test distribution: An exponential distribution covering half the alphabet */
 1175 static int
 1176 sec_dist_func4 (xd3_stream *stream, xd3_output *data)
 1177 {
 1178   int i, ret, x;
 1179   for (i = 0; i < ALPHABET_SIZE*20; i += 1)
 1180     {
 1181       x = mt_exp_rand (10, ALPHABET_SIZE/2);
 1182       if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; }
 1183     }
 1184   return 0;
 1185 }
 1186 
 1187 /* Test distribution: An exponential distribution covering the entire alphabet */
 1188 static int
 1189 sec_dist_func5 (xd3_stream *stream, xd3_output *data)
 1190 {
 1191   int i, ret, x;
 1192   for (i = 0; i < ALPHABET_SIZE*20; i += 1)
 1193     {
 1194       x = mt_exp_rand (10, ALPHABET_SIZE-1);
 1195       if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; }
 1196     }
 1197   return 0;
 1198 }
 1199 
 1200 /* Test distribution: An uniform random distribution covering half the alphabet */
 1201 static int
 1202 sec_dist_func6 (xd3_stream *stream, xd3_output *data)
 1203 {
 1204   int i, ret, x;
 1205   for (i = 0; i < ALPHABET_SIZE*20; i += 1)
 1206     {
 1207       x = mt_random (&static_mtrand) % (ALPHABET_SIZE/2);
 1208       if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; }
 1209     }
 1210   return 0;
 1211 }
 1212 
 1213 /* Test distribution: An uniform random distribution covering the entire alphabet */
 1214 static int
 1215 sec_dist_func7 (xd3_stream *stream, xd3_output *data)
 1216 {
 1217   int i, ret, x;
 1218   for (i = 0; i < ALPHABET_SIZE*200; i += 1)
 1219     {
 1220       x = mt_random (&static_mtrand) % ALPHABET_SIZE;
 1221       if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; }
 1222     }
 1223   return 0;
 1224 }
 1225 
 1226 /* Test distribution: A small number of frequent characters, difficult
 1227  * to divide into many groups */
 1228 static int
 1229 sec_dist_func8 (xd3_stream *stream, xd3_output *data)
 1230 {
 1231   int i, ret;
 1232   for (i = 0; i < ALPHABET_SIZE*5; i += 1)
 1233     {
 1234       if ((ret = xd3_emit_byte (stream, & data, 0))) { return ret; }
 1235       if ((ret = xd3_emit_byte (stream, & data, 64))) { return ret; }
 1236       if ((ret = xd3_emit_byte (stream, & data, 128))) { return ret; }
 1237       if ((ret = xd3_emit_byte (stream, & data, 255))) { return ret; }
 1238     }
 1239   return 0;
 1240 }
 1241 
 1242 /* Test distribution: One that causes many FGK block promotions (found a bug) */
 1243 static int
 1244 sec_dist_func9 (xd3_stream *stream, xd3_output *data)
 1245 {
 1246   int i, ret;
 1247 
 1248   int ramp   = 0;
 1249   int rcount = 0;
 1250   int prom   = 0;
 1251   int pcount = 0;
 1252 
 1253   /* 200 was long enough to trigger it--only when stricter checking
 1254    * that counted all blocks was turned on, but it seems I deleted
 1255    * this code. (missing fgk_free_block on line 398). */
 1256   for (i = 0; i < ALPHABET_SIZE*200; i += 1)
 1257     {
 1258     repeat:
 1259       if (ramp < ALPHABET_SIZE)
 1260     {
 1261       /* Initially Nth symbol has (N+1) frequency */
 1262       if (rcount <= ramp)
 1263         {
 1264           rcount += 1;
 1265           if ((ret = xd3_emit_byte (stream, & data, ramp))) { return ret; }
 1266           continue;
 1267         }
 1268 
 1269       ramp   += 1;
 1270       rcount  = 0;
 1271       goto repeat;
 1272     }
 1273 
 1274       /* Thereafter, promote least freq to max freq */
 1275       if (pcount == ALPHABET_SIZE)
 1276     {
 1277       pcount = 0;
 1278       prom   = (prom + 1) % ALPHABET_SIZE;
 1279     }
 1280 
 1281       pcount += 1;
 1282       if ((ret = xd3_emit_byte (stream, & data, prom))) { return ret; }
 1283     }
 1284 
 1285   return 0;
 1286 }
 1287 
 1288 /* Test distribution: freq[i] == i*i, creates a 21-bit code length, fixed in 3.0r. */
 1289 static int
 1290 sec_dist_func10 (xd3_stream *stream, xd3_output *data)
 1291 {
 1292   int i, j, ret;
 1293   for (i = 0; i < ALPHABET_SIZE; i += 1)
 1294     {
 1295       for (j = 0; j <= (i*i); j += 1)
 1296     {
 1297       if ((ret = xd3_emit_byte (stream, & data, i))) { return ret; }
 1298     }
 1299     }
 1300   return 0;
 1301 }
 1302 
 1303 /* Test distribution: fibonacci */
 1304 static int
 1305 sec_dist_func11 (xd3_stream *stream, xd3_output *data)
 1306 {
 1307   int sum0 = 0;
 1308   int sum1 = 1;
 1309   int i, j, ret;
 1310   for (i = 0; i < 33; ++i)
 1311     {
 1312       for (j = 0; j < (sum0 + sum1); ++j)
 1313     {
 1314       if ((ret = xd3_emit_byte (stream, & data, i))) { return ret; }
 1315     }
 1316       sum0 = sum1;
 1317       sum1 = j;
 1318     }
 1319   return 0;
 1320 }
 1321 
 1322 static int
 1323 test_secondary_decode (xd3_stream         *stream,
 1324                const xd3_sec_type *sec,
 1325                usize_t              input_size,
 1326                usize_t              compress_size,
 1327                const uint8_t      *dec_input,
 1328                const uint8_t      *dec_correct,
 1329                uint8_t            *dec_output)
 1330 {
 1331   int ret;
 1332   xd3_sec_stream *dec_stream;
 1333   const uint8_t *dec_input_used, *dec_input_end;
 1334   uint8_t *dec_output_used, *dec_output_end;
 1335 
 1336   if ((dec_stream = sec->alloc (stream)) == NULL) { return ENOMEM; }
 1337 
 1338   if ((ret = sec->init (stream, dec_stream, 0)) != 0) { goto fail; }
 1339 
 1340   dec_input_used = dec_input;
 1341   dec_input_end  = dec_input + compress_size;
 1342 
 1343   dec_output_used = dec_output;
 1344   dec_output_end  = dec_output + input_size;
 1345 
 1346   if ((ret = sec->decode (stream, dec_stream,
 1347               & dec_input_used, dec_input_end,
 1348               & dec_output_used, dec_output_end)))
 1349     {
 1350       goto fail;
 1351     }
 1352 
 1353   if (dec_input_used != dec_input_end)
 1354     {
 1355       stream->msg = "unused input";
 1356       ret = XD3_INTERNAL;
 1357       goto fail;
 1358     }
 1359 
 1360   if (dec_output_used != dec_output_end)
 1361     {
 1362       stream->msg = "unfinished output";
 1363       ret = XD3_INTERNAL;
 1364       goto fail;
 1365     }
 1366 
 1367   if (memcmp (dec_output, dec_correct, input_size) != 0)
 1368     {
 1369       stream->msg = "incorrect output";
 1370       ret = XD3_INTERNAL;
 1371       goto fail;
 1372     }
 1373 
 1374  fail:
 1375   sec->destroy (stream, dec_stream);
 1376   return ret;
 1377 }
 1378 
 1379 static int
 1380 test_secondary (xd3_stream *stream, const xd3_sec_type *sec, usize_t groups)
 1381 {
 1382   usize_t test_i;
 1383   int ret;
 1384   xd3_output *in_head, *out_head, *p;
 1385   usize_t p_off, input_size, compress_size;
 1386   uint8_t *dec_input = NULL, *dec_output = NULL, *dec_correct = NULL;
 1387   xd3_sec_stream *enc_stream;
 1388   xd3_sec_cfg cfg;
 1389 
 1390   memset (& cfg, 0, sizeof (cfg));
 1391 
 1392   cfg.inefficient = 1;
 1393 
 1394   for (cfg.ngroups = 1; cfg.ngroups <= groups; cfg.ngroups += 1)
 1395     {
 1396       XPR(NTR "\n...");
 1397       for (test_i = 0; test_i < SIZEOF_ARRAY (sec_dists); test_i += 1)
 1398     {
 1399       mt_init (& static_mtrand, 0x9f73f7fc);
 1400 
 1401       in_head  = xd3_alloc_output (stream, NULL);
 1402       out_head = xd3_alloc_output (stream, NULL);
 1403       enc_stream = sec->alloc (stream);
 1404       dec_input = NULL;
 1405       dec_output = NULL;
 1406       dec_correct = NULL;
 1407 
 1408       if (in_head == NULL || out_head == NULL || enc_stream == NULL)
 1409         {
 1410           goto nomem;
 1411         }
 1412 
 1413       if ((ret = sec_dists[test_i] (stream, in_head))) { goto fail; }
 1414 
 1415       if ((ret = sec->init (stream, enc_stream, 1)) != 0) { goto fail; }
 1416 
 1417       /* Encode data */
 1418       if ((ret = sec->encode (stream, enc_stream,
 1419                   in_head, out_head, & cfg)))
 1420         {
 1421           XPR(NT "test %u: encode: %s", test_i, stream->msg);
 1422           goto fail;
 1423         }
 1424 
 1425       /* Calculate sizes, allocate contiguous arrays for decoding */
 1426       input_size    = xd3_sizeof_output (in_head);
 1427       compress_size = xd3_sizeof_output (out_head);
 1428 
 1429       XPR(NTR "%.3f", 8.0 * (double) compress_size / (double) input_size);
 1430 
 1431       if ((dec_input   = (uint8_t*) xd3_alloc (stream, compress_size, 1)) == NULL ||
 1432           (dec_output  = (uint8_t*) xd3_alloc (stream, input_size, 1)) == NULL ||
 1433           (dec_correct = (uint8_t*) xd3_alloc (stream, input_size, 1)) == NULL)
 1434         {
 1435           goto nomem;
 1436         }
 1437 
 1438       /* Fill the compressed data array */
 1439       for (p_off = 0, p = out_head; p != NULL;
 1440            p_off += p->next, p = p->next_page)
 1441         {
 1442           memcpy (dec_input + p_off, p->base, p->next);
 1443         }
 1444 
 1445       CHECK(p_off == compress_size);
 1446 
 1447       /* Fill the input data array */
 1448       for (p_off = 0, p = in_head; p != NULL;
 1449            p_off += p->next, p = p->next_page)
 1450         {
 1451           memcpy (dec_correct + p_off, p->base, p->next);
 1452         }
 1453 
 1454       CHECK(p_off == input_size);
 1455 
 1456       if ((ret = test_secondary_decode (stream, sec, input_size,
 1457                         compress_size, dec_input,
 1458                         dec_correct, dec_output)))
 1459         {
 1460           XPR(NT "test %u: decode: %s", test_i, stream->msg);
 1461           goto fail;
 1462         }
 1463 
 1464       /* Single-bit error test, only cover the first 10 bytes.
 1465        * Some non-failures are expected in the Huffman case:
 1466        * Changing the clclen array, for example, may not harm the
 1467        * decoding.  Really looking for faults here. */
 1468       {
 1469         int i;
 1470         int bytes = xd3_min (compress_size, 10U);
 1471         for (i = 0; i < bytes * 8; i += 1)
 1472           {
 1473         dec_input[i/8] ^= 1 << (i%8);
 1474 
 1475         if ((ret = test_secondary_decode (stream, sec, input_size,
 1476                           compress_size, dec_input,
 1477                           dec_correct, dec_output))
 1478             == 0)
 1479           {
 1480             /*XPR(NT "test %u: decode single-bit [%u/%u]
 1481               error non-failure", test_i, i/8, i%8);*/
 1482           }
 1483 
 1484         dec_input[i/8] ^= 1 << (i%8);
 1485 
 1486         if ((i % (2*bytes)) == (2*bytes)-1)
 1487           {
 1488             DOT ();
 1489           }
 1490           }
 1491         ret = 0;
 1492       }
 1493 
 1494       if (0) { nomem: ret = ENOMEM; }
 1495 
 1496     fail:
 1497       sec->destroy (stream, enc_stream);
 1498       xd3_free_output (stream, in_head);
 1499       xd3_free_output (stream, out_head);
 1500       xd3_free (stream, dec_input);
 1501       xd3_free (stream, dec_output);
 1502       xd3_free (stream, dec_correct);
 1503 
 1504       if (ret != 0) { return ret; }
 1505     }
 1506     }
 1507 
 1508   return 0;
 1509 }
 1510 
 1511 IF_FGK (static int test_secondary_fgk  (xd3_stream *stream, usize_t gp)
 1512     { return test_secondary (stream, & fgk_sec_type, gp); })
 1513 IF_DJW (static int test_secondary_huff (xd3_stream *stream, usize_t gp)
 1514     { return test_secondary (stream, & djw_sec_type, gp); })
 1515 IF_LZMA (static int test_secondary_lzma (xd3_stream *stream, usize_t gp)
 1516     { return test_secondary (stream, & lzma_sec_type, gp); })
 1517 
 1518 #endif  /* SECONDARY_ANY */
 1519 
 1520 /***********************************************************************
 1521  TEST INSTRUCTION TABLE
 1522  ***********************************************************************/
 1523 
 1524 /* Test that xd3_choose_instruction() does the right thing for its code
 1525  * table. */
 1526 static int
 1527 test_choose_instruction (xd3_stream *stream, int ignore)
 1528 {
 1529   int i;
 1530 
 1531   stream->code_table = (*stream->code_table_func) ();
 1532 
 1533   for (i = 0; i < 256; i += 1)
 1534     {
 1535       const xd3_dinst *d = stream->code_table + i;
 1536       xd3_rinst prev, inst;
 1537 
 1538       CHECK(d->type1 > 0);
 1539 
 1540       memset (& prev, 0, sizeof (prev));
 1541       memset (& inst, 0, sizeof (inst));
 1542 
 1543       if (d->type2 == 0)
 1544     {
 1545       inst.type = d->type1;
 1546 
 1547       if ((inst.size = d->size1) == 0)
 1548         {
 1549           inst.size = TESTBUFSIZE;
 1550         }
 1551 
 1552       XD3_CHOOSE_INSTRUCTION (stream, NULL, & inst);
 1553 
 1554       if (inst.code2 != 0 || inst.code1 != i)
 1555         {
 1556           stream->msg = "wrong single instruction";
 1557           return XD3_INTERNAL;
 1558         }
 1559     }
 1560       else
 1561     {
 1562       prev.type = d->type1;
 1563       prev.size = d->size1;
 1564       inst.type = d->type2;
 1565       inst.size = d->size2;
 1566 
 1567       XD3_CHOOSE_INSTRUCTION (stream, & prev, & inst);
 1568 
 1569       if (prev.code2 != i)
 1570         {
 1571           stream->msg = "wrong double instruction";
 1572           return XD3_INTERNAL;
 1573         }
 1574     }
 1575     }
 1576 
 1577   return 0;
 1578 }
 1579 
 1580 /***********************************************************************
 1581  64BIT STREAMING
 1582  ***********************************************************************/
 1583 
 1584 /* This test encodes and decodes a series of 1 megabyte windows, each
 1585  * containing a long run of zeros along with a single xoff_t size
 1586  * record to indicate the sequence. */
 1587 static int
 1588 test_streaming (xd3_stream *in_stream, uint8_t *encbuf, uint8_t *decbuf, uint8_t *delbuf, usize_t megs)
 1589 {
 1590   xd3_stream estream, dstream;
 1591   int ret;
 1592   usize_t i, delsize, decsize;
 1593   xd3_config cfg;
 1594   xd3_init_config (& cfg, in_stream->flags);
 1595   cfg.flags |= XD3_COMPLEVEL_6;
 1596 
 1597   if ((ret = xd3_config_stream (& estream, & cfg)) ||
 1598       (ret = xd3_config_stream (& dstream, & cfg)))
 1599     {
 1600       goto fail;
 1601     }
 1602 
 1603   for (i = 0; i < megs; i += 1)
 1604     {
 1605       ((usize_t*) encbuf)[0] = i;
 1606 
 1607       if ((i % 200) == 199) { DOT (); }
 1608 
 1609       if ((ret = xd3_process_stream (1, & estream, xd3_encode_input, 0,
 1610                      encbuf, 1 << 20,
 1611                      delbuf, & delsize, 1 << 20)))
 1612     {
 1613       in_stream->msg = estream.msg;
 1614       goto fail;
 1615     }
 1616 
 1617       if ((ret = xd3_process_stream (0, & dstream, xd3_decode_input, 0,
 1618                      delbuf, delsize,
 1619                      decbuf, & decsize, 1 << 20)))
 1620     {
 1621       in_stream->msg = dstream.msg;
 1622       goto fail;
 1623     }
 1624 
 1625       if (decsize != 1 << 20 ||
 1626       memcmp (encbuf, decbuf, 1 << 20) != 0)
 1627     {
 1628       in_stream->msg = "wrong result";
 1629       ret = XD3_INTERNAL;
 1630       goto fail;
 1631     }
 1632     }
 1633 
 1634   if ((ret = xd3_close_stream (& estream)) ||
 1635       (ret = xd3_close_stream (& dstream)))
 1636     {
 1637       goto fail;
 1638     }
 1639 
 1640  fail:
 1641   xd3_free_stream (& estream);
 1642   xd3_free_stream (& dstream);
 1643   return ret;
 1644 }
 1645 
 1646 /* Run tests of data streaming of over and around 4GB of data. */
 1647 static int
 1648 test_compressed_stream_overflow (xd3_stream *stream, int ignore)
 1649 {
 1650   int ret;
 1651   int i;
 1652   uint8_t *buf;
 1653 
 1654   if ((buf = (uint8_t*) malloc (TWO_MEGS_AND_DELTA)) == NULL) { return ENOMEM; }
 1655 
 1656   memset (buf, 0, TWO_MEGS_AND_DELTA);
 1657   for (i = 0; i < (2 << 20); i += 256)
 1658     {
 1659       int j;
 1660       int off = mt_random(& static_mtrand) % 10;
 1661       for (j = 0; j < 256; j++)
 1662     {
 1663       buf[i + j] = j + off;
 1664     }
 1665     }
 1666 
 1667   /* Test overflow of a 32-bit file offset. */
 1668   if (SIZEOF_XOFF_T == 4)
 1669     {
 1670       ret = test_streaming (stream, buf, buf + (1 << 20), buf + (2 << 20), (1 << 12) + 1);
 1671 
 1672       if (ret == XD3_INVALID_INPUT && MSG_IS ("decoder file offset overflow"))
 1673     {
 1674       ret = 0;
 1675     }
 1676       else
 1677     {
 1678           XPR(NT XD3_LIB_ERRMSG (stream, ret));
 1679       stream->msg = "expected overflow condition";
 1680       ret = XD3_INTERNAL;
 1681       goto fail;
 1682     }
 1683     }
 1684 
 1685   /* Test transfer of exactly 32bits worth of data. */
 1686   if ((ret = test_streaming (stream,
 1687                  buf,
 1688                  buf + (1 << 20),
 1689                  buf + (2 << 20),
 1690                  1 << 12)))
 1691     {
 1692       goto fail;
 1693     }
 1694  fail:
 1695   free (buf);
 1696   return ret;
 1697 }
 1698 
 1699 /***********************************************************************
 1700  COMMAND LINE
 1701  ***********************************************************************/
 1702 
 1703 #if SHELL_TESTS
 1704 
 1705 /* For each pair of command templates in the array below, test that
 1706  * encoding and decoding commands work.  Also check for the expected
 1707  * size delta, which should be approximately TEST_ADD_RATIO times the
 1708  * file size created by test_make_inputs.  Due to differences in the
 1709  * application header, it is suppressed (-A) so that all delta files
 1710  * are the same. */
 1711 static int
 1712 test_command_line_arguments (xd3_stream *stream, int ignore)
 1713 {
 1714   int i, ret;
 1715 
 1716   static const char* cmdpairs[] =
 1717   {
 1718     /* standard input, output */
 1719     "%s %s -A < %s > %s", "%s -d < %s > %s",
 1720     "%s %s -A -e < %s > %s", "%s -d < %s > %s",
 1721     "%s %s -A= encode < %s > %s", "%s decode < %s > %s",
 1722     "%s %s -A -q encode < %s > %s", "%s -qdq < %s > %s",
 1723 
 1724     /* file input, standard output */
 1725     "%s %s -A= %s > %s", "%s -d %s > %s",
 1726     "%s %s -A -e %s > %s", "%s -d %s > %s",
 1727     "%s %s encode -A= %s > %s", "%s decode %s > %s",
 1728 
 1729     /* file input, output */
 1730     "%s %s -A= %s %s", "%s -d %s %s",
 1731     "%s %s -A -e %s %s", "%s -d %s %s",
 1732     "%s %s -A= encode %s %s", "%s decode %s %s",
 1733 
 1734     /* option placement */
 1735     "%s %s -A -f %s %s", "%s -f -d %s %s",
 1736     "%s %s -e -A= %s %s", "%s -d -f %s %s",
 1737     "%s %s -f encode -A= %s %s", "%s -f decode -f %s %s",
 1738   };
 1739 
 1740   char ecmd[TESTBUFSIZE], dcmd[TESTBUFSIZE];
 1741   int pairs = SIZEOF_ARRAY (cmdpairs) / 2;
 1742   xoff_t tsize;
 1743   xoff_t dsize;
 1744   double ratio;
 1745 
 1746   mt_init (& static_mtrand, 0x9f73f7fc);
 1747 
 1748   for (i = 0; i < pairs; i += 1)
 1749     {
 1750       test_setup ();
 1751       if ((ret = test_make_inputs (stream, NULL, & tsize))) { return ret; }
 1752 
 1753       snprintf_func (ecmd, TESTBUFSIZE, cmdpairs[2*i], program_name,
 1754            test_softcfg_str, TEST_TARGET_FILE, TEST_DELTA_FILE);
 1755       snprintf_func (dcmd, TESTBUFSIZE, cmdpairs[2*i+1], program_name,
 1756            TEST_DELTA_FILE, TEST_RECON_FILE);
 1757 
 1758       /* Encode and decode. */
 1759       if ((ret = system (ecmd)) != 0)
 1760     {
 1761       XPR(NT "encode command: %s\n", ecmd);
 1762       stream->msg = "encode cmd failed";
 1763       return XD3_INTERNAL;
 1764     }
 1765 
 1766       if ((ret = system (dcmd)) != 0)
 1767     {
 1768       XPR(NT "decode command: %s\n", dcmd);
 1769       stream->msg = "decode cmd failed";
 1770       return XD3_INTERNAL;
 1771     }
 1772 
 1773       /* Compare the target file. */
 1774       if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_RECON_FILE)))
 1775     {
 1776       return ret;
 1777     }
 1778 
 1779       if ((ret = test_file_size (TEST_DELTA_FILE, & dsize)))
 1780     {
 1781       return ret;
 1782     }
 1783 
 1784       ratio = (double) dsize / (double) tsize;
 1785 
 1786       /* Check that it is not too small, not too large. */
 1787       if (ratio >= TEST_ADD_RATIO + TEST_EPSILON)
 1788     {
 1789       XPR(NT "test encode with size ratio %.4f, "
 1790          "expected < %.4f (%"Q"u, %"Q"u)\n",
 1791         ratio, TEST_ADD_RATIO + TEST_EPSILON, dsize, tsize);
 1792       stream->msg = "strange encoding";
 1793       return XD3_INTERNAL;
 1794     }
 1795 
 1796       if (ratio <= TEST_ADD_RATIO * (1.0 - 2 * TEST_EPSILON))
 1797     {
 1798       XPR(NT "test encode with size ratio %.4f, "
 1799          "expected > %.4f\n",
 1800         ratio, TEST_ADD_RATIO - TEST_EPSILON);
 1801       stream->msg = "strange encoding";
 1802       return XD3_INTERNAL;
 1803     }
 1804 
 1805       /* Also check that test_compare_files works.  The delta and original should
 1806        * not be identical. */
 1807       if ((ret = test_compare_files (TEST_DELTA_FILE,
 1808                 TEST_TARGET_FILE)) == 0)
 1809     {
 1810       stream->msg = "broken test_compare_files";
 1811       return XD3_INTERNAL;
 1812     }
 1813 
 1814       test_cleanup ();
 1815       DOT ();
 1816     }
 1817 
 1818   return 0;
 1819 }
 1820 
 1821 static int
 1822 check_vcdiff_header (xd3_stream *stream,
 1823              const char *input,
 1824              const char *line_start,
 1825              const char *matches,
 1826              int yes_or_no)
 1827 {
 1828   int ret;
 1829   char vcmd[TESTBUFSIZE], gcmd[TESTBUFSIZE];
 1830 
 1831   snprintf_func (vcmd, TESTBUFSIZE, "%s printhdr -f %s %s",
 1832         program_name, input, TEST_RECON2_FILE);
 1833 
 1834   if ((ret = system (vcmd)) != 0)
 1835     {
 1836       XPR(NT "printhdr command: %s\n", vcmd);
 1837       stream->msg = "printhdr cmd failed";
 1838       return XD3_INTERNAL;
 1839     }
 1840 
 1841   snprintf_func (gcmd, TESTBUFSIZE, "grep \"%s.*%s.*\" %s > /dev/null",
 1842         line_start, matches, TEST_RECON2_FILE);
 1843 
 1844   if (yes_or_no)
 1845     {
 1846       if ((ret = do_cmd (stream, gcmd)))
 1847     {
 1848       XPR(NT "%s\n", gcmd);
 1849       return ret;
 1850     }
 1851     }
 1852   else
 1853     {
 1854       if ((ret = do_fail (stream, gcmd)))
 1855     {
 1856       XPR(NT "%s\n", gcmd);
 1857       return ret;
 1858     }
 1859     }
 1860 
 1861   return 0;
 1862 }
 1863 
 1864 static int
 1865 test_recode_command2 (xd3_stream *stream, int has_source,
 1866               int variant, int change)
 1867 {
 1868   int has_adler32 = (variant & 0x1) != 0;
 1869   int has_apphead = (variant & 0x2) != 0;
 1870   int has_secondary = (variant & 0x4) != 0;
 1871 
 1872   int change_adler32 = (change & 0x1) != 0;
 1873   int change_apphead = (change & 0x2) != 0;
 1874   int change_secondary = (change & 0x4) != 0;
 1875 
 1876   int recoded_adler32 = change_adler32 ? !has_adler32 : has_adler32;
 1877   int recoded_apphead = change_apphead ? !has_apphead : has_apphead;
 1878   int recoded_secondary = change_secondary ? !has_secondary : has_secondary;
 1879 
 1880   char ecmd[TESTBUFSIZE], recmd[TESTBUFSIZE], dcmd[TESTBUFSIZE];
 1881   xoff_t tsize, ssize;
 1882   int ret;
 1883 
 1884   test_setup ();
 1885 
 1886   if ((ret = test_make_inputs (stream, has_source ? & ssize : NULL, & tsize)))
 1887     {
 1888       return ret;
 1889     }
 1890 
 1891   /* First encode */
 1892   snprintf_func (ecmd, TESTBUFSIZE, "%s %s -f %s %s %s %s %s %s %s",
 1893         program_name, test_softcfg_str,
 1894         has_adler32 ? "" : "-n ",
 1895         has_apphead ? "-A=encode_apphead " : "-A= ",
 1896         has_secondary ? "-S djw " : "-S none ",
 1897         has_source ? "-s " : "",
 1898         has_source ? TEST_SOURCE_FILE : "",
 1899         TEST_TARGET_FILE,
 1900         TEST_DELTA_FILE);
 1901 
 1902   if ((ret = system (ecmd)) != 0)
 1903     {
 1904       XPR(NT "encode command: %s\n", ecmd);
 1905       stream->msg = "encode cmd failed";
 1906       return XD3_INTERNAL;
 1907     }
 1908 
 1909   /* Now recode */
 1910   snprintf_func (recmd, TESTBUFSIZE,
 1911         "%s recode %s -f %s %s %s %s %s", program_name, test_softcfg_str,
 1912         recoded_adler32 ? "" : "-n ",
 1913         !change_apphead ? "" :
 1914             (recoded_apphead ? "-A=recode_apphead " : "-A= "),
 1915         recoded_secondary ? "-S djw " : "-S= ",
 1916         TEST_DELTA_FILE,
 1917         TEST_COPY_FILE);
 1918 
 1919   if ((ret = system (recmd)) != 0)
 1920     {
 1921       XPR(NT "recode command: %s\n", recmd);
 1922       stream->msg = "recode cmd failed";
 1923       return XD3_INTERNAL;
 1924     }
 1925 
 1926   /* Check recode changes. */
 1927 
 1928   if ((ret = check_vcdiff_header (stream,
 1929                   TEST_COPY_FILE,
 1930                   "VCDIFF window indicator",
 1931                   "VCD_SOURCE",
 1932                   has_source))) { return ret; }
 1933 
 1934   if ((ret = check_vcdiff_header (stream,
 1935                   TEST_COPY_FILE,
 1936                   "VCDIFF header indicator",
 1937                   "VCD_SECONDARY",
 1938                   recoded_secondary))) { return ret; }
 1939 
 1940   if ((ret = check_vcdiff_header (stream,
 1941                   TEST_COPY_FILE,
 1942                   "VCDIFF window indicator",
 1943                   "VCD_ADLER32",
 1944                   /* Recode can't generate an adler32
 1945                    * checksum, it can only preserve it or
 1946                    * remove it. */
 1947                   has_adler32 && recoded_adler32)))
 1948     {
 1949       return ret;
 1950     }
 1951 
 1952   if (!change_apphead)
 1953     {
 1954       if ((ret = check_vcdiff_header (stream,
 1955                       TEST_COPY_FILE,
 1956                       "VCDIFF header indicator",
 1957                       "VCD_APPHEADER",
 1958                       has_apphead)))
 1959     {
 1960       return ret;
 1961     }
 1962       if ((ret = check_vcdiff_header (stream,
 1963                       TEST_COPY_FILE,
 1964                       "VCDIFF application header",
 1965                       "encode_apphead",
 1966                       has_apphead)))
 1967     {
 1968       return ret;
 1969     }
 1970     }
 1971   else
 1972     {
 1973       if ((ret = check_vcdiff_header (stream,
 1974                       TEST_COPY_FILE,
 1975                       "VCDIFF header indicator",
 1976                       "VCD_APPHEADER",
 1977                       recoded_apphead)))
 1978     {
 1979       return ret;
 1980     }
 1981       if (recoded_apphead &&
 1982       (ret = check_vcdiff_header (stream,
 1983                       TEST_COPY_FILE,
 1984                       "VCDIFF application header",
 1985                       "recode_apphead",
 1986                       1)))
 1987     {
 1988       return ret;
 1989     }
 1990     }
 1991 
 1992   /* Now decode */
 1993   snprintf_func (dcmd, TESTBUFSIZE, "%s -fd %s %s %s %s ", program_name,
 1994         has_source ? "-s " : "",
 1995         has_source ? TEST_SOURCE_FILE : "",
 1996         TEST_COPY_FILE,
 1997         TEST_RECON_FILE);
 1998 
 1999   if ((ret = system (dcmd)) != 0)
 2000     {
 2001       XPR(NT "decode command: %s\n", dcmd);
 2002       stream->msg = "decode cmd failed";
 2003       return XD3_INTERNAL;
 2004     }
 2005 
 2006   /* Now compare. */
 2007   if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_RECON_FILE)))
 2008     {
 2009       return ret;
 2010     }
 2011   test_cleanup ();
 2012 
 2013   return 0;
 2014 }
 2015 
 2016 static int
 2017 test_recode_command (xd3_stream *stream, int ignore)
 2018 {
 2019   /* Things to test:
 2020    * - with and without a source file (recode does not change)
 2021    *
 2022    * (recode may or may not change -- 8 variations)
 2023    * - with and without adler32
 2024    * - with and without app header
 2025    * - with and without secondary
 2026    */
 2027   int has_source;
 2028   int variant;
 2029   int change;
 2030   int ret;
 2031 
 2032   for (has_source = 0; has_source < 2; has_source++)
 2033     {
 2034       for (variant = 0; variant < 8; variant++)
 2035     {
 2036       for (change = 0; change < 8; change++)
 2037         {
 2038           if ((ret = test_recode_command2 (stream, has_source,
 2039                            variant, change)))
 2040         {
 2041           return ret;
 2042         }
 2043         }
 2044       DOT ();
 2045     }
 2046     }
 2047 
 2048   return 0;
 2049 }
 2050 
 2051 #if SECONDARY_LZMA
 2052 int test_secondary_lzma_default (xd3_stream *stream, int ignore)
 2053 {
 2054   char ecmd[TESTBUFSIZE];
 2055   int ret;
 2056 
 2057   test_setup ();
 2058 
 2059   if ((ret = test_make_inputs (stream, NULL, NULL)))
 2060     {
 2061       return ret;
 2062     }
 2063 
 2064   /* First encode */
 2065   snprintf_func (ecmd, TESTBUFSIZE, "%s -e %s %s",
 2066          program_name,
 2067          TEST_TARGET_FILE,
 2068          TEST_DELTA_FILE);
 2069 
 2070   if ((ret = system (ecmd)) != 0)
 2071     {
 2072       return XD3_INTERNAL;
 2073     }
 2074 
 2075   if ((ret = check_vcdiff_header (stream,
 2076                   TEST_DELTA_FILE,
 2077                   "VCDIFF secondary compressor",
 2078                   "lzma",
 2079                   1)))
 2080     {
 2081       return ret;
 2082     }
 2083 
 2084   test_cleanup ();
 2085   return 0;
 2086 }
 2087 
 2088 #endif  /* SECONDARY_LZMA */
 2089 #endif  /* SHELL_TESTS */
 2090 
 2091 /***********************************************************************
 2092  EXTERNAL I/O DECOMPRESSION/RECOMPRESSION
 2093  ***********************************************************************/
 2094 
 2095 #if EXTERNAL_COMPRESSION
 2096 /* This performs one step of the test_externally_compressed_io
 2097  * function described below.  It builds a pipe containing both Xdelta
 2098  * and external compression/decompression that should not modify the
 2099  * data passing through. */
 2100 static int
 2101 test_compressed_pipe (xd3_stream *stream, main_extcomp *ext, char* buf,
 2102               const char* comp_options, const char* decomp_options,
 2103               int do_ext_recomp, const char* msg)
 2104 {
 2105   int ret;
 2106   char decomp_buf[TESTBUFSIZE];
 2107 
 2108   if (do_ext_recomp)
 2109     {
 2110       snprintf_func (decomp_buf, TESTBUFSIZE,
 2111         " | %s %s", ext->decomp_cmdname, ext->decomp_options);
 2112     }
 2113   else
 2114     {
 2115       decomp_buf[0] = 0;
 2116     }
 2117 
 2118   snprintf_func (buf, TESTBUFSIZE, "%s %s < %s | %s %s | %s %s%s > %s",
 2119        ext->recomp_cmdname, ext->recomp_options,
 2120        TEST_TARGET_FILE,
 2121        program_name, comp_options,
 2122        program_name, decomp_options,
 2123        decomp_buf,
 2124        TEST_RECON_FILE);
 2125 
 2126   if ((ret = system (buf)) != 0)
 2127     {
 2128       stream->msg = msg;
 2129       return XD3_INTERNAL;
 2130     }
 2131 
 2132   if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_RECON_FILE)))
 2133     {
 2134       return XD3_INTERNAL;
 2135     }
 2136 
 2137   DOT ();
 2138   return 0;
 2139 }
 2140 
 2141 /* We want to test that a pipe such as:
 2142  *
 2143  * --> | gzip -cf | xdelta3 -cf | xdelta3 -dcf | gzip -dcf | -->
 2144  *
 2145  * is transparent, i.e., does not modify the stream of data.  However,
 2146  * we also want to verify that at the center the data is properly
 2147  * compressed, i.e., that we do not just have a re-compressed gzip
 2148  * format, that we have an VCDIFF format.  We do this in two steps.
 2149  * First test the above pipe, then test with suppressed output
 2150  * recompression (-D).  The result should be the original input:
 2151  *
 2152  * --> | gzip -cf | xdelta3 -cf | xdelta3 -Ddcf | -->
 2153  *
 2154  * Finally we want to test that -D also disables input decompression:
 2155  *
 2156  * --> | gzip -cf | xdelta3 -Dcf | xdelta3 -Ddcf | gzip -dcf | -->
 2157  */
 2158 static int
 2159 test_externally_compressed_io (xd3_stream *stream, int ignore)
 2160 {
 2161   usize_t i;
 2162   int ret;
 2163   char buf[TESTBUFSIZE];
 2164 
 2165   mt_init (& static_mtrand, 0x9f73f7fc);
 2166 
 2167   if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; }
 2168 
 2169   for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1)
 2170     {
 2171       main_extcomp *ext = & extcomp_types[i];
 2172 
 2173       /* Test for the existence of the external command first, if not skip. */
 2174       snprintf_func (buf, TESTBUFSIZE, "%s %s < /dev/null > /dev/null", ext->recomp_cmdname, ext->recomp_options);
 2175 
 2176       if ((ret = system (buf)) != 0)
 2177     {
 2178       XPR(NT "%s=0", ext->recomp_cmdname);
 2179       continue;
 2180     }
 2181 
 2182       if ((ret = test_compressed_pipe (stream, ext, buf, "-cfq", "-dcfq", 1,
 2183                        "compression failed: identity pipe")) ||
 2184       (ret = test_compressed_pipe (stream, ext, buf, "-cfq", "-Rdcfq", 0,
 2185                        "compression failed: without recompression")) ||
 2186       (ret = test_compressed_pipe (stream, ext, buf, "-Dcfq", "-Rdcfq", 1,
 2187                        "compression failed: without decompression")))
 2188     {
 2189       return ret;
 2190     }
 2191     }
 2192 
 2193   return 0;
 2194 }
 2195 
 2196 /* This tests the proper functioning of external decompression for
 2197  * source files.  The source and target files are identical and
 2198  * compressed by gzip.  Decoding such a delta with recompression
 2199  * disbaled (-R) should produce the original, uncompressed
 2200  * source/target file.  Then it checks with output recompression
 2201  * enabled--in this case the output should be a compressed copy of the
 2202  * original source/target file.  Then it checks that encoding with
 2203  * decompression disabled works--the compressed files are identical
 2204  * and decoding them should always produce a compressed output,
 2205  * regardless of -R since the encoded delta file had decompression
 2206  * disabled..
 2207  */
 2208 static int
 2209 test_source_decompression (xd3_stream *stream, int ignore)
 2210 {
 2211   int ret;
 2212   char buf[TESTBUFSIZE];
 2213   const main_extcomp *ext;
 2214   xoff_t dsize;
 2215 
 2216   mt_init (& static_mtrand, 0x9f73f7fc);
 2217 
 2218   test_setup ();
 2219   if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; }
 2220 
 2221   /* Use gzip. */
 2222   if ((ext = main_get_compressor ("G")) == NULL)
 2223     {
 2224       XPR(NT "skipped");
 2225       return 0;
 2226     }
 2227 
 2228   /* Save an uncompressed copy. */
 2229   if ((ret = test_save_copy (TEST_TARGET_FILE))) { return ret; }
 2230 
 2231   /* Compress the source. */
 2232   snprintf_func (buf, TESTBUFSIZE, "%s -1 %s < %s > %s", ext->recomp_cmdname,
 2233        ext->recomp_options, TEST_COPY_FILE, TEST_SOURCE_FILE);
 2234   if ((ret = do_cmd (stream, buf))) { return ret; }
 2235   /* Compress the target. */
 2236   snprintf_func (buf, TESTBUFSIZE, "%s -9 %s < %s > %s", ext->recomp_cmdname,
 2237        ext->recomp_options, TEST_COPY_FILE, TEST_TARGET_FILE);
 2238   if ((ret = do_cmd (stream, buf))) { return ret; }
 2239 
 2240   /* Now the two identical files are compressed.  Delta-encode the target,
 2241    * with decompression. */
 2242   snprintf_func (buf, TESTBUFSIZE, "%s -e -vfq -s%s %s %s", program_name, TEST_SOURCE_FILE,
 2243        TEST_TARGET_FILE, TEST_DELTA_FILE);
 2244   if ((ret = do_cmd (stream, buf))) { return ret; }
 2245 
 2246   /* Check that the compressed file is small (b/c inputs are
 2247    * identical). */
 2248   if ((ret = test_file_size (TEST_DELTA_FILE, & dsize))) { return ret; }
 2249   /* Deltas for identical files should be very small. */
 2250   if (dsize > 200)
 2251     {
 2252       XPR(NT "external compression did not happen\n");
 2253       stream->msg = "external compression did not happen";
 2254       return XD3_INTERNAL;
 2255     }
 2256 
 2257   /* Decode the delta file with recompression disabled, should get an
 2258    * uncompressed file out. */
 2259   snprintf_func (buf, TESTBUFSIZE, "%s -v -dq -R -s%s %s %s", program_name,
 2260        TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE);
 2261   if ((ret = do_cmd (stream, buf))) { return ret; }
 2262   if ((ret = test_compare_files (TEST_COPY_FILE,
 2263                 TEST_RECON_FILE))) { return ret; }
 2264 
 2265   /* Decode the delta file with recompression, should get a compressed file
 2266    * out.  But we can't compare compressed files directly. */
 2267   snprintf_func (buf, TESTBUFSIZE, "%s -v -dqf -s%s %s %s", program_name,
 2268        TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE);
 2269   if ((ret = do_cmd (stream, buf))) { return ret; }
 2270   snprintf_func (buf, TESTBUFSIZE, "%s %s < %s > %s", ext->decomp_cmdname, ext->decomp_options,
 2271        TEST_RECON_FILE, TEST_RECON2_FILE);
 2272   if ((ret = do_cmd (stream, buf))) { return ret; }
 2273   if ((ret = test_compare_files (TEST_COPY_FILE,
 2274                 TEST_RECON2_FILE))) { return ret; }
 2275 
 2276   /* Encode with decompression disabled */
 2277   snprintf_func (buf, TESTBUFSIZE, "%s -e -D -vfq -s%s %s %s", program_name,
 2278        TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE);
 2279   if ((ret = do_cmd (stream, buf))) { return ret; }
 2280 
 2281   /* Decode the delta file with decompression disabled, should get the
 2282    * identical compressed file out. */
 2283   snprintf_func (buf, TESTBUFSIZE, "%s -d -D -vfq -s%s %s %s", program_name,
 2284        TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE);
 2285   if ((ret = do_cmd (stream, buf))) { return ret; }
 2286   if ((ret = test_compare_files (TEST_TARGET_FILE,
 2287                 TEST_RECON_FILE))) { return ret; }
 2288 
 2289   test_cleanup();
 2290   return 0;
 2291 }
 2292 #endif
 2293 
 2294 /***********************************************************************
 2295  FORCE, STDOUT
 2296  ***********************************************************************/
 2297 
 2298 /* This tests that output will not overwrite an existing file unless
 2299  * -f was specified.  The test is for encoding (the same code handles
 2300  * it for decoding). */
 2301 static int
 2302 test_force_behavior (xd3_stream *stream, int ignore)
 2303 {
 2304   int ret;
 2305   char buf[TESTBUFSIZE];
 2306 
 2307   /* Create empty target file */
 2308   test_setup ();
 2309   snprintf_func (buf, TESTBUFSIZE, "cp /dev/null %s", TEST_TARGET_FILE);
 2310   if ((ret = do_cmd (stream, buf))) { return ret; }
 2311 
 2312   /* Encode to delta file */
 2313   snprintf_func (buf, TESTBUFSIZE, "%s -e %s %s", program_name,
 2314        TEST_TARGET_FILE, TEST_DELTA_FILE);
 2315   if ((ret = do_cmd (stream, buf))) { return ret; }
 2316 
 2317   /* Encode again, should fail. */
 2318   snprintf_func (buf, TESTBUFSIZE, "%s -q -e %s %s ", program_name,
 2319        TEST_TARGET_FILE, TEST_DELTA_FILE);
 2320   if ((ret = do_fail (stream, buf))) { return ret; }
 2321 
 2322   /* Force it, should succeed. */
 2323   snprintf_func (buf, TESTBUFSIZE, "%s -f -e %s %s", program_name,
 2324        TEST_TARGET_FILE, TEST_DELTA_FILE);
 2325   if ((ret = do_cmd (stream, buf))) { return ret; }
 2326   test_cleanup();
 2327   return 0;
 2328 }
 2329 
 2330 /* This checks the proper operation of the -c flag.  When specified
 2331  * the default output becomes stdout, otherwise the input must be
 2332  * provided (encode) or it may be defaulted (decode w/ app header). */
 2333 static int
 2334 test_stdout_behavior (xd3_stream *stream, int ignore)
 2335 {
 2336   int ret;
 2337   char buf[TESTBUFSIZE];
 2338 
 2339   test_setup();
 2340   snprintf_func (buf, TESTBUFSIZE, "cp /dev/null %s", TEST_TARGET_FILE);
 2341   if ((ret = do_cmd (stream, buf))) { return ret; }
 2342 
 2343   /* Without -c, encode writes to delta file */
 2344   snprintf_func (buf, TESTBUFSIZE, "%s -e %s %s", program_name,
 2345        TEST_TARGET_FILE, TEST_DELTA_FILE);
 2346   if ((ret = do_cmd (stream, buf))) { return ret; }
 2347 
 2348   /* With -c, encode writes to stdout */
 2349   snprintf_func (buf, TESTBUFSIZE, "%s -e -c %s > %s", program_name,
 2350        TEST_TARGET_FILE, TEST_DELTA_FILE);
 2351   if ((ret = do_cmd (stream, buf))) { return ret; }
 2352 
 2353   /* Without -c, decode writes to target file name, but it fails because the
 2354    * file exists. */
 2355   snprintf_func (buf, TESTBUFSIZE, "%s -q -d %s ", program_name, TEST_DELTA_FILE);
 2356   if ((ret = do_fail (stream, buf))) { return ret; }
 2357 
 2358   /* With -c, decode writes to stdout */
 2359   snprintf_func (buf, TESTBUFSIZE, "%s -d -c %s > /dev/null", program_name, TEST_DELTA_FILE);
 2360   if ((ret = do_cmd (stream, buf))) { return ret; }
 2361   test_cleanup();
 2362 
 2363   return 0;
 2364 }
 2365 
 2366 /* This tests that the no-output flag (-J) works. */
 2367 static int
 2368 test_no_output (xd3_stream *stream, int ignore)
 2369 {
 2370   int ret;
 2371   char buf[TESTBUFSIZE];
 2372 
 2373   test_setup ();
 2374 
 2375   snprintf_func (buf, TESTBUFSIZE, "touch %s && chmod 0000 %s",
 2376        TEST_NOPERM_FILE, TEST_NOPERM_FILE);
 2377   if ((ret = do_cmd (stream, buf))) { return ret; }
 2378 
 2379   if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; }
 2380 
 2381   /* Try no_output encode w/out unwritable output file */
 2382   snprintf_func (buf, TESTBUFSIZE, "%s -q -f -e %s %s", program_name,
 2383        TEST_TARGET_FILE, TEST_NOPERM_FILE);
 2384   if ((ret = do_fail (stream, buf))) { return ret; }
 2385   snprintf_func (buf, TESTBUFSIZE, "%s -J -e %s %s", program_name,
 2386        TEST_TARGET_FILE, TEST_NOPERM_FILE);
 2387   if ((ret = do_cmd (stream, buf))) { return ret; }
 2388 
 2389   /* Now really write the delta to test decode no-output */
 2390   snprintf_func (buf, TESTBUFSIZE, "%s -e %s %s", program_name,
 2391        TEST_TARGET_FILE, TEST_DELTA_FILE);
 2392   if ((ret = do_cmd (stream, buf))) { return ret; }
 2393 
 2394   snprintf_func (buf, TESTBUFSIZE, "%s -q -f -d %s %s", program_name,
 2395        TEST_DELTA_FILE, TEST_NOPERM_FILE);
 2396   if ((ret = do_fail (stream, buf))) { return ret; }
 2397   snprintf_func (buf, TESTBUFSIZE, "%s -J -d %s %s", program_name,
 2398        TEST_DELTA_FILE, TEST_NOPERM_FILE);
 2399   if ((ret = do_cmd (stream, buf))) { return ret; }
 2400   test_cleanup ();
 2401   return 0;
 2402 }
 2403 
 2404 /* This tests that the default appheader works */
 2405 static int
 2406 test_appheader (xd3_stream *stream, int ignore)
 2407 {
 2408   int i;
 2409   int ret;
 2410   char buf[TESTBUFSIZE];
 2411   char bogus[TESTBUFSIZE];
 2412   xoff_t ssize, tsize;
 2413   test_setup ();
 2414 
 2415   if ((ret = test_make_inputs (stream, &ssize, &tsize))) { return ret; }
 2416 
 2417   snprintf_func (buf, TESTBUFSIZE, "%s -q -f -e -s %s %s %s", program_name,
 2418          TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE);
 2419   if ((ret = do_cmd (stream, buf))) { return ret; }
 2420 
 2421   if ((ret = test_copy_to (program_name, TEST_RECON2_FILE))) { return ret; }
 2422 
 2423   snprintf_func (buf, TESTBUFSIZE, "chmod 0700 %s", TEST_RECON2_FILE);
 2424   if ((ret = do_cmd (stream, buf))) { return ret; }
 2425 
 2426   if ((ret = test_save_copy (TEST_TARGET_FILE))) { return ret; }
 2427   if ((ret = test_copy_to (TEST_SOURCE_FILE, TEST_TARGET_FILE))) { return ret; }
 2428 
 2429   if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_COPY_FILE)) == 0)
 2430     {
 2431       return XD3_INVALID;  // I.e., files are different!
 2432     }
 2433 
 2434   // Test that the target file is restored.
 2435   snprintf_func (buf, TESTBUFSIZE, "(cd /tmp && %s -q -f -d %s)",
 2436          TEST_RECON2_FILE,
 2437          TEST_DELTA_FILE);
 2438   if ((ret = do_cmd (stream, buf))) { return ret; }
 2439 
 2440   if ((ret = test_compare_files (TEST_TARGET_FILE, TEST_COPY_FILE)) != 0)
 2441     {
 2442       return ret;
 2443     }
 2444 
 2445   // Test a malicious string w/ entries > 4 in the appheader by having
 2446   // the encoder write it:
 2447   for (i = 0; i < TESTBUFSIZE / 4; ++i)
 2448     {
 2449       bogus[2*i] = 'G';
 2450       bogus[2*i+1] = '/';
 2451     }
 2452   bogus[TESTBUFSIZE/2-1] = 0;
 2453 
 2454   snprintf_func (buf, TESTBUFSIZE, 
 2455          "%s -q -f -A=%s -e -s %s %s %s", program_name, bogus,
 2456          TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE);
 2457   if ((ret = do_cmd (stream, buf))) { return ret; }
 2458   // Then read it:
 2459   snprintf_func (buf, TESTBUFSIZE, "(cd /tmp && %s -q -f -d %s)",
 2460          TEST_RECON2_FILE,
 2461          TEST_DELTA_FILE);
 2462   if ((ret = do_cmd (stream, buf)) == 0) 
 2463     { 
 2464       return XD3_INVALID;  // Impossible
 2465     }
 2466   if (!WIFEXITED(ret))
 2467     {
 2468       return XD3_INVALID;  // Must have crashed!
 2469     }
 2470 
 2471   test_cleanup ();
 2472   return 0;
 2473 }
 2474 
 2475 /***********************************************************************
 2476  Source identical optimization
 2477  ***********************************************************************/
 2478 
 2479 /* Computing a delta should be fastest when the two inputs are
 2480  * identical, this checks it.  The library is called to compute a
 2481  * delta between a 10000 byte file, 1000 byte winsize, 500 byte source
 2482  * blocksize.  The same buffer is used for both source and target. */
 2483 static int
 2484 test_identical_behavior (xd3_stream *stream, int ignore)
 2485 {
 2486 #define IDB_TGTSZ 10000  /* Not a power of two b/c of hard-coded expectations below. */
 2487 #define IDB_BLKSZ 512
 2488 #define IDB_WINSZ 1000
 2489 #define IDB_DELSZ 1000
 2490 #define IDB_WINCNT (IDB_TGTSZ / IDB_WINSZ)
 2491 
 2492   int ret, i;
 2493   uint8_t buf[IDB_TGTSZ];
 2494   uint8_t del[IDB_DELSZ];
 2495   uint8_t rec[IDB_TGTSZ];
 2496   xd3_source source;
 2497   int nextencwin = 0;
 2498   int winstarts = 0, winfinishes = 0;
 2499   usize_t delpos = 0, recsize;
 2500   xd3_config config;
 2501   memset(&source, 0, sizeof(source));
 2502 
 2503   for (i = 0; i < IDB_TGTSZ; i += 1)
 2504     {
 2505       buf[i] = (uint8_t) mt_random (&static_mtrand);
 2506     }
 2507 
 2508   stream->winsize = IDB_WINSZ;
 2509 
 2510   source.blksize  = IDB_BLKSZ;
 2511   source.name     = "";
 2512   source.curblk   = NULL;
 2513   source.curblkno = 0;
 2514 
 2515   if ((ret = xd3_set_source (stream, & source))) { goto fail; }
 2516 
 2517   /* Compute an delta between identical source and targets. */
 2518   for (;;)
 2519     {
 2520       ret = xd3_encode_input (stream);
 2521 
 2522       if (ret == XD3_INPUT)
 2523     {
 2524       xd3_avail_input (stream, buf + (IDB_WINSZ * nextencwin), IDB_WINSZ);
 2525       nextencwin += 1;
 2526       continue;
 2527     }
 2528 
 2529       if (ret == XD3_GETSRCBLK)
 2530     {
 2531       source.curblkno = source.getblkno;
 2532       source.onblk    = IDB_BLKSZ;
 2533       source.curblk   = buf + source.getblkno * IDB_BLKSZ;
 2534       continue;
 2535     }
 2536 
 2537       if (ret == XD3_WINSTART)
 2538     {
 2539       winstarts++;
 2540       continue;
 2541     }
 2542       if (ret == XD3_WINFINISH)
 2543     {
 2544       winfinishes++;
 2545       if (winfinishes == IDB_WINCNT)
 2546         {
 2547           break;
 2548         }
 2549       continue;
 2550     }
 2551 
 2552       if (ret != XD3_OUTPUT) { goto fail; }
 2553 
 2554       CHECK(delpos + stream->avail_out <= IDB_DELSZ);
 2555 
 2556       memcpy (del + delpos, stream->next_out, stream->avail_out);
 2557 
 2558       delpos += stream->avail_out;
 2559 
 2560       xd3_consume_output (stream);
 2561     }
 2562 
 2563   CHECK(winfinishes == IDB_WINCNT);
 2564   CHECK(winstarts == IDB_WINCNT);
 2565   CHECK(nextencwin == IDB_WINCNT);
 2566 
 2567   /* Reset. */
 2568   memset(&source, 0, sizeof(source));
 2569   source.blksize  = IDB_TGTSZ;
 2570   source.onblk    = IDB_TGTSZ;
 2571   source.curblk   = buf;
 2572   source.curblkno = 0;
 2573 
 2574   if ((ret = xd3_close_stream (stream))) { goto fail; }
 2575   xd3_free_stream (stream);
 2576   xd3_init_config (& config, 0);
 2577   if ((ret = xd3_config_stream (stream, & config))) { goto fail; }
 2578   if ((ret = xd3_set_source_and_size (stream, & source, IDB_TGTSZ))) { goto fail; }
 2579 
 2580   /* Decode. */
 2581   if ((ret = xd3_decode_stream (stream, del, delpos, rec, & recsize, IDB_TGTSZ))) { goto fail; }
 2582 
 2583   /* Check result size and data. */
 2584   if (recsize != IDB_TGTSZ) { stream->msg = "wrong size reconstruction"; goto fail; }
 2585   if (memcmp (rec, buf, IDB_TGTSZ) != 0) { stream->msg = "wrong data reconstruction"; goto fail; }
 2586 
 2587   /* Check that there was one copy per window. */
 2588   IF_DEBUG (if (stream->n_scpy != IDB_WINCNT ||
 2589         stream->n_add != 0 ||
 2590         stream->n_run != 0) { stream->msg = "wrong copy count"; goto fail; });
 2591 
 2592   /* Check that no checksums were computed because the initial match
 2593      was presumed. */
 2594   IF_DEBUG (if (stream->large_ckcnt != 0) { stream->msg = "wrong checksum behavior"; goto fail; });
 2595 
 2596   ret = 0;
 2597  fail:
 2598   return ret;
 2599 }
 2600 
 2601 /***********************************************************************
 2602  String matching test
 2603  ***********************************************************************/
 2604 
 2605 /* Check particular matching behaviors by calling
 2606  * xd3_string_match_soft directly with specific arguments. */
 2607 typedef struct _string_match_test string_match_test;
 2608 
 2609 typedef enum
 2610 {
 2611   SM_NONE    = 0,
 2612   SM_LAZY    = (1 << 1),
 2613 } string_match_flags;
 2614 
 2615 struct _string_match_test
 2616 {
 2617   const char *input;
 2618   int         flags;
 2619   const char *result;
 2620 };
 2621 
 2622 static const string_match_test match_tests[] =
 2623 {
 2624   /* nothing */
 2625   { "1234567890", SM_NONE, "" },
 2626 
 2627   /* basic run, copy */
 2628   { "11111111112323232323", SM_NONE, "R0/10 C12/8@10" },
 2629 
 2630   /* no run smaller than MIN_RUN=8 */
 2631   { "1111111",  SM_NONE, "C1/6@0" },
 2632   { "11111111", SM_NONE, "R0/8" },
 2633 
 2634   /* simple promotion: the third copy address depends on promotion */
 2635   { "ABCDEF_ABCDEF^ABCDEF", SM_NONE,    "C7/6@0 C14/6@7" },
 2636   /* { "ABCDEF_ABCDEF^ABCDEF", SM_PROMOTE, "C7/6@0 C14/6@0" }, forgotten */
 2637 
 2638   /* simple lazy: there is a better copy starting with "23 X" than "123 " */
 2639   { "123 23 XYZ 123 XYZ", SM_NONE, "C11/4@0" },
 2640   { "123 23 XYZ 123 XYZ", SM_LAZY, "C11/4@0 C12/6@4" },
 2641 
 2642   /* trylazy: no lazy matches unless there are at least two characters beyond
 2643    * the first match */
 2644   { "2123_121212",   SM_LAZY, "C7/4@5" },
 2645   { "2123_1212123",  SM_LAZY, "C7/4@5" },
 2646   { "2123_1212123_", SM_LAZY, "C7/4@5 C8/5@0" },
 2647 
 2648   /* trylazy: no lazy matches if the copy is >= MAXLAZY=10 */
 2649   { "2123_121212123_",   SM_LAZY, "C7/6@5 C10/5@0" },
 2650   { "2123_12121212123_", SM_LAZY, "C7/8@5 C12/5@0" },
 2651   { "2123_1212121212123_", SM_LAZY, "C7/10@5" },
 2652 
 2653   /* lazy run: check a run overlapped by a longer copy */
 2654   { "11111112 111111112 1", SM_LAZY, "C1/6@0 R9/8 C10/10@0" },
 2655 
 2656   /* lazy match: match_length,run_l >= min_match tests, shouldn't get any
 2657    * copies within the run, no run within the copy */
 2658   { "^________^________  ", SM_LAZY, "R1/8 C9/9@0" },
 2659 
 2660   /* chain depth: it only goes back 10. this checks that the 10th match hits
 2661    * and the 11th misses. */
 2662   { "1234 1234_1234-1234=1234+1234[1234]1234{1234}1234<1234 ", SM_NONE,
 2663     "C5/4@0 C10/4@5 C15/4@10 C20/4@15 C25/4@20 C30/4@25 C35/4@30 C40/4@35 C45/4@40 C50/5@0" },
 2664   { "1234 1234_1234-1234=1234+1234[1234]1234{1234}1234<1234>1234 ", SM_NONE,
 2665     "C5/4@0 C10/4@5 C15/4@10 C20/4@15 C25/4@20 C30/4@25 C35/4@30 C40/4@35 C45/4@40 C50/4@45 C55/4@50" },
 2666 
 2667   /* ssmatch test */
 2668   { "ABCDE___ABCDE*** BCDE***", SM_NONE, "C8/5@0 C17/4@1" },
 2669   /*{ "ABCDE___ABCDE*** BCDE***", SM_SSMATCH, "C8/5@0 C17/7@9" }, forgotten */
 2670 };
 2671 
 2672 static int
 2673 test_string_matching (xd3_stream *stream, int ignore)
 2674 {
 2675   usize_t i;
 2676   int ret;
 2677   xd3_config config;
 2678   char rbuf[TESTBUFSIZE];
 2679 
 2680   for (i = 0; i < SIZEOF_ARRAY (match_tests); i += 1)
 2681     {
 2682       const string_match_test *test = & match_tests[i];
 2683       char *rptr = rbuf;
 2684       usize_t len = (usize_t) strlen (test->input);
 2685 
 2686       xd3_free_stream (stream);
 2687       xd3_init_config (& config, 0);
 2688 
 2689       config.smatch_cfg   = XD3_SMATCH_SOFT;
 2690       config.smatcher_soft.large_look   = 4;
 2691       config.smatcher_soft.large_step   = 4;
 2692       config.smatcher_soft.small_look   = 4;
 2693       config.smatcher_soft.small_chain  = 10;
 2694       config.smatcher_soft.small_lchain = 10;
 2695       config.smatcher_soft.max_lazy     = (test->flags & SM_LAZY) ? 10 : 0;
 2696       config.smatcher_soft.long_enough  = 10;
 2697 
 2698       if ((ret = xd3_config_stream (stream, & config))) { return ret; }
 2699       if ((ret = xd3_encode_init_full (stream))) { return ret; }
 2700 
 2701       xd3_avail_input (stream, (uint8_t*)test->input, len);
 2702 
 2703       if ((ret = stream->smatcher.string_match (stream))) { return ret; }
 2704 
 2705       *rptr = 0;
 2706       while (! xd3_rlist_empty (& stream->iopt_used))
 2707     {
 2708       xd3_rinst *inst = xd3_rlist_pop_front (& stream->iopt_used);
 2709 
 2710       switch (inst->type)
 2711         {
 2712         case XD3_RUN: *rptr++ = 'R'; break;
 2713         case XD3_CPY: *rptr++ = 'C'; break;
 2714         default: CHECK(0);
 2715         }
 2716 
 2717       snprintf_func (rptr, rbuf+TESTBUFSIZE-rptr, "%d/%d",
 2718              inst->pos, inst->size);
 2719       rptr += strlen (rptr);
 2720 
 2721       if (inst->type == XD3_CPY)
 2722         {
 2723           *rptr++ = '@';
 2724           snprintf_func (rptr, rbuf+TESTBUFSIZE-rptr, "%"Q"d", inst->addr);
 2725           rptr += strlen (rptr);
 2726         }
 2727 
 2728       *rptr++ = ' ';
 2729 
 2730       xd3_rlist_push_back (& stream->iopt_free, inst);
 2731     }
 2732 
 2733       if (rptr != rbuf)
 2734     {
 2735       rptr -= 1; *rptr = 0;
 2736     }
 2737 
 2738       if (strcmp (rbuf, test->result) != 0)
 2739     {
 2740       XPR(NT "test %u: expected %s: got %s", i, test->result, rbuf);
 2741       stream->msg = "wrong result";
 2742       return XD3_INTERNAL;
 2743     }
 2744     }
 2745 
 2746   return 0;
 2747 }
 2748 
 2749 /*
 2750  * This is a test for many overlapping instructions. It must be a lazy
 2751  * matcher.
 2752  */
 2753 static int
 2754 test_iopt_flush_instructions (xd3_stream *stream, int ignore)
 2755 {
 2756   int ret, i;
 2757   usize_t tpos = 0;
 2758   usize_t delta_size, recon_size;
 2759   xd3_config config;
 2760   uint8_t target[TESTBUFSIZE];
 2761   uint8_t delta[TESTBUFSIZE];
 2762   uint8_t recon[TESTBUFSIZE];
 2763 
 2764   xd3_free_stream (stream);
 2765   xd3_init_config (& config, 0);
 2766 
 2767   config.smatch_cfg    = XD3_SMATCH_SOFT;
 2768   config.smatcher_soft.large_look    = 16;
 2769   config.smatcher_soft.large_step    = 16;
 2770   config.smatcher_soft.small_look    = 4;
 2771   config.smatcher_soft.small_chain   = 128;
 2772   config.smatcher_soft.small_lchain  = 16;
 2773   config.smatcher_soft.max_lazy      = 8;
 2774   config.smatcher_soft.long_enough   = 128;
 2775 
 2776   if ((ret = xd3_config_stream (stream, & config))) { return ret; }
 2777 
 2778   for (i = 1; i < 250; i++)
 2779     {
 2780       target[tpos++] = i;
 2781       target[tpos++] = i+1;
 2782       target[tpos++] = i+2;
 2783       target[tpos++] = i+3;
 2784       target[tpos++] = 0;
 2785     }
 2786   for (i = 1; i < 253; i++)
 2787     {
 2788       target[tpos++] = i;
 2789     }
 2790 
 2791   if ((ret = xd3_encode_stream (stream, target, tpos,
 2792                     delta, & delta_size, sizeof (delta))))
 2793     {
 2794       return ret;
 2795     }
 2796 
 2797   xd3_free_stream(stream);
 2798   if ((ret = xd3_config_stream (stream, & config))) { return ret; }
 2799 
 2800   if ((ret = xd3_decode_stream (stream, delta, delta_size,
 2801                 recon, & recon_size, sizeof (recon))))
 2802     {
 2803       return ret;
 2804     }
 2805 
 2806   CHECK(tpos == recon_size);
 2807   CHECK(memcmp(target, recon, recon_size) == 0);
 2808 
 2809   return 0;
 2810 }
 2811 
 2812 /*
 2813  * This tests the 32/64bit ambiguity for source-window matching.
 2814  */
 2815 static int
 2816 test_source_cksum_offset (xd3_stream *stream, int ignore)
 2817 {
 2818   xd3_source source;
 2819 
 2820   // Inputs are:
 2821   struct {
 2822     xoff_t   cpos;   // stream->srcwin_cksum_pos;
 2823     xoff_t   ipos;   // stream->total_in;
 2824     xoff_t   size;   // stream->src->size;
 2825 
 2826     usize_t  input;  // input  32-bit offset
 2827     xoff_t   output; // output 64-bit offset
 2828 
 2829   } cksum_test[] = {
 2830     // If cpos is <= 2^32
 2831     { 1, 1, 1, 1, 1 },
 2832 
 2833 #if XD3_USE_LARGEFILE64
 2834 //    cpos            ipos            size            input         output
 2835 //    0x____xxxxxULL, 0x____xxxxxULL, 0x____xxxxxULL, 0x___xxxxxUL, 0x____xxxxxULL
 2836     { 0x100100000ULL, 0x100000000ULL, 0x100200000ULL, 0x00000000UL, 0x100000000ULL },
 2837     { 0x100100000ULL, 0x100000000ULL, 0x100200000ULL, 0xF0000000UL, 0x0F0000000ULL },
 2838 
 2839     { 0x100200000ULL, 0x100100000ULL, 0x100200000ULL, 0x00300000UL, 0x000300000ULL },
 2840 
 2841     { 25771983104ULL, 25770000000ULL, 26414808769ULL, 2139216707UL, 23614053187ULL },
 2842 
 2843 #endif
 2844 
 2845     { 0, 0, 0, 0, 0 },
 2846   }, *test_ptr;
 2847 
 2848   stream->src = &source;
 2849 
 2850   for (test_ptr = cksum_test; test_ptr->cpos; test_ptr++) {
 2851     xoff_t r;
 2852     stream->srcwin_cksum_pos = test_ptr->cpos;
 2853     stream->total_in = test_ptr->ipos;
 2854 
 2855     r = xd3_source_cksum_offset(stream, test_ptr->input);
 2856     CHECK(r == test_ptr->output);
 2857   }
 2858   return 0;
 2859 }
 2860 
 2861 static int
 2862 test_in_memory (xd3_stream *stream, int ignore)
 2863 {
 2864   // test_text is 256 bytes
 2865   uint8_t ibuf[sizeof(test_text)];
 2866   uint8_t dbuf[sizeof(test_text)];
 2867   uint8_t obuf[sizeof(test_text)];
 2868   usize_t size = sizeof(test_text);
 2869   usize_t dsize, osize;
 2870   int r1, r2;
 2871   int eflags = SECONDARY_DJW ? XD3_SEC_DJW : 0;
 2872 
 2873   memcpy(ibuf, test_text, size);
 2874   memset(ibuf + 128, 0, 16);
 2875 
 2876   r1 = xd3_encode_memory(ibuf, size,
 2877              test_text, size,
 2878              dbuf, &dsize, size, eflags);
 2879 
 2880   r2 = xd3_decode_memory(dbuf, dsize,
 2881              test_text, size,
 2882              obuf, &osize, size, 0);
 2883 
 2884   if (r1 != 0 || r2 != 0 || dsize >= (size/2) || dsize < 1 ||
 2885       osize != size) {
 2886     stream->msg = "encode/decode size error";
 2887     return XD3_INTERNAL;
 2888   }
 2889 
 2890   if (memcmp(obuf, ibuf, size) != 0) {
 2891     stream->msg = "encode/decode data error";
 2892     return XD3_INTERNAL;
 2893   }
 2894 
 2895   return 0;
 2896 }
 2897 
 2898 /***********************************************************************
 2899  TEST MAIN
 2900  ***********************************************************************/
 2901 
 2902 static int
 2903 xd3_selftest (void)
 2904 {
 2905 #define DO_TEST(fn,flags,arg)                                         \
 2906   do {                                                                \
 2907     xd3_stream stream;                                                \
 2908     xd3_config config;                                                \
 2909     xd3_init_config (& config, flags);                                \
 2910     XPR(NT "testing " #fn "%s...",                          \
 2911              flags ? (" (" #flags ")") : "");                         \
 2912     if ((ret = xd3_config_stream (& stream, & config) == 0) &&        \
 2913         (ret = test_ ## fn (& stream, arg)) == 0) {                   \
 2914       XPR(NTR " success\n");                                          \
 2915     } else {                                                          \
 2916       XPR(NTR " failed: %s: %s\n", xd3_errstring (& stream),          \
 2917                xd3_mainerror (ret)); }                                \
 2918     xd3_free_stream (& stream);                                       \
 2919     if (ret != 0) { goto failure; }                                   \
 2920   } while (0)
 2921 
 2922   int ret;
 2923   DO_TEST (random_numbers, 0, 0);
 2924   DO_TEST (printf_xoff, 0, 0);
 2925 
 2926   DO_TEST (decode_integer_end_of_input, 0, 0);
 2927   DO_TEST (decode_integer_overflow, 0, 0);
 2928   DO_TEST (encode_decode_uint32_t, 0, 0);
 2929   DO_TEST (encode_decode_uint64_t, 0, 0);
 2930   DO_TEST (usize_t_overflow, 0, 0);
 2931   DO_TEST (forward_match, 0, 0);
 2932 
 2933   DO_TEST (address_cache, 0, 0);
 2934 
 2935   DO_TEST (string_matching, 0, 0);
 2936   DO_TEST (choose_instruction, 0, 0);
 2937   DO_TEST (identical_behavior, 0, 0);
 2938   DO_TEST (in_memory, 0, 0);
 2939 
 2940   DO_TEST (iopt_flush_instructions, 0, 0);
 2941   DO_TEST (source_cksum_offset, 0, 0);
 2942 
 2943   DO_TEST (decompress_single_bit_error, 0, 3);
 2944   DO_TEST (decompress_single_bit_error, XD3_ADLER32, 3);
 2945 
 2946   IF_LZMA (DO_TEST (decompress_single_bit_error, XD3_SEC_LZMA, 54));
 2947   IF_FGK (DO_TEST (decompress_single_bit_error, XD3_SEC_FGK, 3));
 2948   IF_DJW (DO_TEST (decompress_single_bit_error, XD3_SEC_DJW, 8));
 2949 
 2950 #if SHELL_TESTS
 2951   DO_TEST (force_behavior, 0, 0);
 2952   DO_TEST (stdout_behavior, 0, 0);
 2953   DO_TEST (no_output, 0, 0);
 2954   DO_TEST (appheader, 0, 0);
 2955   DO_TEST (command_line_arguments, 0, 0);
 2956 
 2957 #if EXTERNAL_COMPRESSION
 2958   DO_TEST (source_decompression, 0, 0);
 2959   DO_TEST (externally_compressed_io, 0, 0);
 2960 #endif
 2961 
 2962   DO_TEST (recode_command, 0, 0);
 2963   IF_LZMA (DO_TEST (secondary_lzma_default, 0, 0));
 2964 #endif
 2965 
 2966   IF_LZMA (DO_TEST (secondary_lzma, 0, 1));
 2967   IF_DJW (DO_TEST (secondary_huff, 0, DJW_MAX_GROUPS));
 2968   IF_FGK (DO_TEST (secondary_fgk, 0, 1));
 2969 
 2970   DO_TEST (compressed_stream_overflow, 0, 0);
 2971   IF_LZMA (DO_TEST (compressed_stream_overflow, XD3_SEC_LZMA, 0));
 2972 
 2973 failure:
 2974   test_cleanup ();
 2975   return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 2976 #undef DO_TEST
 2977 }