1/************************************************************************
2 * Copyright (C) 2002-2009, Xiph.org Foundation
3 * Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 *     * Neither the names of the Xiph.org Foundation nor Pinknoise
17 * Productions Ltd nor the names of its contributors may be used to
18 * endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 ************************************************************************
33
34  function: packing variable sized words into an octet stream
35
36 ************************************************************************/
37
38/* We're 'LSb' endian; if we write a word but read individual bits,
39   then we'll read the lsb first */
40
41#include <string.h>
42#include <stdlib.h>
43#include "misc.h"
44#include "ogg.h"
45
46#include <stdio.h>
47
48
49#if !defined(ARM_LITTLE_ENDIAN) || defined(_V_BIT_TEST)
50static unsigned long mask[]=
51{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
52 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
53 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
54 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
55 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
56 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
57 0x3fffffff,0x7fffffff,0xffffffff };
58#endif
59
60#ifdef ARM_LITTLE_ENDIAN
61
62#ifdef DEBUGGING_BITWISE
63extern void oggpack_readinitARM(oggpack_buffer *b,ogg_reference *r);
64
65void oggpack_readinit(oggpack_buffer *b,ogg_reference *r){
66    oggpack_readinitARM(b,r);
67    //fprintf(stderr, "Init: buffer=(%d,%x,%d,%d) %08x%08x\n",
68    //        b->bitsLeftInSegment, b->ptr, b->bitsLeftInWord, b->count,
69    //        b->ptr[1], b->ptr[0]);
70    //fflush(stderr);
71}
72
73extern long oggpack_lookARM(oggpack_buffer *b,int bits);
74
75long oggpack_look(oggpack_buffer *b,int bits){
76    long l;
77
78    //fprintf(stderr, "PreLook: buffer=(%x,%x,%x) %08x%08x (%d bits)\n",
79    //        b->bitsLeftInSegment, b->ptr, b->bitsLeftInWord,
80    //        b->ptr[1], b->ptr[0], bits);
81    //fflush(stderr);
82    l = oggpack_lookARM(b,bits);
83    //fprintf(stderr, "Look: buffer=(%d,%x,%d,%d) %08x%08x (%d bits) (result=%x)\n",
84    //        b->bitsLeftInSegment, b->ptr, b->bitsLeftInWord, b->count,
85    //        b->ptr[1], b->ptr[0], bits, l);
86    //fflush(stderr);
87
88    return l;
89}
90
91extern void oggpack_advARM(oggpack_buffer *b,int bits);
92
93void oggpack_adv(oggpack_buffer *b,int bits){
94    //fprintf(stderr, "Adv before: buffer=(%x,%x,%x) %08x%08x (%d bits)\n",
95    //        b->bitsLeftInSegment, b->ptr, b->bitsLeftInWord,
96    //        b->ptr[1], b->ptr[0],bits);
97    //fflush(stderr);
98    oggpack_advARM(b,bits);
99    //fprintf(stderr, "Adv: buffer=(%d,%x,%d,%d) %08x%08x\n",
100    //        b->bitsLeftInSegment, b->ptr, b->bitsLeftInWord, b->count,
101    //        b->ptr[1], b->ptr[0]);
102    //fflush(stderr);
103}
104
105extern long oggpack_readARM(oggpack_buffer *b,int bits);
106
107/* bits <= 32 */
108long oggpack_read(oggpack_buffer *b,int bits){
109    long l;
110
111    //fprintf(stderr, "PreRead: buffer=(%d,%x,%d,%d) %08x%08x (%d bits)\n",
112    //        b->bitsLeftInSegment, b->ptr, b->bitsLeftInWord, b->count,
113    //        b->ptr[1], b->ptr[0], bits);
114    //fflush(stderr);
115    l = oggpack_readARM(b,bits);
116    //fprintf(stderr, "Read: buffer=(%d,%x,%d,%d) %08x%08x (%d bits) (result=%x)\n",
117    //       b->bitsLeftInSegment, b->ptr, b->bitsLeftInWord, b->count,
118    //       b->ptr[1], b->ptr[0], bits, l);
119    //fflush(stderr);
120
121    return l;
122}
123#endif
124
125int oggpack_eop(oggpack_buffer *b){
126  int ret;
127  if(b->bitsLeftInSegment<0)ret= -1;
128  else ret = 0;
129  //fprintf(stderr, "EOP %d\n", ret);
130  //fflush(stderr);
131  return ret;
132}
133
134long oggpack_bytes(oggpack_buffer *b){
135  long ret;
136  if(b->bitsLeftInSegment<0) ret = b->count+b->head->length;
137  else ret = b->count + b->head->length - (b->bitsLeftInSegment)/8;
138  //fprintf(stderr, "count=%d length=%d bitsLeftInSegment=%d\n",
139  //        b->count, b->head->length, b->bitsLeftInSegment);
140  //fflush(stderr);
141  return ret;
142}
143
144long oggpack_bits(oggpack_buffer *b){
145  long ret;
146  if(b->bitsLeftInSegment<0) ret=(b->count+b->head->length)*8;
147  else ret = b->count*8 + b->head->length*8 - b->bitsLeftInSegment;
148  //fprintf(stderr, "count=%d length=%d bitsLeftInSegment=%d\n",
149  //        b->count, b->head->length, b->bitsLeftInSegment);
150  //fflush(stderr);
151  return ret;
152}
153
154#else
155
156/* spans forward, skipping as many bytes as headend is negative; if
157   headend is zero, simply finds next byte.  If we're up to the end
158   of the buffer, leaves headend at zero.  If we've read past the end,
159   halt the decode process. */
160
161static void _span(oggpack_buffer *b){
162  while(b->headend-(b->headbit>>3)<1){
163    b->headend-=b->headbit>>3;
164    b->headbit&=0x7;
165
166    if(b->head && b->head->next){
167      b->count+=b->head->length;
168      b->head=b->head->next;
169
170      if(b->headend+b->head->length>0)
171	b->headptr=b->head->buffer->data+b->head->begin-b->headend;
172
173      b->headend+=b->head->length;
174    }else{
175      /* we've either met the end of decode, or gone past it. halt
176	 only if we're past */
177      if(b->headend*8<b->headbit)
178	/* read has fallen off the end */
179	b->headend=-1;
180        break;
181    }
182  }
183}
184
185void oggpack_readinit(oggpack_buffer *b,ogg_reference *r){
186  memset(b,0,sizeof(*b));
187
188  b->tail=b->head=r;
189  b->count=0;
190  if (b->head && r->length) {
191    b->headptr=b->head->buffer->data+b->head->begin;
192    b->headend=b->head->length;
193  } else {
194    b->headptr=0;
195    b->headend=0;
196  }
197  _span(b);
198
199  //fprintf(stderr,
200  //        "Init: buffer=(%d,%x,%d,%d) %02x%02x%02x%02x%02x%02x%02x%02x\n",
201  //        b->headbit, b->headptr, b->headend, b->count,
202  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
203  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0]);
204  //fflush(stderr);
205}
206
207#define _lookspan()   while(!end){\
208                        head=head->next;\
209                        if(!head) return -1;\
210                        ptr=head->buffer->data + head->begin;\
211                        end=head->length;\
212                      }
213
214/* Read in bits without advancing the bitptr; bits <= 32 */
215long oggpack_look(oggpack_buffer *b,int bits){
216  unsigned long m=mask[bits];
217  unsigned long ret = 0;
218  int BITS = bits;
219
220  if (!b->headptr) return 0;
221
222  bits+=b->headbit;
223
224  if(bits >= b->headend<<3){
225    int            end=b->headend;
226    unsigned char *ptr=b->headptr;
227    ogg_reference *head=b->head;
228
229    if(end<0)return 0;
230    if (!head || !end)return 0;
231
232    if(bits){
233      _lookspan();
234      ret=*ptr++>>b->headbit;
235      if(bits>8){
236        --end;
237        _lookspan();
238        ret|=*ptr++<<(8-b->headbit);
239        if(bits>16){
240          --end;
241          _lookspan();
242          ret|=*ptr++<<(16-b->headbit);
243          if(bits>24){
244            --end;
245            _lookspan();
246            ret|=*ptr++<<(24-b->headbit);
247            if(bits>32 && b->headbit){
248              --end;
249              _lookspan();
250              ret|=*ptr<<(32-b->headbit);
251            }
252          }
253        }
254      }
255    }
256
257  }else{
258
259    /* make this a switch jump-table */
260    ret=b->headptr[0]>>b->headbit;
261    if(bits>8){
262      ret|=b->headptr[1]<<(8-b->headbit);
263      if(bits>16){
264        ret|=b->headptr[2]<<(16-b->headbit);
265        if(bits>24){
266          ret|=b->headptr[3]<<(24-b->headbit);
267          if(bits>32 && b->headbit)
268            ret|=b->headptr[4]<<(32-b->headbit);
269        }
270      }
271    }
272  }
273
274  ret&=m;
275  //fprintf(stderr,
276  //        "Look: buffer=(%d,%x,%d,%d) %02x%02x%02x%02x%02x%02x%02x%02x (%d bits) return=%x\n",
277  //        b->headbit, b->headptr, b->headend, b->count,
278  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
279  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0],
280  //        BITS, ret);
281  //fflush(stderr);
282  return ret;
283}
284
285/* limited to 32 at a time */
286void oggpack_adv(oggpack_buffer *b,int bits){
287    int BITS=bits;
288  bits+=b->headbit;
289  b->headbit=bits&7;
290  b->headend-=(bits>>3);
291  b->headptr+=(bits>>3);
292  if(b->headend<1)_span(b);
293  //fprintf(stderr, "Adv: buffer=(%d,%x,%d,%d) %02x%02x%02x%02x%02x%02x%02x%02x (%d bits)\n",
294  //        b->headbit, b->headptr, b->headend,b->count,
295  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
296  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0],
297  //        BITS);
298  //fflush(stderr);
299}
300
301int oggpack_eop(oggpack_buffer *b){
302  int ret;
303  if(b->headend<0)ret= -1;
304  else ret = 0;
305  //fprintf(stderr, "EOP %d\n", ret);
306  //fflush(stderr);
307  return ret;
308}
309
310long oggpack_bytes(oggpack_buffer *b){
311  long ret;
312  if(b->headend<0) ret = b->count+b->head->length;
313  ret = b->count + b->head->length-b->headend + (b->headbit+7)/8;
314  //fprintf(stderr, "Bytes: buffer=(%d,%x,%d,%d) %02x%02x%02x%02x%02x%02x%02x%02x (%d bytes)\n",
315  //        b->headbit, b->headptr, b->headend, b->count,
316  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
317  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0],
318  //        ret);
319  //fflush(stderr);
320  return ret;
321}
322
323long oggpack_bits(oggpack_buffer *b){
324  long ret;
325  if(b->headend<0) ret = (b->count+b->head->length)*8;
326  else ret = (b->count + b->head->length-b->headend)*8 + b->headbit;
327  //fprintf(stderr, "Bits: buffer=(%x,%x,%x) %02x%02x%02x%02x%02x%02x%02x%02x (%d bits)\n",
328  //        b->headbit, b->headptr, b->headend,
329  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
330  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0],
331  //        ret);
332  //fflush(stderr);
333  return ret;
334}
335
336/* bits <= 32 */
337long oggpack_read(oggpack_buffer *b,int bits){
338  long ret=oggpack_look(b,bits);
339  oggpack_adv(b,bits);
340  return(ret);
341}
342
343#endif
344
345/* Self test of the bitwise routines; everything else is based on
346   them, so they damned well better be solid. */
347
348#ifdef _V_BIT_TEST
349#include <string.h>
350#include <stdlib.h>
351#include <stdio.h>
352#include "framing.c"
353
354static int ilog(unsigned long v){
355  int ret=0;
356  while(v){
357    ret++;
358    v>>=1;
359  }
360  return(ret);
361}
362
363oggpack_buffer r;
364oggpack_buffer o;
365ogg_buffer_state *bs;
366ogg_reference *or;
367#define TESTWORDS 256
368
369void report(char *in){
370  fprintf(stderr,"%s",in);
371  exit(1);
372}
373
374int getbyte(ogg_reference *or,int position){
375  while(or && position>=or->length){
376    position-=or->length;
377    or=or->next;
378    if(or==NULL){
379      fprintf(stderr,"\n\tERROR: getbyte ran off end of buffer.\n");
380      exit(1);
381    }
382  }
383
384  if((position+or->begin)&1)
385    return (or->buffer->data[(position+or->begin)>>1])&0xff;
386  else
387    return (or->buffer->data[(position+or->begin)>>1]>>8)&0xff;
388}
389
390void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){
391  long i,bitcount=0;
392  ogg_reference *or=ogg_buffer_alloc(bs,64);
393  for(i=0;i<compsize;i++)
394    or->buffer->data[i]= comp[i];
395  or->length=i;
396
397  oggpack_readinit(&r,or);
398  for(i=0;i<vals;i++){
399    unsigned long test;
400    int tbit=bits?bits:ilog(b[i]);
401    if((test=oggpack_look(&r,tbit))==0xffffffff)
402      report("out of data!\n");
403    if(test!=(b[i]&mask[tbit])){
404      fprintf(stderr,"%ld) %lx %lx\n",i,(b[i]&mask[tbit]),test);
405      report("looked at incorrect value!\n");
406    }
407    if((test=oggpack_read(&r,tbit))==0xffffffff){
408      report("premature end of data when reading!\n");
409    }
410    if(test!=(b[i]&mask[tbit])){
411      fprintf(stderr,"%ld) %lx %lx\n",i,(b[i]&mask[tbit]),test);
412      report("read incorrect value!\n");
413    }
414    bitcount+=tbit;
415
416    if(bitcount!=oggpack_bits(&r))
417      report("wrong number of bits while reading!\n");
418    if((bitcount+7)/8!=oggpack_bytes(&r))
419      report("wrong number of bytes while reading!\n");
420
421  }
422  if(oggpack_bytes(&r)!=(bitcount+7)/8){
423      fprintf(stderr, "%d vs %d\n", oggpack_bytes(&r), (bitcount+7)/8);
424      report("leftover bytes after read!\n");
425  }
426  ogg_buffer_release(or);
427}
428
429void _end_verify(int count){
430  int i;
431
432  /* are the proper number of bits left over? */
433  int leftover=count*8-oggpack_bits(&o);
434  if(leftover>7)
435    report("\nERROR: too many bits reported left over.\n");
436
437  /* does reading to exactly byte alignment *not* trip EOF? */
438  if(oggpack_read(&o,leftover)==-1)
439    report("\nERROR: read to but not past exact end tripped EOF.\n");
440  if(oggpack_bits(&o)!=count*8)
441    report("\nERROR: read to but not past exact end reported bad bitcount.\n");
442
443  /* does EOF trip properly after a single additional bit? */
444  if(oggpack_read(&o,1)!=-1)
445    report("\nERROR: read past exact end did not trip EOF.\n");
446  if(oggpack_bits(&o)!=count*8)
447    report("\nERROR: read past exact end reported bad bitcount.\n");
448
449  /* does EOF stay set over additional bit reads? */
450  for(i=0;i<=32;i++){
451    if(oggpack_read(&o,i)!=-1)
452      report("\nERROR: EOF did not stay set on stream.\n");
453    if(oggpack_bits(&o)!=count*8)
454      report("\nERROR: read past exact end reported bad bitcount.\n");
455  }
456}
457
458void _end_verify2(int count){
459  int i;
460
461  /* are the proper number of bits left over? */
462  int leftover=count*8-oggpack_bits(&o);
463  if(leftover>7)
464    report("\nERROR: too many bits reported left over.\n");
465
466  /* does reading to exactly byte alignment *not* trip EOF? */
467  oggpack_adv(&o,leftover);
468#ifdef ARM_LITTLE_ENDIAN
469    if(o.bitsLeftInSegment!=0)
470#else
471  if(o.headend!=0)
472#endif
473    report("\nERROR: read to but not past exact end tripped EOF.\n");
474  if(oggpack_bits(&o)!=count*8)
475    report("\nERROR: read to but not past exact end reported bad bitcount.\n");
476
477  /* does EOF trip properly after a single additional bit? */
478  oggpack_adv(&o,1);
479#ifdef ARM_LITTLE_ENDIAN
480    if(o.bitsLeftInSegment>=0)
481#else
482  if(o.headend>=0)
483#endif
484    report("\nERROR: read past exact end did not trip EOF.\n");
485  if(oggpack_bits(&o)!=count*8)
486    report("\nERROR: read past exact end reported bad bitcount.\n");
487
488  /* does EOF stay set over additional bit reads? */
489  for(i=0;i<=32;i++){
490    oggpack_adv(&o,i);
491#ifdef ARM_LITTLE_ENDIAN
492    if(o.bitsLeftInSegment>=0)
493#else
494    if(o.headend>=0)
495#endif
496      report("\nERROR: EOF did not stay set on stream.\n");
497    if(oggpack_bits(&o)!=count*8)
498      report("\nERROR: read past exact end reported bad bitcount.\n");
499  }
500}
501
502long ogg_buffer_length(ogg_reference *or){
503  int count=0;
504  while(or){
505    count+=or->length;
506    or=or->next;
507  }
508  return count;
509}
510
511ogg_reference *ogg_buffer_extend(ogg_reference *or,long bytes){
512  if(or){
513    while(or->next){
514      or=or->next;
515    }
516    or->next=ogg_buffer_alloc(or->buffer->ptr.owner,bytes);
517    return(or->next);
518  }
519  return 0;
520}
521
522void ogg_buffer_posttruncate(ogg_reference *or,long pos){
523  /* walk to the point where we want to begin truncate */
524  while(or && pos>or->length){
525    pos-=or->length;
526    or=or->next;
527  }
528  if(or){
529    ogg_buffer_release(or->next);
530    or->next=0;
531    or->length=pos;
532  }
533}
534
535int main(void){
536  long i;
537  static unsigned long testbuffer1[]=
538    {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
539       567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
540  int test1size=43;
541
542  static unsigned long testbuffer2[]=
543    {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212,
544       1233432,534,5,346435231,14436467,7869299,76326614,167548585,
545       85525151,0,12321,1,349528352};
546  int test2size=21;
547
548  static unsigned long testbuffer3[]=
549    {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,
550       0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
551  int test3size=56;
552
553  static unsigned long large[]=
554    {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212,
555       1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
556       85525151,0,12321,1,2146528352};
557
558  int onesize=33;
559  static int one[33]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
560                    34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
561                    223,4};
562
563  int twosize=6;
564  static int two[6]={61,255,255,251,231,29};
565
566  int threesize=54;
567  static int three[54]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
568                      142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
569                      58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
570                      100,52,4,14,18,86,77,1};
571
572  int foursize=38;
573  static int four[38]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
574                     132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
575                     28,2,133,0,1};
576
577  int fivesize=45;
578  static int five[45]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
579                     241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
580                     84,75,159,2,1,0,132,192,8,0,0,18,22};
581
582  int sixsize=7;
583  static int six[7]={17,177,170,242,169,19,148};
584
585  /* Test read/write together */
586  /* Later we test against pregenerated bitstreams */
587  bs=ogg_buffer_create();
588
589  fprintf(stderr,"\nSmall preclipped packing (LSb): ");
590  cliptest(testbuffer1,test1size,0,one,onesize);
591  fprintf(stderr,"ok.");
592
593  fprintf(stderr,"\nNull bit call (LSb): ");
594  cliptest(testbuffer3,test3size,0,two,twosize);
595  fprintf(stderr,"ok.");
596
597  fprintf(stderr,"\nLarge preclipped packing (LSb): ");
598  cliptest(testbuffer2,test2size,0,three,threesize);
599  fprintf(stderr,"ok.");
600
601  fprintf(stderr,"\n32 bit preclipped packing (LSb): ");
602
603  or=ogg_buffer_alloc(bs,128);
604  for(i=0;i<test2size;i++){
605    or->buffer->data[i*4]  = large[i]&0xff;
606    or->buffer->data[i*4+1]  = (large[i]>>8)&0xff;
607    or->buffer->data[i*4+2]  = (large[i]>>16)&0xff;
608    or->buffer->data[i*4+3]  = (large[i]>>24)&0xff;
609  }
610  or->length=test2size*4;
611  oggpack_readinit(&r,or);
612  for(i=0;i<test2size;i++){
613    unsigned long test;
614    if((test=oggpack_look(&r,32))==0xffffffffUL)report("out of data. failed!");
615    if(test!=large[i]){
616      fprintf(stderr,"%ld != %ld (%lx!=%lx):",test,large[i],
617              test,large[i]);
618      report("read incorrect value!\n");
619    }
620    oggpack_adv(&r,32);
621  }
622  ogg_buffer_release(or);
623  if(oggpack_bytes(&r)!=test2size*4){
624    fprintf(stderr, "%d vs %d\n", oggpack_bytes(&r), test2size*4);
625    report("leftover bytes after read!\n");
626  }
627  fprintf(stderr,"ok.");
628
629  fprintf(stderr,"\nSmall unclipped packing (LSb): ");
630  cliptest(testbuffer1,test1size,7,four,foursize);
631  fprintf(stderr,"ok.");
632
633  fprintf(stderr,"\nLarge unclipped packing (LSb): ");
634  cliptest(testbuffer2,test2size,17,five,fivesize);
635  fprintf(stderr,"ok.");
636
637  fprintf(stderr,"\nSingle bit unclipped packing (LSb): ");
638  cliptest(testbuffer3,test3size,1,six,sixsize);
639  fprintf(stderr,"ok.");
640
641  fprintf(stderr,"\nTesting read past end (LSb): ");
642  {
643    unsigned char dda[]={0,0,0,0};
644    ogg_buffer lob={dda,8,0,{0}};
645    ogg_reference lor={&lob,0,8,0};
646
647    oggpack_readinit(&r,&lor);
648    for(i=0;i<64;i++){
649      if(oggpack_read(&r,1)<0){
650        fprintf(stderr,"failed; got -1 prematurely.\n");
651        exit(1);
652      }
653    }
654    if(oggpack_look(&r,1)!=-1 ||
655       oggpack_read(&r,1)!=-1){
656      fprintf(stderr,"failed; read past end without -1.\n");
657      exit(1);
658    }
659  }
660  {
661    unsigned char dda[]={0,0,0,0};
662    ogg_buffer lob={dda,8,0,{0}};
663    ogg_reference lor={&lob,0,8,0};
664    unsigned long test;
665
666    oggpack_readinit(&r,&lor);
667    if((test=oggpack_read(&r,30))==0xffffffffUL ||
668       (test=oggpack_read(&r,16))==0xffffffffUL){
669      fprintf(stderr,"failed 2; got -1 prematurely.\n");
670      exit(1);
671    }
672
673    if((test=oggpack_look(&r,18))==0xffffffffUL){
674      fprintf(stderr,"failed 3; got -1 prematurely.\n");
675      exit(1);
676    }
677    if((test=oggpack_look(&r,19))!=0xffffffffUL){
678      fprintf(stderr,"failed; read past end without -1.\n");
679      exit(1);
680    }
681    if((test=oggpack_look(&r,32))!=0xffffffffUL){
682      fprintf(stderr,"failed; read past end without -1.\n");
683      exit(1);
684    }
685  }
686  fprintf(stderr,"ok.\n");
687
688  /* now the scary shit: randomized testing */
689
690  for(i=0;i<10000;i++){
691    long j,count=0,count2=0,bitcount=0;
692    unsigned long values[TESTWORDS];
693    int len[TESTWORDS];
694    unsigned char flat[4*TESTWORDS]; /* max possible needed size */
695
696    memset(flat,0,sizeof(flat));
697    fprintf(stderr,"\rRandomized testing (LSb)... (%ld)   ",10000-i);
698
699    /* generate a list of words and lengths */
700    /* write the required number of bits out to packbuffer */
701    {
702      long word=0;
703      long bit=0;
704      int k;
705
706      for(j=0;j<TESTWORDS;j++){
707	values[j]=rand();
708	len[j]=(rand()%33);
709
710	for(k=0;k<len[j];k++){
711	  flat[word] |= ((values[j]>>k)&0x1)<<bit;
712	  bit++;
713	  bitcount++;
714	  if(bit>7){
715	    bit=0;
716	    word++;
717	  }
718	}
719      }
720    }
721    count2=(bitcount+7)>>3;
722
723    /* construct random-length buffer chain from flat vector; random
724       byte starting offset within the length of the vector */
725    {
726      ogg_reference *or=NULL,*orl=NULL;
727      long pos=0;
728
729      /* build buffer chain */
730      while(count2){
731        int ilen=(rand()%32),k;
732        int ibegin=(rand()%32);
733
734
735        if(ilen>count2)ilen=count2;
736
737        if(or)
738          orl=ogg_buffer_extend(orl,64);
739        else
740          or=orl=ogg_buffer_alloc(bs,64);
741
742        orl->length=ilen;
743        orl->begin=ibegin;
744
745	for(k=0;k<ilen;k++)
746	  orl->buffer->data[ibegin++]= flat[pos++];
747
748        count2-=ilen;
749      }
750
751      if(ogg_buffer_length(or)!=(bitcount+7)/8){
752        fprintf(stderr,"\nERROR: buffer length incorrect after build.\n");
753        exit(1);
754      }
755
756
757      {
758        int begin=0; //=(rand()%TESTWORDS);
759        int ilen=(rand()%(TESTWORDS-begin));
760        int bitoffset,bitcount=0;
761        unsigned long temp;
762
763        for(j=0;j<begin;j++)
764          bitcount+=len[j];
765        or=ogg_buffer_pretruncate(or,bitcount/8);
766        bitoffset=bitcount%=8;
767        for(;j<begin+ilen;j++)
768          bitcount+=len[j];
769        ogg_buffer_posttruncate(or,((bitcount+7)/8));
770
771        if((count=ogg_buffer_length(or))!=(bitcount+7)/8){
772          fprintf(stderr,"\nERROR: buffer length incorrect after truncate.\n");
773          exit(1);
774        }
775
776        oggpack_readinit(&o,or);
777
778        /* verify bit count */
779        if(oggpack_bits(&o)!=0){
780          fprintf(stderr,"\nERROR: Read bitcounter not zero!\n");
781          exit(1);
782        }
783        if(oggpack_bytes(&o)!=0){
784          fprintf(stderr,"\nERROR: Read bytecounter not zero!\n");
785          exit(1);
786        }
787
788        bitcount=bitoffset;
789        oggpack_read(&o,bitoffset);
790
791        /* read and compare to original list */
792        for(j=begin;j<begin+ilen;j++){
793	  temp=oggpack_read(&o,len[j]);
794          if(temp==0xffffffffUL){
795            fprintf(stderr,"\nERROR: End of stream too soon! word: %ld,%d\n",
796                    j-begin,ilen);
797            exit(1);
798          }
799          if(temp!=(values[j]&mask[len[j]])){
800            fprintf(stderr,"\nERROR: Incorrect read %lx != %lx, word %ld, len %d\n"
801,
802                    values[j]&mask[len[j]],temp,j-begin,len[j]);
803            exit(1);
804          }
805          bitcount+=len[j];
806          if(oggpack_bits(&o)!=bitcount){
807            fprintf(stderr,"\nERROR: Read bitcounter %d != %ld!\n",
808                    bitcount,oggpack_bits(&o));
809            exit(1);
810          }
811          if(oggpack_bytes(&o)!=(bitcount+7)/8){
812            fprintf(stderr,"\nERROR: Read bytecounter %d != %ld!\n",
813                    (bitcount+7)/8,oggpack_bytes(&o));
814            exit(1);
815          }
816
817        }
818        _end_verify(count);
819
820        /* look/adv version */
821        oggpack_readinit(&o,or);
822        bitcount=bitoffset;
823        oggpack_adv(&o,bitoffset);
824
825        /* read and compare to original list */
826        for(j=begin;j<begin+ilen;j++){
827	  temp=oggpack_look(&o,len[j]);
828
829          if(temp==0xffffffffUL){
830            fprintf(stderr,"\nERROR: End of stream too soon! word: %ld\n",
831                    j-begin);
832            exit(1);
833          }
834          if(temp!=(values[j]&mask[len[j]])){
835            fprintf(stderr,"\nERROR: Incorrect look %lx != %lx, word %ld, len %d\n"
836,
837                    values[j]&mask[len[j]],temp,j-begin,len[j]);
838            exit(1);
839          }
840	  oggpack_adv(&o,len[j]);
841          bitcount+=len[j];
842          if(oggpack_bits(&o)!=bitcount){
843            fprintf(stderr,"\nERROR: Look/Adv bitcounter %d != %ld!\n",
844                    bitcount,oggpack_bits(&o));
845            exit(1);
846          }
847          if(oggpack_bytes(&o)!=(bitcount+7)/8){
848            fprintf(stderr,"\nERROR: Look/Adv bytecounter %d != %ld!\n",
849                    (bitcount+7)/8,oggpack_bytes(&o));
850            exit(1);
851          }
852
853        }
854        _end_verify2(count);
855
856      }
857      ogg_buffer_release(or);
858    }
859  }
860  fprintf(stderr,"\rRandomized testing (LSb)... ok.   \n");
861
862  return(0);
863}
864
865#ifdef _WIN32_WCE
866int WinMain(void){
867    return main();
868}
869#endif
870
871#endif
872