+/* -*-mode:java; c-basic-offset:2; -*- */
+/* JOrbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk<ymnk@jcraft.com>
+ *
+ * Many thanks to
+ * Monty <monty@xiph.org> and
+ * The XIPHOPHORUS Company http://www.xiph.org/ .
+ * JOrbis has been based on their awesome works, Vorbis codec.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jogg;
+
+public class Page{
+ private static int[] crc_lookup=new int[256];
+ static {
+ for(int i=0; i<crc_lookup.length; i++){
+ crc_lookup[i]=crc_entry(i);
+ }
+ }
+
+ private static int crc_entry(int index){
+ int r=index<<24;
+ for(int i=0; i<8; i++){
+ if((r& 0x80000000)!=0){
+ r=(r << 1)^0x04c11db7; /* The same as the ethernet generator
+ polynomial, although we use an
+ unreflected alg and an init/final
+ of 0, not 0xffffffff */
+ }
+ else{
+ r<<=1;
+ }
+ }
+ return(r&0xffffffff);
+ }
+
+ public byte[] header_base;
+ public int header;
+ public int header_len;
+ public byte[] body_base;
+ public int body;
+ public int body_len;
+
+ int version(){
+ return header_base[header+4]&0xff;
+ }
+ int continued(){
+ return (header_base[header+5]&0x01);
+ }
+ public int bos(){
+ return (header_base[header+5]&0x02);
+ }
+ public int eos(){
+ return (header_base[header+5]&0x04);
+ }
+ public long granulepos(){
+ long foo=header_base[header+13]&0xff;
+ foo=(foo<<8)|(header_base[header+12]&0xff);
+ foo=(foo<<8)|(header_base[header+11]&0xff);
+ foo=(foo<<8)|(header_base[header+10]&0xff);
+ foo=(foo<<8)|(header_base[header+9]&0xff);
+ foo=(foo<<8)|(header_base[header+8]&0xff);
+ foo=(foo<<8)|(header_base[header+7]&0xff);
+ foo=(foo<<8)|(header_base[header+6]&0xff);
+ return(foo);
+ }
+ public int serialno(){
+ return (header_base[header+14]&0xff)|
+ ((header_base[header+15]&0xff)<<8)|
+ ((header_base[header+16]&0xff)<<16)|
+ ((header_base[header+17]&0xff)<<24);
+ }
+ int pageno(){
+ return (header_base[header+18]&0xff)|
+ ((header_base[header+19]&0xff)<<8)|
+ ((header_base[header+20]&0xff)<<16)|
+ ((header_base[header+21]&0xff)<<24);
+ }
+
+ void checksum(){
+ int crc_reg=0;
+
+// for(int i=0;i<header_len;i++){
+// System.err.println("chksum: "+Integer.toHexString(header_base[header+i]&0xff));
+// }
+
+ for(int i=0;i<header_len;i++){
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg>>>24)&0xff)^(header_base[header+i]&0xff)];
+ }
+ for(int i=0;i<body_len;i++){
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg>>>24)&0xff)^(body_base[body+i]&0xff)];
+ }
+ header_base[header+22]=(byte)crc_reg/*&0xff*/;
+ header_base[header+23]=(byte)(crc_reg>>>8)/*&0xff*/;
+ header_base[header+24]=(byte)(crc_reg>>>16)/*&0xff*/;
+ header_base[header+25]=(byte)(crc_reg>>>24)/*&0xff*/;
+ }
+ public Page copy(){
+ return copy(new Page());
+ }
+ public Page copy(Page p){
+ byte[] tmp=new byte[header_len];
+ System.arraycopy(header_base, header, tmp, 0, header_len);
+ p.header_len=header_len;
+ p.header_base=tmp;
+ p.header=0;
+ tmp=new byte[body_len];
+ System.arraycopy(body_base, body, tmp, 0, body_len);
+ p.body_len=body_len;
+ p.body_base=tmp;
+ p.body=0;
+ return p;
+ }
+ /*
+ // TEST
+ static StreamState os_en, os_de;
+ static SyncState oy;
+ void check_page(byte[] data_base, int data, int[] _header){
+ // Test data
+ for(int j=0;j<body_len;j++)
+ if(body_base[body+j]!=data_base[data+j]){
+ System.err.println("body data mismatch at pos "+j+": "+data_base[data+j]+"!="+body_base[body+j]+"!\n");
+ System.exit(1);
+ }
+
+ // Test header
+ for(int j=0;j<header_len;j++){
+ if((header_base[header+j]&0xff)!=_header[j]){
+ System.err.println("header content mismatch at pos "+j);
+ for(int jj=0;jj<_header[26]+27;jj++)
+ System.err.print(" ("+jj+")"+Integer.toHexString(_header[jj])+":"+Integer.toHexString(header_base[header+jj]));
+ System.err.println("");
+ System.exit(1);
+ }
+ }
+ if(header_len!=_header[26]+27){
+ System.err.print("header length incorrect! ("+header_len+"!="+(_header[26]+27)+")");
+ System.exit(1);
+ }
+ }
+
+ void print_header(){
+ System.err.println("\nHEADER:");
+ System.err.println(" capture: "+
+ (header_base[header+0]&0xff)+" "+
+ (header_base[header+1]&0xff)+" "+
+ (header_base[header+2]&0xff)+" "+
+ (header_base[header+3]&0xff)+" "+
+ " version: "+(header_base[header+4]&0xff)+" flags: "+
+ (header_base[header+5]&0xff));
+ System.err.println(" pcmpos: "+
+ (((header_base[header+9]&0xff)<<24)|
+ ((header_base[header+8]&0xff)<<16)|
+ ((header_base[header+7]&0xff)<<8)|
+ ((header_base[header+6]&0xff)))+
+ " serialno: "+
+ (((header_base[header+17]&0xff)<<24)|
+ ((header_base[header+16]&0xff)<<16)|
+ ((header_base[header+15]&0xff)<<8)|
+ ((header_base[header+14]&0xff)))+
+ " pageno: "+
+ (((header_base[header+21]&0xff)<<24)|
+ ((header_base[header+20]&0xff)<<16)|
+ ((header_base[header+19]&0xff)<<8)|
+ ((header_base[header+18]&0xff))));
+
+ System.err.println(" checksum: "+
+ (header_base[header+22]&0xff)+":"+
+ (header_base[header+23]&0xff)+":"+
+ (header_base[header+24]&0xff)+":"+
+ (header_base[header+25]&0xff)+"\n segments: "+
+ (header_base[header+26]&0xff)+" (");
+ for(int j=27;j<header_len;j++){
+ System.err.println((header_base[header+j]&0xff)+" ");
+ }
+ System.err.println(")\n");
+ }
+
+ void copy_page(){
+ byte[] tmp=new byte[header_len];
+ System.arraycopy(header_base, header, tmp, 0, header_len);
+ header_base=tmp;
+ header=0;
+ tmp=new byte[body_len];
+ System.arraycopy(body_base, body, tmp, 0, body_len);
+ body_base=tmp;
+ body=0;
+ }
+
+ static void test_pack(int[] pl, int[][] headers){
+ byte[] data=new byte[1024*1024]; // for scripted test cases only
+ int inptr=0;
+ int outptr=0;
+ int deptr=0;
+ int depacket=0;
+ int pcm_pos=7;
+ int packets,pageno=0,pageout=0;
+ int eosflag=0;
+ int bosflag=0;
+
+ os_en.reset();
+ os_de.reset();
+ oy.reset();
+
+ for(packets=0;;packets++){
+ if(pl[packets]==-1)break;
+ }
+
+ for(int i=0;i<packets;i++){
+ // construct a test packet
+ Packet op=new Packet();
+ int len=pl[i];
+ op.packet_base=data;
+ op.packet=inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=pcm_pos;
+
+ pcm_pos+=1024;
+
+ for(int j=0;j<len;j++){
+ data[inptr++]=(byte)(i+j);
+ }
+
+ // submit the test packet
+ os_en.packetin(op);
+
+ // retrieve any finished pages
+ {
+ Page og=new Page();
+
+ while(os_en.pageout(og)!=0){
+ // We have a page. Check it carefully
+ //System.err.print(pageno+", ");
+ if(headers[pageno]==null){
+ System.err.println("coded too many pages!");
+ System.exit(1);
+ }
+ og.check_page(data, outptr, headers[pageno]);
+
+ outptr+=og.body_len;
+ pageno++;
+
+//System.err.println("1# pageno="+pageno+", pageout="+pageout);
+
+ // have a complete page; submit it to sync/decode
+
+ {
+ Page og_de=new Page();
+ Packet op_de=new Packet();
+ int index=oy.buffer(og.header_len+og.body_len);
+ byte[] buf=oy.data;
+ System.arraycopy(og.header_base, og.header, buf, index, og.header_len);
+ System.arraycopy(og.body_base, og.body, buf, index+og.header_len, og.body_len);
+ oy.wrote(og.header_len+og.body_len);
+
+//System.err.println("2# pageno="+pageno+", pageout="+pageout);
+
+ while(oy.pageout(og_de)>0){
+ // got a page. Happy happy. Verify that it's good.
+
+ og_de.check_page(data, deptr, headers[pageout]);
+ deptr+=og_de.body_len;
+ pageout++;
+
+ // submit it to deconstitution
+ os_de.pagein(og_de);
+
+ // packets out?
+ while(os_de.packetout(op_de)>0){
+
+ // verify the packet!
+ // check data
+ boolean check=false;
+ for(int ii=0; ii<op_de.bytes; ii++){
+ if(data[depacket+ii]!=op_de.packet_base[op_de.packet+ii]){
+ check=true;
+ break;
+ }
+ }
+ if(check){
+ System.err.println("packet data mismatch in decode! pos="+
+ depacket);
+ System.exit(1);
+ }
+
+ // check bos flag
+ if(bosflag==0 && op_de.b_o_s==0){
+ System.err.println("b_o_s flag not set on packet!");
+ System.exit(1);
+ }
+ if(bosflag!=0 && op_de.b_o_s!=0){
+ System.err.println("b_o_s flag incorrectly set on packet!");
+ System.exit(1);
+ }
+
+ bosflag=1;
+ depacket+=op_de.bytes;
+
+ // check eos flag
+ if(eosflag!=0){
+ System.err.println("Multiple decoded packets with eos flag!");
+ System.exit(1);
+ }
+
+ if(op_de.e_o_s!=0)eosflag=1;
+
+ // check pcmpos flag
+ if(op_de.granulepos!=-1){
+ System.err.print(" pcm:"+op_de.granulepos+" ");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //free(data);
+ if(headers[pageno]!=null){
+ System.err.println("did not write last page!");
+ System.exit(1);
+ }
+ if(headers[pageout]!=null){
+ System.err.println("did not decode last page!");
+ System.exit(1);
+ }
+ if(inptr!=outptr){
+ System.err.println("encoded page data incomplete!");
+ System.exit(1);
+ }
+ if(inptr!=deptr){
+ System.err.println("decoded page data incomplete!");
+ System.exit(1);
+ }
+ if(inptr!=depacket){
+ System.err.println("decoded packet data incomplete!");
+ System.exit(1);
+ }
+ if(eosflag==0){
+ System.err.println("Never got a packet with EOS set!");
+ }
+ System.err.println("ok.");
+ }
+
+ static void error(){
+ System.err.println("error!");
+ System.exit(1);
+ }
+ public static void main(String[] arg){
+
+ os_en=new StreamState(0x04030201);
+ os_de=new StreamState(0x04030201);
+
+ oy=new SyncState();
+
+ // Exercise each code path in the framing code. Also verify that
+ // the checksums are working.
+
+ {
+ // 17 only
+ int[] packets={17, -1};
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x06,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x15,0xed,0xec,0x91,
+ 1,
+ 17};
+ int[][] headret={head1, null};
+
+ System.err.print("testing single page encoding... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // 17, 254, 255, 256, 500, 510, 600 byte, pad
+ int[] packets={17, 254, 255, 256, 500, 510, 600, -1};
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x59,0x10,0x6c,0x2c,
+ 1,
+ 17};
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x89,0x33,0x85,0xce,
+ 13,
+ 254,255,0,255,1,255,245,255,255,0,
+ 255,255,90};
+ int[][] headret={head1,head2,null};
+
+ System.err.print("testing basic page encoding... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // nil packets; beginning,middle,end
+ int[] packets={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x5c,0x3f,0x66,0xcb,
+ 17,
+ 17,254,255,0,0,255,1,0,255,245,255,255,0,
+ 255,255,90,0};
+ int[][] headret={head1,head2,null};
+
+ System.err.print("testing basic nil packets... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // large initial packet
+ int[] packets={4345,259,255,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x01,0x27,0x31,0xaa,
+ 18,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x7f,0x4e,0x8a,0xd2,
+ 4,
+ 255,4,255,0};
+ int[][] headret={head1,head2,null};
+
+ System.err.print("testing initial-packet lacing > 4k... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // continuing packet test
+ int[] packets={0,4345,259,255,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x34,0x24,0xd5,0x29,
+ 17,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255};
+
+ int[] head3={0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xc8,0xc3,0xcb,0xed,
+ 5,
+ 10,255,4,255,0};
+ int[][] headret={head1,head2,head3,null};
+
+ System.err.print("testing single packet page span... ");
+ test_pack(packets,headret);
+ }
+
+ // page with the 255 segment limit
+ {
+
+ int[] packets={0,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,50,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xed,0x2a,0x2e,0xa7,
+ 255,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10};
+
+ int[] head3={0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x6c,0x3b,0x82,0x3d,
+ 1,
+ 50};
+ int[][] headret={head1,head2,head3,null};
+
+ System.err.print("testing max packet segments... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // packet that overspans over an entire page
+
+ int[] packets={0,100,9000,259,255,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x3c,0xd9,0x4d,0x3f,
+ 17,
+ 100,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+
+ int[] head3={0x4f,0x67,0x67,0x53,0,0x01,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xbd,0xd5,0xb5,0x8b,
+ 17,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255};
+
+ int[] head4={0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,3,0,0,0,
+ 0xef,0xdd,0x88,0xde,
+ 7,
+ 255,255,75,255,4,255,0};
+ int[][] headret={head1,head2,head3,head4,null};
+
+ System.err.print("testing very large packets... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // term only page. why not?
+
+ int[] packets={0,100,4080,-1};
+
+ int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+ int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x3c,0xd9,0x4d,0x3f,
+ 17,
+ 100,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+
+ int[] head3={0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xd4,0xe0,0x60,0xe5,
+ 1,0};
+
+ int[][] headret={head1,head2,head3,null};
+
+ System.err.print("testing zero data page (1 nil packet)... ");
+ test_pack(packets,headret);
+ }
+
+ {
+ // build a bunch of pages for testing
+ byte[] data=new byte[1024*1024];
+ int[] pl={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
+ int inptr=0;
+ Page[] og=new Page[5];
+ for(int i=0; i<5; i++){
+ og[i]=new Page();
+ }
+
+ os_en.reset();
+
+ for(int i=0;pl[i]!=-1;i++){
+ Packet op=new Packet();
+ int len=pl[i];
+
+ op.packet_base=data;
+ op.packet=inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=(i+1)*1000;
+
+ for(int j=0;j<len;j++)data[inptr++]=(byte)(i+j);
+ os_en.packetin(op);
+ }
+
+// free(data);
+
+ // retrieve finished pages
+ for(int i=0;i<5;i++){
+ if(os_en.pageout(og[i])==0){
+ System.err.print("Too few pages output building sync tests!\n");
+ System.exit(1);
+ }
+ og[i].copy_page();
+ }
+
+ // Test lost pages on pagein/packetout: no rollback
+ {
+ Page temp=new Page();
+ Packet test=new Packet();
+
+ System.err.print("Testing loss of pages... ");
+
+ oy.reset();
+ os_de.reset();
+ for(int i=0;i<5;i++){
+ int index=oy.buffer(og[i].header_len);
+ System.arraycopy(og[i].header_base, og[i].header,
+ oy.data, index, og[i].header_len);
+ oy.wrote(og[i].header_len);
+ index=oy.buffer(og[i].body_len);
+ System.arraycopy(og[i].body_base, og[i].body,
+ oy.data, index, og[i].body_len);
+ oy.wrote(og[i].body_len);
+ }
+
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+
+ // skip
+ oy.pageout(temp);
+ os_de.pagein(temp);
+
+ // do we get the expected results/packets?
+
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(0,0,0);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(100,1,-1);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(4079,2,3000);
+ if(os_de.packetout(test)!=-1){
+ System.err.println("Error: loss of page did not return error");
+ System.exit(1);
+ }
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(76,5,-1);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(34,6,-1);
+ System.err.println("ok.");
+ }
+
+ // Test lost pages on pagein/packetout: rollback with continuation
+ {
+ Page temp=new Page();
+ Packet test=new Packet();
+
+ System.err.print("Testing loss of pages (rollback required)... ");
+
+ oy.reset();
+ os_de.reset();
+ for(int i=0;i<5;i++){
+ int index=oy.buffer(og[i].header_len);
+ System.arraycopy(og[i].header_base, og[i].header,
+ oy.data, index, og[i].header_len);
+ oy.wrote(og[i].header_len);
+ index=oy.buffer(og[i].body_len);
+ System.arraycopy(og[i].body_base, og[i].body,
+ oy.data, index, og[i].body_len);
+ oy.wrote(og[i].body_len);
+ }
+
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+ os_de.pagein(temp);
+ oy.pageout(temp);
+ // skip
+ oy.pageout(temp);
+ os_de.pagein(temp);
+
+ // do we get the expected results/packets?
+
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(0,0,0);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(100,1,-1);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(4079,2,3000);
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(2956,3,4000);
+ if(os_de.packetout(test)!=-1){
+ System.err.println("Error: loss of page did not return error");
+ System.exit(1);
+ }
+ if(os_de.packetout(test)!=1)error();
+ test.checkpacket(300,13,14000);
+ System.err.println("ok.");
+ }
+
+ // the rest only test sync
+ {
+ Page og_de=new Page();
+ // Test fractional page inputs: incomplete capture
+ System.err.print("Testing sync on partial inputs... ");
+ oy.reset();
+ int index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, 3);
+ oy.wrote(3);
+ if(oy.pageout(og_de)>0)error();
+
+ // Test fractional page inputs: incomplete fixed header
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header+3,
+ oy.data, index, 20);
+
+ oy.wrote(20);
+ if(oy.pageout(og_de)>0)error();
+
+ // Test fractional page inputs: incomplete header
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header+23,
+ oy.data, index, 5);
+ oy.wrote(5);
+ if(oy.pageout(og_de)>0)error();
+
+ // Test fractional page inputs: incomplete body
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header+28,
+ oy.data, index, og[1].header_len-28);
+ oy.wrote(og[1].header_len-28);
+ if(oy.pageout(og_de)>0)error();
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, 1000);
+ oy.wrote(1000);
+ if(oy.pageout(og_de)>0)error();
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body+1000,
+ oy.data, index, og[1].body_len-1000);
+ oy.wrote(og[1].body_len-1000);
+ if(oy.pageout(og_de)<=0)error();
+ System.err.println("ok.");
+ }
+
+ // Test fractional page inputs: page + incomplete capture
+ {
+ Page og_de=new Page();
+ System.err.print("Testing sync on 1+partial inputs... ");
+ oy.reset();
+
+ int index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, og[1].header_len);
+ oy.wrote(og[1].header_len);
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+ oy.wrote(og[1].body_len);
+
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, 20);
+ oy.wrote(20);
+ if(oy.pageout(og_de)<=0)error();
+ if(oy.pageout(og_de)>0)error();
+
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header+20,
+ oy.data, index, og[1].header_len-20);
+ oy.wrote(og[1].header_len-20);
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+
+ oy.wrote(og[1].body_len);
+ if(oy.pageout(og_de)<=0)error();
+
+ System.err.println("ok.");
+ }
+
+// // // // // // // // //
+ // Test recapture: garbage + page
+ {
+ Page og_de=new Page();
+ System.err.print("Testing search for capture... ");
+ oy.reset();
+
+ // 'garbage'
+ int index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+ oy.wrote(og[1].body_len);
+
+ index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, og[1].header_len);
+ oy.wrote(og[1].header_len);
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+ oy.wrote(og[1].body_len);
+
+ index=oy.buffer(og[2].header_len);
+ System.arraycopy(og[2].header_base, og[2].header,
+ oy.data, index, 20);
+
+ oy.wrote(20);
+ if(oy.pageout(og_de)>0)error();
+ if(oy.pageout(og_de)<=0)error();
+ if(oy.pageout(og_de)>0)error();
+
+ index=oy.buffer(og[2].header_len);
+ System.arraycopy(og[2].header_base, og[2].header+20,
+ oy.data, index, og[2].header_len-20);
+ oy.wrote(og[2].header_len-20);
+ index=oy.buffer(og[2].body_len);
+ System.arraycopy(og[2].body_base, og[2].body,
+ oy.data, index, og[2].body_len);
+ oy.wrote(og[2].body_len);
+ if(oy.pageout(og_de)<=0)error();
+
+ System.err.println("ok.");
+ }
+
+ // Test recapture: page + garbage + page
+ {
+ Page og_de=new Page();
+ System.err.print("Testing recapture... ");
+ oy.reset();
+
+ int index=oy.buffer(og[1].header_len);
+ System.arraycopy(og[1].header_base, og[1].header,
+ oy.data, index, og[1].header_len);
+ oy.wrote(og[1].header_len);
+
+ index=oy.buffer(og[1].body_len);
+ System.arraycopy(og[1].body_base, og[1].body,
+ oy.data, index, og[1].body_len);
+ oy.wrote(og[1].body_len);
+
+ index=oy.buffer(og[2].header_len);
+ System.arraycopy(og[2].header_base, og[2].header,
+ oy.data, index, og[2].header_len);
+ oy.wrote(og[2].header_len);
+
+ index=oy.buffer(og[2].header_len);
+ System.arraycopy(og[2].header_base, og[2].header,
+ oy.data, index, og[2].header_len);
+ oy.wrote(og[2].header_len);
+
+ if(oy.pageout(og_de)<=0)error();
+
+ index=oy.buffer(og[2].body_len);
+ System.arraycopy(og[2].body_base, og[2].body,
+ oy.data, index, og[2].body_len-5);
+ oy.wrote(og[2].body_len-5);
+
+ index=oy.buffer(og[3].header_len);
+ System.arraycopy(og[3].header_base, og[3].header,
+ oy.data, index, og[3].header_len);
+ oy.wrote(og[3].header_len);
+
+ index=oy.buffer(og[3].body_len);
+ System.arraycopy(og[3].body_base, og[3].body,
+ oy.data, index, og[3].body_len);
+ oy.wrote(og[3].body_len);
+
+ if(oy.pageout(og_de)>0)error();
+ if(oy.pageout(og_de)<=0)error();
+
+ System.err.println("ok.");
+ }
+ }
+ //return(0);
+ }
+ */
+}