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) {
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  bits+=b->headbit;
221
222  if(bits >= b->headend<<3){
223    int            end=b->headend;
224    unsigned char *ptr=b->headptr;
225    ogg_reference *head=b->head;
226
227    if(end<0)return -1;
228    if (!head || !end)return -1;
229
230    if(bits){
231      _lookspan();
232      ret=*ptr++>>b->headbit;
233      if(bits>8){
234        --end;
235        _lookspan();
236        ret|=*ptr++<<(8-b->headbit);
237        if(bits>16){
238          --end;
239          _lookspan();
240          ret|=*ptr++<<(16-b->headbit);
241          if(bits>24){
242            --end;
243            _lookspan();
244            ret|=*ptr++<<(24-b->headbit);
245            if(bits>32 && b->headbit){
246              --end;
247              _lookspan();
248              ret|=*ptr<<(32-b->headbit);
249            }
250          }
251        }
252      }
253    }
254
255  }else{
256
257    /* make this a switch jump-table */
258    ret=b->headptr[0]>>b->headbit;
259    if(bits>8){
260      ret|=b->headptr[1]<<(8-b->headbit);
261      if(bits>16){
262        ret|=b->headptr[2]<<(16-b->headbit);
263        if(bits>24){
264          ret|=b->headptr[3]<<(24-b->headbit);
265          if(bits>32 && b->headbit)
266            ret|=b->headptr[4]<<(32-b->headbit);
267        }
268      }
269    }
270  }
271
272  ret&=m;
273  //fprintf(stderr,
274  //        "Look: buffer=(%d,%x,%d,%d) %02x%02x%02x%02x%02x%02x%02x%02x (%d bits) return=%x\n",
275  //        b->headbit, b->headptr, b->headend, b->count,
276  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
277  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0],
278  //        BITS, ret);
279  //fflush(stderr);
280  return ret;
281}
282
283/* limited to 32 at a time */
284void oggpack_adv(oggpack_buffer *b,int bits){
285    int BITS=bits;
286  bits+=b->headbit;
287  b->headbit=bits&7;
288  b->headend-=(bits>>3);
289  b->headptr+=(bits>>3);
290  if(b->headend<1)_span(b);
291  //fprintf(stderr, "Adv: buffer=(%d,%x,%d,%d) %02x%02x%02x%02x%02x%02x%02x%02x (%d bits)\n",
292  //        b->headbit, b->headptr, b->headend,b->count,
293  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
294  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0],
295  //        BITS);
296  //fflush(stderr);
297}
298
299int oggpack_eop(oggpack_buffer *b){
300  int ret;
301  if(b->headend<0)ret= -1;
302  else ret = 0;
303  //fprintf(stderr, "EOP %d\n", ret);
304  //fflush(stderr);
305  return ret;
306}
307
308long oggpack_bytes(oggpack_buffer *b){
309  long ret;
310  if(b->headend<0) ret = b->count+b->head->length;
311  ret = b->count + b->head->length-b->headend + (b->headbit+7)/8;
312  //fprintf(stderr, "Bytes: buffer=(%d,%x,%d,%d) %02x%02x%02x%02x%02x%02x%02x%02x (%d bytes)\n",
313  //        b->headbit, b->headptr, b->headend, b->count,
314  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
315  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0],
316  //        ret);
317  //fflush(stderr);
318  return ret;
319}
320
321long oggpack_bits(oggpack_buffer *b){
322  long ret;
323  if(b->headend<0) ret = (b->count+b->head->length)*8;
324  else ret = (b->count + b->head->length-b->headend)*8 + b->headbit;
325  //fprintf(stderr, "Bits: buffer=(%x,%x,%x) %02x%02x%02x%02x%02x%02x%02x%02x (%d bits)\n",
326  //        b->headbit, b->headptr, b->headend,
327  //        b->headptr[7], b->headptr[6], b->headptr[5], b->headptr[4],
328  //        b->headptr[3], b->headptr[2], b->headptr[1], b->headptr[0],
329  //        ret);
330  //fflush(stderr);
331  return ret;
332}
333
334/* bits <= 32 */
335long oggpack_read(oggpack_buffer *b,int bits){
336  long ret=oggpack_look(b,bits);
337  oggpack_adv(b,bits);
338  return(ret);
339}
340
341#endif
342
343/* Self test of the bitwise routines; everything else is based on
344   them, so they damned well better be solid. */
345
346#ifdef _V_BIT_TEST
347#include <string.h>
348#include <stdlib.h>
349#include <stdio.h>
350#include "framing.c"
351
352static int ilog(unsigned long v){
353  int ret=0;
354  while(v){
355    ret++;
356    v>>=1;
357  }
358  return(ret);
359}
360
361oggpack_buffer r;
362oggpack_buffer o;
363ogg_buffer_state *bs;
364ogg_reference *or;
365#define TESTWORDS 256
366
367void report(char *in){
368  fprintf(stderr,"%s",in);
369  exit(1);
370}
371
372int getbyte(ogg_reference *or,int position){
373  while(or && position>=or->length){
374    position-=or->length;
375    or=or->next;
376    if(or==NULL){
377      fprintf(stderr,"\n\tERROR: getbyte ran off end of buffer.\n");
378      exit(1);
379    }
380  }
381
382  if((position+or->begin)&1)
383    return (or->buffer->data[(position+or->begin)>>1])&0xff;
384  else
385    return (or->buffer->data[(position+or->begin)>>1]>>8)&0xff;
386}
387
388void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){
389  long i,bitcount=0;
390  ogg_reference *or=ogg_buffer_alloc(bs,64);
391  for(i=0;i<compsize;i++)
392    or->buffer->data[i]= comp[i];
393  or->length=i;
394
395  oggpack_readinit(&r,or);
396  for(i=0;i<vals;i++){
397    unsigned long test;
398    int tbit=bits?bits:ilog(b[i]);
399    if((test=oggpack_look(&r,tbit))==0xffffffff)
400      report("out of data!\n");
401    if(test!=(b[i]&mask[tbit])){
402      fprintf(stderr,"%ld) %lx %lx\n",i,(b[i]&mask[tbit]),test);
403      report("looked at incorrect value!\n");
404    }
405    if((test=oggpack_read(&r,tbit))==0xffffffff){
406      report("premature end of data when reading!\n");
407    }
408    if(test!=(b[i]&mask[tbit])){
409      fprintf(stderr,"%ld) %lx %lx\n",i,(b[i]&mask[tbit]),test);
410      report("read incorrect value!\n");
411    }
412    bitcount+=tbit;
413
414    if(bitcount!=oggpack_bits(&r))
415      report("wrong number of bits while reading!\n");
416    if((bitcount+7)/8!=oggpack_bytes(&r))
417      report("wrong number of bytes while reading!\n");
418
419  }
420  if(oggpack_bytes(&r)!=(bitcount+7)/8){
421      fprintf(stderr, "%d vs %d\n", oggpack_bytes(&r), (bitcount+7)/8);
422      report("leftover bytes after read!\n");
423  }
424  ogg_buffer_release(or);
425}
426
427void _end_verify(int count){
428  int i;
429
430  /* are the proper number of bits left over? */
431  int leftover=count*8-oggpack_bits(&o);
432  if(leftover>7)
433    report("\nERROR: too many bits reported left over.\n");
434
435  /* does reading to exactly byte alignment *not* trip EOF? */
436  if(oggpack_read(&o,leftover)==-1)
437    report("\nERROR: read to but not past exact end tripped EOF.\n");
438  if(oggpack_bits(&o)!=count*8)
439    report("\nERROR: read to but not past exact end reported bad bitcount.\n");
440
441  /* does EOF trip properly after a single additional bit? */
442  if(oggpack_read(&o,1)!=-1)
443    report("\nERROR: read past exact end did not trip EOF.\n");
444  if(oggpack_bits(&o)!=count*8)
445    report("\nERROR: read past exact end reported bad bitcount.\n");
446
447  /* does EOF stay set over additional bit reads? */
448  for(i=0;i<=32;i++){
449    if(oggpack_read(&o,i)!=-1)
450      report("\nERROR: EOF did not stay set on stream.\n");
451    if(oggpack_bits(&o)!=count*8)
452      report("\nERROR: read past exact end reported bad bitcount.\n");
453  }
454}
455
456void _end_verify2(int count){
457  int i;
458
459  /* are the proper number of bits left over? */
460  int leftover=count*8-oggpack_bits(&o);
461  if(leftover>7)
462    report("\nERROR: too many bits reported left over.\n");
463
464  /* does reading to exactly byte alignment *not* trip EOF? */
465  oggpack_adv(&o,leftover);
466#ifdef ARM_LITTLE_ENDIAN
467    if(o.bitsLeftInSegment!=0)
468#else
469  if(o.headend!=0)
470#endif
471    report("\nERROR: read to but not past exact end tripped EOF.\n");
472  if(oggpack_bits(&o)!=count*8)
473    report("\nERROR: read to but not past exact end reported bad bitcount.\n");
474
475  /* does EOF trip properly after a single additional bit? */
476  oggpack_adv(&o,1);
477#ifdef ARM_LITTLE_ENDIAN
478    if(o.bitsLeftInSegment>=0)
479#else
480  if(o.headend>=0)
481#endif
482    report("\nERROR: read past exact end did not trip EOF.\n");
483  if(oggpack_bits(&o)!=count*8)
484    report("\nERROR: read past exact end reported bad bitcount.\n");
485
486  /* does EOF stay set over additional bit reads? */
487  for(i=0;i<=32;i++){
488    oggpack_adv(&o,i);
489#ifdef ARM_LITTLE_ENDIAN
490    if(o.bitsLeftInSegment>=0)
491#else
492    if(o.headend>=0)
493#endif
494      report("\nERROR: EOF did not stay set on stream.\n");
495    if(oggpack_bits(&o)!=count*8)
496      report("\nERROR: read past exact end reported bad bitcount.\n");
497  }
498}
499
500long ogg_buffer_length(ogg_reference *or){
501  int count=0;
502  while(or){
503    count+=or->length;
504    or=or->next;
505  }
506  return count;
507}
508
509ogg_reference *ogg_buffer_extend(ogg_reference *or,long bytes){
510  if(or){
511    while(or->next){
512      or=or->next;
513    }
514    or->next=ogg_buffer_alloc(or->buffer->ptr.owner,bytes);
515    return(or->next);
516  }
517  return 0;
518}
519
520void ogg_buffer_posttruncate(ogg_reference *or,long pos){
521  /* walk to the point where we want to begin truncate */
522  while(or && pos>or->length){
523    pos-=or->length;
524    or=or->next;
525  }
526  if(or){
527    ogg_buffer_release(or->next);
528    or->next=0;
529    or->length=pos;
530  }
531}
532
533int main(void){
534  long i;
535  static unsigned long testbuffer1[]=
536    {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
537       567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
538  int test1size=43;
539
540  static unsigned long testbuffer2[]=
541    {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212,
542       1233432,534,5,346435231,14436467,7869299,76326614,167548585,
543       85525151,0,12321,1,349528352};
544  int test2size=21;
545
546  static unsigned long testbuffer3[]=
547    {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,
548       0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
549  int test3size=56;
550
551  static unsigned long large[]=
552    {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212,
553       1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
554       85525151,0,12321,1,2146528352};
555
556  int onesize=33;
557  static int one[33]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
558                    34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
559                    223,4};
560
561  int twosize=6;
562  static int two[6]={61,255,255,251,231,29};
563
564  int threesize=54;
565  static int three[54]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
566                      142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
567                      58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
568                      100,52,4,14,18,86,77,1};
569
570  int foursize=38;
571  static int four[38]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
572                     132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
573                     28,2,133,0,1};
574
575  int fivesize=45;
576  static int five[45]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
577                     241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
578                     84,75,159,2,1,0,132,192,8,0,0,18,22};
579
580  int sixsize=7;
581  static int six[7]={17,177,170,242,169,19,148};
582
583  /* Test read/write together */
584  /* Later we test against pregenerated bitstreams */
585  bs=ogg_buffer_create();
586
587  fprintf(stderr,"\nSmall preclipped packing (LSb): ");
588  cliptest(testbuffer1,test1size,0,one,onesize);
589  fprintf(stderr,"ok.");
590
591  fprintf(stderr,"\nNull bit call (LSb): ");
592  cliptest(testbuffer3,test3size,0,two,twosize);
593  fprintf(stderr,"ok.");
594
595  fprintf(stderr,"\nLarge preclipped packing (LSb): ");
596  cliptest(testbuffer2,test2size,0,three,threesize);
597  fprintf(stderr,"ok.");
598
599  fprintf(stderr,"\n32 bit preclipped packing (LSb): ");
600
601  or=ogg_buffer_alloc(bs,128);
602  for(i=0;i<test2size;i++){
603    or->buffer->data[i*4]  = large[i]&0xff;
604    or->buffer->data[i*4+1]  = (large[i]>>8)&0xff;
605    or->buffer->data[i*4+2]  = (large[i]>>16)&0xff;
606    or->buffer->data[i*4+3]  = (large[i]>>24)&0xff;
607  }
608  or->length=test2size*4;
609  oggpack_readinit(&r,or);
610  for(i=0;i<test2size;i++){
611    unsigned long test;
612    if((test=oggpack_look(&r,32))==0xffffffffUL)report("out of data. failed!");
613    if(test!=large[i]){
614      fprintf(stderr,"%ld != %ld (%lx!=%lx):",test,large[i],
615              test,large[i]);
616      report("read incorrect value!\n");
617    }
618    oggpack_adv(&r,32);
619  }
620  ogg_buffer_release(or);
621  if(oggpack_bytes(&r)!=test2size*4){
622    fprintf(stderr, "%d vs %d\n", oggpack_bytes(&r), test2size*4);
623    report("leftover bytes after read!\n");
624  }
625  fprintf(stderr,"ok.");
626
627  fprintf(stderr,"\nSmall unclipped packing (LSb): ");
628  cliptest(testbuffer1,test1size,7,four,foursize);
629  fprintf(stderr,"ok.");
630
631  fprintf(stderr,"\nLarge unclipped packing (LSb): ");
632  cliptest(testbuffer2,test2size,17,five,fivesize);
633  fprintf(stderr,"ok.");
634
635  fprintf(stderr,"\nSingle bit unclipped packing (LSb): ");
636  cliptest(testbuffer3,test3size,1,six,sixsize);
637  fprintf(stderr,"ok.");
638
639  fprintf(stderr,"\nTesting read past end (LSb): ");
640  {
641    unsigned char dda[]={0,0,0,0};
642    ogg_buffer lob={dda,8,0,{0}};
643    ogg_reference lor={&lob,0,8,0};
644
645    oggpack_readinit(&r,&lor);
646    for(i=0;i<64;i++){
647      if(oggpack_read(&r,1)<0){
648        fprintf(stderr,"failed; got -1 prematurely.\n");
649        exit(1);
650      }
651    }
652    if(oggpack_look(&r,1)!=-1 ||
653       oggpack_read(&r,1)!=-1){
654      fprintf(stderr,"failed; read past end without -1.\n");
655      exit(1);
656    }
657  }
658  {
659    unsigned char dda[]={0,0,0,0};
660    ogg_buffer lob={dda,8,0,{0}};
661    ogg_reference lor={&lob,0,8,0};
662    unsigned long test;
663
664    oggpack_readinit(&r,&lor);
665    if((test=oggpack_read(&r,30))==0xffffffffUL ||
666       (test=oggpack_read(&r,16))==0xffffffffUL){
667      fprintf(stderr,"failed 2; got -1 prematurely.\n");
668      exit(1);
669    }
670
671    if((test=oggpack_look(&r,18))==0xffffffffUL){
672      fprintf(stderr,"failed 3; got -1 prematurely.\n");
673      exit(1);
674    }
675    if((test=oggpack_look(&r,19))!=0xffffffffUL){
676      fprintf(stderr,"failed; read past end without -1.\n");
677      exit(1);
678    }
679    if((test=oggpack_look(&r,32))!=0xffffffffUL){
680      fprintf(stderr,"failed; read past end without -1.\n");
681      exit(1);
682    }
683  }
684  fprintf(stderr,"ok.\n");
685
686  /* now the scary shit: randomized testing */
687
688  for(i=0;i<10000;i++){
689    long j,count=0,count2=0,bitcount=0;
690    unsigned long values[TESTWORDS];
691    int len[TESTWORDS];
692    unsigned char flat[4*TESTWORDS]; /* max possible needed size */
693
694    memset(flat,0,sizeof(flat));
695    fprintf(stderr,"\rRandomized testing (LSb)... (%ld)   ",10000-i);
696
697    /* generate a list of words and lengths */
698    /* write the required number of bits out to packbuffer */
699    {
700      long word=0;
701      long bit=0;
702      int k;
703
704      for(j=0;j<TESTWORDS;j++){
705	values[j]=rand();
706	len[j]=(rand()%33);
707
708	for(k=0;k<len[j];k++){
709	  flat[word] |= ((values[j]>>k)&0x1)<<bit;
710	  bit++;
711	  bitcount++;
712	  if(bit>7){
713	    bit=0;
714	    word++;
715	  }
716	}
717      }
718    }
719    count2=(bitcount+7)>>3;
720
721    /* construct random-length buffer chain from flat vector; random
722       byte starting offset within the length of the vector */
723    {
724      ogg_reference *or=NULL,*orl=NULL;
725      long pos=0;
726
727      /* build buffer chain */
728      while(count2){
729        int ilen=(rand()%32),k;
730        int ibegin=(rand()%32);
731
732
733        if(ilen>count2)ilen=count2;
734
735        if(or)
736          orl=ogg_buffer_extend(orl,64);
737        else
738          or=orl=ogg_buffer_alloc(bs,64);
739
740        orl->length=ilen;
741        orl->begin=ibegin;
742
743	for(k=0;k<ilen;k++)
744	  orl->buffer->data[ibegin++]= flat[pos++];
745
746        count2-=ilen;
747      }
748
749      if(ogg_buffer_length(or)!=(bitcount+7)/8){
750        fprintf(stderr,"\nERROR: buffer length incorrect after build.\n");
751        exit(1);
752      }
753
754
755      {
756        int begin=0; //=(rand()%TESTWORDS);
757        int ilen=(rand()%(TESTWORDS-begin));
758        int bitoffset,bitcount=0;
759        unsigned long temp;
760
761        for(j=0;j<begin;j++)
762          bitcount+=len[j];
763        or=ogg_buffer_pretruncate(or,bitcount/8);
764        bitoffset=bitcount%=8;
765        for(;j<begin+ilen;j++)
766          bitcount+=len[j];
767        ogg_buffer_posttruncate(or,((bitcount+7)/8));
768
769        if((count=ogg_buffer_length(or))!=(bitcount+7)/8){
770          fprintf(stderr,"\nERROR: buffer length incorrect after truncate.\n");
771          exit(1);
772        }
773
774        oggpack_readinit(&o,or);
775
776        /* verify bit count */
777        if(oggpack_bits(&o)!=0){
778          fprintf(stderr,"\nERROR: Read bitcounter not zero!\n");
779          exit(1);
780        }
781        if(oggpack_bytes(&o)!=0){
782          fprintf(stderr,"\nERROR: Read bytecounter not zero!\n");
783          exit(1);
784        }
785
786        bitcount=bitoffset;
787        oggpack_read(&o,bitoffset);
788
789        /* read and compare to original list */
790        for(j=begin;j<begin+ilen;j++){
791	  temp=oggpack_read(&o,len[j]);
792          if(temp==0xffffffffUL){
793            fprintf(stderr,"\nERROR: End of stream too soon! word: %ld,%d\n",
794                    j-begin,ilen);
795            exit(1);
796          }
797          if(temp!=(values[j]&mask[len[j]])){
798            fprintf(stderr,"\nERROR: Incorrect read %lx != %lx, word %ld, len %d\n"
799,
800                    values[j]&mask[len[j]],temp,j-begin,len[j]);
801            exit(1);
802          }
803          bitcount+=len[j];
804          if(oggpack_bits(&o)!=bitcount){
805            fprintf(stderr,"\nERROR: Read bitcounter %d != %ld!\n",
806                    bitcount,oggpack_bits(&o));
807            exit(1);
808          }
809          if(oggpack_bytes(&o)!=(bitcount+7)/8){
810            fprintf(stderr,"\nERROR: Read bytecounter %d != %ld!\n",
811                    (bitcount+7)/8,oggpack_bytes(&o));
812            exit(1);
813          }
814
815        }
816        _end_verify(count);
817
818        /* look/adv version */
819        oggpack_readinit(&o,or);
820        bitcount=bitoffset;
821        oggpack_adv(&o,bitoffset);
822
823        /* read and compare to original list */
824        for(j=begin;j<begin+ilen;j++){
825	  temp=oggpack_look(&o,len[j]);
826
827          if(temp==0xffffffffUL){
828            fprintf(stderr,"\nERROR: End of stream too soon! word: %ld\n",
829                    j-begin);
830            exit(1);
831          }
832          if(temp!=(values[j]&mask[len[j]])){
833            fprintf(stderr,"\nERROR: Incorrect look %lx != %lx, word %ld, len %d\n"
834,
835                    values[j]&mask[len[j]],temp,j-begin,len[j]);
836            exit(1);
837          }
838	  oggpack_adv(&o,len[j]);
839          bitcount+=len[j];
840          if(oggpack_bits(&o)!=bitcount){
841            fprintf(stderr,"\nERROR: Look/Adv bitcounter %d != %ld!\n",
842                    bitcount,oggpack_bits(&o));
843            exit(1);
844          }
845          if(oggpack_bytes(&o)!=(bitcount+7)/8){
846            fprintf(stderr,"\nERROR: Look/Adv bytecounter %d != %ld!\n",
847                    (bitcount+7)/8,oggpack_bytes(&o));
848            exit(1);
849          }
850
851        }
852        _end_verify2(count);
853
854      }
855      ogg_buffer_release(or);
856    }
857  }
858  fprintf(stderr,"\rRandomized testing (LSb)... ok.   \n");
859
860  return(0);
861}
862
863#ifdef _WIN32_WCE
864int WinMain(void){
865    return main();
866}
867#endif
868
869#endif
870