/* JOrbis * Copyright (C) 2000 ymnk, JCraft,Inc. * * Written by: 2000 ymnk * * Many thanks to * Monty 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; // DECODING PRIMITIVES: packet streaming layer // This has two layers to place more of the multi-serialno and paging // control in the application's hands. First, we expose a data buffer // using ogg_decode_buffer(). The app either copies into the // buffer, or passes it directly to read(), etc. We then call // ogg_decode_wrote() to tell how many bytes we just added. // // Pages are returned (pointers into the buffer in ogg_sync_state) // by ogg_decode_stream(). The page is then submitted to // ogg_decode_page() along with the appropriate // ogg_stream_state* (ie, matching serialno). We then get raw // packets out calling ogg_stream_packet() with a // ogg_stream_state. See the 'frame-prog.txt' docs for details and // example code. public class SyncState{ public byte[] data; int storage; int fill; int returned; int unsynced; int headerbytes; int bodybytes; public int clear(){ data=null; return(0); } // !!!!!!!!!!!! // byte[] buffer(int size){ public int buffer(int size){ // first, clear out any space that has been previously returned if(returned!=0){ fill-=returned; if(fill>0){ System.arraycopy(data, returned, data, 0, fill); } returned=0; } if(size>storage-fill){ // We need to extend the internal buffer int newsize=size+fill+4096; // an extra page to be nice if(data!=null){ byte[] foo=new byte[newsize]; System.arraycopy(data, 0, foo, 0, data.length); data=foo; } else{ data=new byte[newsize]; } storage=newsize; } // expose a segment at least as large as requested at the fill mark // return((char *)oy->data+oy->fill); // return(data); return(fill); } public int wrote(int bytes){ if(fill+bytes>storage)return(-1); fill+=bytes; return(0); } // sync the stream. This is meant to be useful for finding page // boundaries. // // return values for this: // -n) skipped n bytes // 0) page not ready; more data (no bytes skipped) // n) page synced at current location; page length n bytes private Page pageseek=new Page(); private byte[] chksum=new byte[4]; public int pageseek(Page og){ int page=returned; int next; int bytes=fill-returned; if(headerbytes==0){ int _headerbytes,i; if(bytes<27)return(0); // not enough for a header /* verify capture pattern */ //!!!!!!!!!!! if(data[page]!='O' || data[page+1]!='g' || data[page+2]!='g' || data[page+3]!='S'){ headerbytes=0; bodybytes=0; // search for possible capture next=0; for(int ii=0; iibytes)return(0); // The whole test page is buffered. Verify the checksum synchronized(chksum){ // Grab the checksum bytes, set the header field to zero System.arraycopy(data, page+22, chksum, 0, 4); data[page+22]=0; data[page+23]=0; data[page+24]=0; data[page+25]=0; // set up a temp page struct and recompute the checksum Page log=pageseek; log.header_base=data; log.header=page; log.header_len=headerbytes; log.body_base=data; log.body=page+headerbytes; log.body_len=bodybytes; log.checksum(); // Compare if(chksum[0]!=data[page+22] || chksum[1]!=data[page+23] || chksum[2]!=data[page+24] || chksum[3]!=data[page+25]){ // D'oh. Mismatch! Corrupt page (or miscapture and not a page at all) // replace the computed checksum with the one actually read in System.arraycopy(chksum, 0, data, page+22, 4); // Bad checksum. Lose sync */ headerbytes=0; bodybytes=0; // search for possible capture next=0; for(int ii=0; ii0){ // have a page return(1); } if(ret==0){ // need more data return(0); } // head did not start a synced page... skipped some bytes if(unsynced==0){ unsynced=1; return(-1); } // loop. keep looking } } // clear things to an initial state. Good to call, eg, before seeking public int reset(){ fill=0; returned=0; unsynced=0; headerbytes=0; bodybytes=0; return(0); } public void init(){} public int getDataOffset(){ return returned; } public int getBufferOffset(){ return fill; } }