]> Joshua Wise's Git repositories - patchfork.git/blob - jorbis/src/com/jcraft/jogg/SyncState.java
initial import from pitchfork-0.5.5
[patchfork.git] / jorbis / src / com / jcraft / jogg / SyncState.java
1 /* JOrbis
2  * Copyright (C) 2000 ymnk, JCraft,Inc.
3  *  
4  * Written by: 2000 ymnk<ymnk@jcraft.com>
5  *   
6  * Many thanks to 
7  *   Monty <monty@xiph.org> and 
8  *   The XIPHOPHORUS Company http://www.xiph.org/ .
9  * JOrbis has been based on their awesome works, Vorbis codec.
10  *   
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public License
13  * as published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15    
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Library General Public License for more details.
20  * 
21  * You should have received a copy of the GNU Library General Public
22  * License along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 package com.jcraft.jogg;
27
28 // DECODING PRIMITIVES: packet streaming layer
29
30 // This has two layers to place more of the multi-serialno and paging
31 // control in the application's hands.  First, we expose a data buffer
32 // using ogg_decode_buffer().  The app either copies into the
33 // buffer, or passes it directly to read(), etc.  We then call
34 // ogg_decode_wrote() to tell how many bytes we just added.
35 //
36 // Pages are returned (pointers into the buffer in ogg_sync_state)
37 // by ogg_decode_stream().  The page is then submitted to
38 // ogg_decode_page() along with the appropriate
39 // ogg_stream_state* (ie, matching serialno).  We then get raw
40 // packets out calling ogg_stream_packet() with a
41 // ogg_stream_state.  See the 'frame-prog.txt' docs for details and
42 // example code.
43
44 public class SyncState{
45
46   public byte[] data;
47   int storage;
48   int fill;
49   int returned;
50
51   int unsynced;
52   int headerbytes;
53   int bodybytes;
54
55   public int clear(){
56     data=null;
57     return(0);
58   }
59
60 // !!!!!!!!!!!!
61 //  byte[] buffer(int size){
62   public int buffer(int size){
63     // first, clear out any space that has been previously returned
64     if(returned!=0){
65       fill-=returned;
66       if(fill>0){
67         System.arraycopy(data, returned, data, 0, fill);
68       }
69       returned=0;
70     }
71
72     if(size>storage-fill){
73       // We need to extend the internal buffer
74       int newsize=size+fill+4096; // an extra page to be nice
75       if(data!=null){
76         byte[] foo=new byte[newsize];
77         System.arraycopy(data, 0, foo, 0, data.length);
78         data=foo;
79       }
80       else{
81         data=new byte[newsize];
82       }
83       storage=newsize;
84     }
85
86     // expose a segment at least as large as requested at the fill mark
87 //    return((char *)oy->data+oy->fill);
88 //    return(data);
89     return(fill);
90   }
91
92   public int wrote(int bytes){
93     if(fill+bytes>storage)return(-1);
94     fill+=bytes;
95     return(0);
96   }
97
98 // sync the stream.  This is meant to be useful for finding page
99 // boundaries.
100 //
101 // return values for this:
102 // -n) skipped n bytes
103 //  0) page not ready; more data (no bytes skipped)
104 //  n) page synced at current location; page length n bytes
105   private Page pageseek=new Page();
106   private  byte[] chksum=new byte[4];
107   public int pageseek(Page og){
108     int page=returned;
109     int next;
110     int bytes=fill-returned;
111   
112     if(headerbytes==0){
113       int _headerbytes,i;
114       if(bytes<27)return(0); // not enough for a header
115     
116     /* verify capture pattern */
117 //!!!!!!!!!!!
118       if(data[page]!='O' ||
119          data[page+1]!='g' ||
120          data[page+2]!='g' ||
121          data[page+3]!='S'){
122         headerbytes=0;
123         bodybytes=0;
124   
125         // search for possible capture
126         next=0;
127         for(int ii=0; ii<bytes-1; ii++){
128           if(data[page+1+ii]=='O'){next=page+1+ii; break;}
129         }
130     //next=memchr(page+1,'O',bytes-1);
131         if(next==0) next=fill;
132
133         returned=next;
134         return(-(next-page));
135       }
136       _headerbytes=(data[page+26]&0xff)+27;
137       if(bytes<_headerbytes)return(0); // not enough for header + seg table
138     
139       // count up body length in the segment table
140     
141       for(i=0;i<(data[page+26]&0xff);i++){
142         bodybytes+=(data[page+27+i]&0xff);
143       }
144       headerbytes=_headerbytes;
145     }
146   
147     if(bodybytes+headerbytes>bytes)return(0);
148   
149     // The whole test page is buffered.  Verify the checksum
150     synchronized(chksum){
151       // Grab the checksum bytes, set the header field to zero
152     
153       System.arraycopy(data, page+22, chksum, 0, 4);
154       data[page+22]=0;
155       data[page+23]=0;
156       data[page+24]=0;
157       data[page+25]=0;
158     
159       // set up a temp page struct and recompute the checksum
160       Page log=pageseek;
161       log.header_base=data;
162       log.header=page;
163       log.header_len=headerbytes;
164
165       log.body_base=data;
166       log.body=page+headerbytes;
167       log.body_len=bodybytes;
168       log.checksum();
169
170       // Compare
171       if(chksum[0]!=data[page+22] ||
172          chksum[1]!=data[page+23] ||
173          chksum[2]!=data[page+24] ||
174          chksum[3]!=data[page+25]){
175         // D'oh.  Mismatch! Corrupt page (or miscapture and not a page at all)
176         // replace the computed checksum with the one actually read in
177         System.arraycopy(chksum, 0, data, page+22, 4);
178         // Bad checksum. Lose sync */
179
180         headerbytes=0;
181         bodybytes=0;
182         // search for possible capture
183         next=0;
184         for(int ii=0; ii<bytes-1; ii++){
185           if(data[page+1+ii]=='O'){next=page+1+ii; break;}
186         }
187         //next=memchr(page+1,'O',bytes-1);
188         if(next==0) next=fill;
189         returned=next;
190         return(-(next-page));
191       }
192     }
193   
194     // yes, have a whole page all ready to go
195     {
196       page=returned;
197
198       if(og!=null){
199         og.header_base=data;
200         og.header=page;
201         og.header_len=headerbytes;
202         og.body_base=data;
203         og.body=page+headerbytes;
204         og.body_len=bodybytes;
205       }
206
207       unsynced=0;
208       returned+=(bytes=headerbytes+bodybytes);
209       headerbytes=0;
210       bodybytes=0;
211       return(bytes);
212     }
213 //  headerbytes=0;
214 //  bodybytes=0;
215 //  next=0;
216 //  for(int ii=0; ii<bytes-1; ii++){
217 //    if(data[page+1+ii]=='O'){next=page+1+ii;}
218 //  }
219 //  //next=memchr(page+1,'O',bytes-1);
220 //  if(next==0) next=fill;
221 //  returned=next;
222 //  return(-(next-page));
223   }
224
225
226 // sync the stream and get a page.  Keep trying until we find a page.
227 // Supress 'sync errors' after reporting the first.
228 //
229 // return values:
230 //  -1) recapture (hole in data)
231 //   0) need more data
232 //   1) page returned
233 //
234 // Returns pointers into buffered data; invalidated by next call to
235 // _stream, _clear, _init, or _buffer
236
237   public int pageout(Page og){
238     // all we need to do is verify a page at the head of the stream
239     // buffer.  If it doesn't verify, we look for the next potential
240     // frame
241
242     while(true){
243       int ret=pageseek(og);
244       if(ret>0){
245         // have a page
246         return(1);
247       }
248       if(ret==0){
249         // need more data
250         return(0);
251       }
252     
253       // head did not start a synced page... skipped some bytes
254       if(unsynced==0){
255         unsynced=1;
256         return(-1);
257       }
258       // loop. keep looking
259     }
260   }
261
262 // clear things to an initial state.  Good to call, eg, before seeking
263   public int reset(){
264     fill=0;
265     returned=0;
266     unsynced=0;
267     headerbytes=0;
268     bodybytes=0;
269     return(0);
270   }
271   public void init(){}
272
273   public int getDataOffset(){ return returned; }    
274   public int getBufferOffset(){ return fill;  }
275 }
This page took 0.037104 seconds and 4 git commands to generate.