001/*
002 *  JOrbisComment -- pure Java Ogg Vorbis Comment Editor
003 *
004 *  Copyright (C) 2000 ymnk, JCraft,Inc.
005 *
006 *  Written by: 2000 ymnk<ymnk@jcraft.com>
007 *
008 *  Many thanks to
009 *  Monty <monty@xiph.org> and
010 *  The XIPHOPHORUS Company http://www.xiph.org/ .
011 *  JOrbis has been based on their awesome works, Vorbis codec and
012 *  JOrbisPlayer depends on JOrbis.
013 *
014 *  This program is free software; you can redistribute it and/or modify
015 *  it under the terms of the GNU General Public License as published by
016 *  the Free Software Foundation; either version 2 of the License, or
017 *  (at your option) any later version.
018 *
019 *  This program is distributed in the hope that it will be useful,
020 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
021 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
022 *  GNU General Public License for more details.
023 *
024 *  You should have received a copy of the GNU General Public License
025 *  along with this program; if not, write to the Free Software
026 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
027 */
028package ca.bc.webarts.tools;
029
030import ca.bc.webarts.widgets.Util;
031import com.jcraft.jogg.*;
032import com.jcraft.jorbis.*;
033import java.io.*;
034import java.util.*;
035
036
037/**
038 *  A class that reads and writes comments in Ogg Vorbis Files. It uses jcrafts
039 *  jorbis impl.
040 *
041 * @author
042 */
043public class JOrbisComment
044{
045
046  /**  Description of the Field */
047  private static int CHUNKSIZE = 4096;
048  /**  Description of the Field */
049  State state = null;
050  /**  Description of the Field */
051  File inFile = null;
052  //InputStream vorbisStream_ = null;
053  private final int RAND_HASH_ = (int) (Math.random() * 20000);
054
055
056  String artist_ = "";
057  String album_ = "";
058  String title_ = "";
059  String tracknumber_ = "";
060  String genre_ = "";
061  String artistAlbumTrackNum_ = "";
062  String artistAlbumTrackTitle_ = "";
063
064
065  /**  Constructor for the JOrbisComment object */
066  public JOrbisComment()
067  {
068    super();
069    this.state = new State();
070  }
071
072
073  /**
074   *  Constructor for the JOrbisComment object
075   *
076   * @param  state  Description of the Parameter
077   */
078  public JOrbisComment(State state)
079  {
080    super();
081    this.state = state;
082  }
083
084
085  /**
086   *  Constructor for the JOrbisComment object
087   *
088   * @param  inFile  inits and reads the passed file
089   */
090  public JOrbisComment(File inFile)
091  {
092    super();
093    this.state = new State();
094    this.inFile = inFile;
095    readInFile();
096  }
097
098
099  /**
100   *  Constructor for the JOrbisComment object
101   *
102   * @param  vorbisStream  inits and reads the passed inStream
103   */
104  public JOrbisComment(InputStream vorbisStream)
105  {
106    super();
107    this.state = new State();
108    state.in = vorbisStream;
109  }
110
111
112  /**
113   *  flushes its objects to reease memory
114   *
115   */
116  public void flush()
117  {
118    this.state = null;
119  }
120
121
122  /**
123   *  The main program for the JOrbisComment class.
124   *
125   * @param  arg  The command line arguments
126   */
127  public static void main(String[] arg)
128  {
129    if (arg.length > 0)
130    {
131      String input = arg[0];
132      String output = arg[0];
133      //System.out.println("arg="+arg.length );
134      InputStream in = null;
135      State foo = new State();
136      JOrbisComment jorbiscomment = new JOrbisComment(foo);
137      try
138      {
139        in = new FileInputStream(input);
140        jorbiscomment.read(in);
141        System.out.println(jorbiscomment.getArtistAlbumTrackNum());
142        System.out.println(foo.vc);
143        in.close();
144      }
145      catch (Exception e)
146      {
147        System.out.println(e);
148      }
149
150      // foo.vc.add("TEST=TESTTEST");
151      // foo.vc.add_tag("TITLE", "demodemo");
152      //System.out.println(foo.vc.query("TEST"));
153      //System.out.println(foo.vc.query("TITLE"));
154      //System.out.println(foo.vc.query("ARTIST"));
155
156      // parse any passed comments and add to this
157      if (arg.length > 1)
158      {
159        System.out.println("New Comments Specified "+arg.length );
160        for (int pair = 1; pair < arg.length; pair+=2)
161        {
162          // an ogg comment was given on the commandline so add them tothe file
163          jorbiscomment.setComment(arg[pair], (arg.length>(pair+1)?arg[pair+1]:""));
164          System.out.println("added ogg comment: " +
165            arg[pair] + "=" + (arg.length>(pair+1)?arg[pair+1]:""));
166        }
167      }
168
169      if (arg.length > 1)
170      {
171        try
172        {
173          // persist any changes back to the file NOTE you could persist this to any other file as well.
174          OutputStream out = new FileOutputStream(output);
175
176          jorbiscomment.write(out);
177          out.close();
178        }
179        catch (Exception e)
180        {
181          e.printStackTrace();
182          System.out.println(e);
183        }
184      }
185    }
186    else
187    {
188      System.out.println(usage());
189    }
190  }
191
192
193  public static String usage()
194  {
195    String retVal = "JOrbisComment - A Java query and writer for Ogg Vorbis File comments.";
196    retVal+= Util.SYSTEM_LINE_SEPERATOR;
197    retVal+= "> java ca.bc.webarts.tools.JOrbisComment [inputFile] [commentFiled commentValue]...";
198    retVal+= Util.SYSTEM_LINE_SEPERATOR;
199    retVal+= "   inputFile - is the ogg file to read(and writeiff comments are specified)";
200    retVal+= Util.SYSTEM_LINE_SEPERATOR;
201    retVal+= "   comments are specified in name value pairs";
202    retVal+= Util.SYSTEM_LINE_SEPERATOR;
203    retVal+= "   If only the inputFile is specified, then it is read and the comments are printed on the commandline.";
204    retVal+= Util.SYSTEM_LINE_SEPERATOR;
205    return retVal;
206  }
207
208
209  public boolean setArtist(String value)
210  {
211    return setComment("ARTIST",value);
212  }
213
214
215  public boolean setAlbum(String value)
216  {
217    return setComment("ALBUM",value);
218  }
219
220
221  public boolean setTitle(String value)
222  {
223    return setComment("TITLE",value);
224  }
225
226
227  public boolean setTracknumber(String value)
228  {
229    return setComment("TRACKNUMBER",value);
230  }
231
232
233  public boolean setTrackTotal(String value)
234  {
235    return setComment("TRACKTOTAL",value);
236  }
237
238
239  public boolean setGenre(String value)
240  {
241    return setComment("GENRE",value);
242  }
243
244
245  /**
246   *  Sets a comment attribute of the JOrbisComment object BUT does not write to file.
247   *
248   * @param  field  ThSystem.out.printlne new comment value
249   * @param  value  The new comment value
250   * @return        Description of the Return Value
251   */
252  public boolean setComment(String field, String value)
253  {
254    boolean retVal = true;
255    try
256    {
257      if (value==null) value="";
258      this.state.vc.add_tag(field, value);
259    }
260    catch (Exception e)
261    {
262      //e.printStackTrace();
263      System.out.println("Can't add comment: " + field + "=" + value);
264      retVal = false;
265    }
266    return retVal;
267  }
268
269
270  /**
271   *  Gets the comment attribute of the JOrbisComment object. It is case
272   *  sensitive - it will search for the exact match of the passed field.
273   *
274   * @param  field  Description of the Parameter
275   * @return        The comment value
276   */
277  public String getComment(String field)
278  {
279    return (this.state.vc!=null?this.state.vc.query(field):"");
280
281  }
282
283
284  /**
285   *  Gets the comment attribute of the JOrbisComment object. NOTE: that this method
286   *  looks for the AllCaps version of this tag 1st, then the allLower version
287   *
288   * @param  smart  flag if the Uppercase should be prioritized.
289   * @param  field  Description of the Parameter
290   * @return        The comment value, or an empty string if not found.
291   */
292  public String getComment(String field, boolean smart)
293  {
294    String retVal = "";
295    if (smart)
296    {
297      String caps = getComment(field.toUpperCase());
298      String sml = getComment(field.toLowerCase());
299      retVal = (caps!=null?caps:(sml!=null?sml:""));
300    }
301    else
302      retVal = getComment(field);
303
304    return retVal;
305  }
306
307
308  /**
309   *  Gets a concatenation of Artist Album and Track# Comment for this ogg vorbis file.
310   *
311   * @return    a concatenation of Artist Album and Track# Comment
312   */
313  public String getArtistAlbumTrackNum()
314  {
315    // use the cache if available
316    if (artistAlbumTrackNum_.equals(""))
317    {
318      artistAlbumTrackNum_ =
319                ( ( getArtist()!=null     ? getArtist():"")+" "+
320                  ( getAlbum() !=null     ? getAlbum() :"")+" "+
321                  ( getTracknumber()!=null && !getTracknumber().equals("")?
322                      ( getTracknumber().length()<2?"0"+ getTracknumber(): getTracknumber()) :
323                      ( getTitle() !=null     ? getTitle() :"")
324                  ) +
325                  "_"+RAND_HASH_
326                );
327    }
328
329    return artistAlbumTrackNum_;
330  }
331
332
333  /**
334   *  Gets a concatenation of Artist Album and Track Title Comment for this ogg vorbis file.
335   *
336   * @return    a concatenation of Artist Album and Track# Comment
337   */
338  public String getArtistAlbumTrackTitle()
339  {
340    // use the cache if available
341    if (artistAlbumTrackTitle_.equals(""))
342    {
343      artistAlbumTrackTitle_ =
344                ( ( getArtist()!=null     ? getArtist():"")+" "+
345                  ( getAlbum() !=null     ? getAlbum() :"")+" "+
346                  ( getTitle() !=null     ? getTitle() :"") +
347                  "_"+RAND_HASH_
348                );
349    }
350
351    return artistAlbumTrackTitle_;
352  }
353
354
355  /**
356   * Gets the artist attribute of the JOrbisComment object.
357   * NOTE: It calls the smart upparcase prioritized getComment method.
358   *
359   * @return    The artist value
360   */
361  public String getArtist()
362  {
363    // Uses the cached val if available
364    if (artist_.equals("")) artist_ = getComment("artist",true);
365    return artist_;
366  }
367
368
369  /**
370   *  Gets the album attribute of the JOrbisComment object.
371   * NOTE: It calls the smart upparcase prioritized getComment method.
372   *
373   * @return    The album value
374   */
375  public String getAlbum()
376  {
377    // Uses the cached val if available
378    if (album_.equals("")) album_ = getComment("album",true);
379    return album_;
380  }
381
382
383  /**
384   *  Gets the title attribute of the JOrbisComment object. NOTE: that this method
385   *  looks for the AllCaps version of this tag 1st, then the allLower version
386   *
387   * @return    The TITLE comment value, or an empty string if not found.
388   */
389  public String getTitle()
390  {
391    // Uses the cached val if available
392    if (title_.equals("")) title_ = getComment("title",true);
393    return title_;
394  }
395
396
397  /**
398   *  Gets the tracknumber attribute of the JOrbisComment object.
399   * NOTE: It calls the smart upparcase prioritized getComment method.
400   *
401   * @return    The tracknumber value
402   */
403  public String getTracknumber()
404  {
405    // Uses the cached val if available
406    if (tracknumber_.equals("")) tracknumber_ = getComment("tracknumber",true);
407    return tracknumber_;
408  }
409
410
411  /**
412   *  Gets the tracktotal attribute of the JOrbisComment object.
413   * NOTE: It calls the smart upparcase prioritized getComment method.
414   *
415   * @return    The tracktotal value
416   */
417  public String getTrackTotal()
418  {
419    return getComment("tracktotal",true);
420  }
421
422
423  /**
424   *  Gets the genre attribute of the JOrbisComment object.
425   * NOTE: It calls the smart upparcase prioritized getComment method.
426   *
427   * @return    The genre value
428   */
429  public String getGenre()
430  {
431    // Uses the cached val if available
432    if (genre_.equals("")) genre_ = getComment("genre",true);
433    return genre_;
434  }
435
436
437  /**
438   *  Gets the date attribute of the JOrbisComment object.
439   * NOTE: It calls the smart upparcase prioritized getComment method.
440   *
441   * @return    The date value
442   */
443  public String getDate()
444  {
445    return getComment("date",true);
446  }
447
448
449  /**
450   *  Gets the MusicBrainz DiscID attribute of the JOrbisComment object.
451   * NOTE: It calls the smart upparcase prioritized getComment method.
452   *
453   * @return    The MUSICBRAINZ_DISCID value
454   */
455  public String getMusicBrainzDiscID()
456  {
457    return getComment("MUSICBRAINZ_DISCID",true);
458  }
459
460
461  /**
462   *  Reads from this classes inputstream
463   *
464   */
465  public boolean read(){ return read(state.in);}
466
467
468  /**
469   *  Reads from the classes inFile
470   *
471   */
472  public boolean readInFile()
473  {
474    InputStream in = null;
475    boolean retVal = true;
476    try
477    {
478      in = new FileInputStream(this.inFile.toString());
479      if (in != null)
480      {
481        retVal = this.read(in);
482        if (!retVal) System.err.println("Input truncated or empty: "+ this.inFile.toString());
483        in.close();
484      }
485    }
486    catch (Exception e)
487    {
488      e.printStackTrace();
489      retVal = false;
490    }
491
492    return retVal;
493  }
494
495
496  /**
497   *  Description of the Method
498   *
499   * @param  in  Description of the Parameter
500   */
501  public boolean read(InputStream in)
502  {
503    boolean retVal = true;
504    if (this.state==null)
505    {
506      retVal = false;
507    }
508    else
509    {
510      this.state.in = in;
511
512      Page og = new Page();
513
514      int index;
515      byte[] buffer;
516      int bytes = 0;
517
518      state.oy = new SyncState();
519      state.oy.init();
520
521      index = state.oy.buffer(CHUNKSIZE);
522      buffer = state.oy.data;
523      try
524      {
525        bytes = this.state.in.read(buffer, index, CHUNKSIZE);
526      }
527      catch (Exception e)
528      {
529        //System.err.println("vorbisStream is "+(in==null?"":"NOT ")+" null");
530        //System.err.println("buffer is "+(buffer==null?"":"NOT ")+" null");
531        //System.err.println(e);
532        //e.printStackTrace();
533        return false;
534      }
535      state.oy.wrote(bytes);
536
537      if (state.oy.pageout(og) != 1)
538      {
539        if (bytes < CHUNKSIZE)
540        {
541          System.err.println("Input truncated or empty.");
542        }
543        else
544        {
545          System.err.println("Input is not an Ogg bitstream.");
546        }
547        // goto err;
548        return false;
549      }
550      state.serial = og.serialno();
551      state.os = new StreamState();
552      state.os.init(state.serial);
553      //  os.reset();
554
555      state.vi = new Info();
556      state.vi.init();
557
558      state.vc = new Comment();
559      state.vc.init();
560
561      if (state.os.pagein(og) < 0)
562      {
563        System.err.println("Error reading first page of Ogg bitstream data.");
564        // goto err
565        return false;
566      }
567
568      Packet header_main = new Packet();
569
570      if (state.os.packetout(header_main) != 1)
571      {
572        System.err.println("Error reading initial header packet.");
573        // goto err
574        return false;
575      }
576
577      if (state.vi.synthesis_headerin(state.vc, header_main) < 0)
578      {
579        System.err.println("This Ogg bitstream does not contain Vorbis data.");
580        // goto err
581        return false;
582      }
583
584      state.mainlen = header_main.bytes;
585      state.mainbuf = new byte[state.mainlen];
586      System.arraycopy(header_main.packet_base, header_main.packet,
587          state.mainbuf, 0, state.mainlen);
588
589      int i = 0;
590      Packet header;
591      Packet header_comments = new Packet();
592      Packet header_codebooks = new Packet();
593
594      header = header_comments;
595      while (i < 2)
596      {
597        while (i < 2)
598        {
599          int result = state.oy.pageout(og);
600          if (result == 0)
601          {
602            break;
603          }
604          /*
605           *  Too little data so far
606           */
607          else if (result == 1)
608          {
609            state.os.pagein(og);
610            while (i < 2)
611            {
612              result = state.os.packetout(header);
613              if (result == 0)
614              {
615                break;
616              }
617              if (result == -1)
618              {
619                System.out.println("Corrupt secondary header.");
620                //goto err;
621                return false;
622              }
623              state.vi.synthesis_headerin(state.vc, header);
624              if (i == 1)
625              {
626                state.booklen = header.bytes;
627                state.bookbuf = new byte[state.booklen];
628                System.arraycopy(header.packet_base, header.packet,
629                    state.bookbuf, 0, header.bytes);
630              }
631              i++;
632              header = header_codebooks;
633            }
634          }
635        }
636
637        index = state.oy.buffer(CHUNKSIZE);
638        buffer = state.oy.data;
639        try
640        {
641          bytes = state.in.read(buffer, index, CHUNKSIZE);
642        }
643        catch (Exception e)
644        {
645          System.err.println(e);
646          return false;
647        }
648
649        if (bytes == 0 && i < 2)
650        {
651          System.out.println("EOF before end of vorbis headers.");
652          // goto err;
653          return false;
654        }
655        state.oy.wrote(bytes);
656      }
657      //System.out.println(state.vi);
658    }
659    return retVal;
660  }
661
662
663  /**
664   *  Writes (persists) the JOrbisComment object comments to the original file.
665   *
666   * @return      Description of the Return Value
667   */
668  int write()
669  {
670    int retVal = -1;
671    try
672    {
673      // persist any changes back to the file NOTE you could persist this to any other file as well.
674      OutputStream out = new FileOutputStream(this.inFile);
675      retVal = write(out);
676      out.close();
677    }
678    catch (Exception e)
679    {
680      e.printStackTrace();
681      System.out.println(e);
682    }
683    return retVal;
684  }
685
686
687  /**
688   *  Writes (persists) the JOrbisComment object comments to the outputstream.
689   *
690   * @param  out  Description of the Parameter
691   * @return      Description of the Return Value
692   */
693  int write(OutputStream out)
694  {
695    StreamState streamout = new StreamState();
696    Packet header_main = new Packet();
697    Packet header_comments = new Packet();
698    Packet header_codebooks = new Packet();
699
700    Page ogout = new Page();
701
702    Packet op = new Packet();
703    long granpos = 0;
704
705    int result;
706
707    int index;
708    byte[] buffer;
709
710    int bytes;
711
712    int eosin = 0;
713    int needflush = 0;
714    int needout = 0;
715
716    header_main.bytes = state.mainlen;
717    header_main.packet_base = state.mainbuf;
718    header_main.packet = 0;
719    header_main.b_o_s = 1;
720    header_main.e_o_s = 0;
721    header_main.granulepos = 0;
722
723    header_codebooks.bytes = state.booklen;
724    header_codebooks.packet_base = state.bookbuf;
725    header_codebooks.packet = 0;
726    header_codebooks.b_o_s = 0;
727    header_codebooks.e_o_s = 0;
728    header_codebooks.granulepos = 0;
729
730    streamout.init(state.serial);
731
732    state.vc.header_out(header_comments);
733
734    streamout.packetin(header_main);
735    streamout.packetin(header_comments);
736    streamout.packetin(header_codebooks);
737
738//System.out.println("%1");
739
740    while ((result = streamout.flush(ogout)) != 0)
741    {
742//System.out.println("result="+result);
743      try
744      {
745        out.write(ogout.header_base, ogout.header, ogout.header_len);
746        out.flush();
747      }
748      catch (Exception e)
749      {
750        //goto cleanup;
751        break;
752      }
753      try
754      {
755        out.write(ogout.body_base, ogout.body, ogout.body_len);
756        out.flush();
757      }
758      catch (Exception e)
759      {
760        //goto cleanup;
761        break;
762      }
763    }
764
765//System.out.println("%2");
766
767    while (state.fetch_next_packet(op) != 0)
768    {
769      int size = state.blocksize(op);
770      granpos += size;
771//System.out.println("#1");
772      if (needflush != 0)
773      {
774//System.out.println("##1");
775        if (streamout.flush(ogout) != 0)
776        {
777          try
778          {
779            out.write(ogout.header_base, ogout.header, ogout.header_len);
780            out.flush();
781          }
782          catch (Exception e)
783          {
784            e.printStackTrace();
785            //goto cleanup;
786            return -1;
787          }
788          try
789          {
790            out.write(ogout.body_base, ogout.body, ogout.body_len);
791            out.flush();
792          }
793          catch (Exception e)
794          {
795            e.printStackTrace();
796//System.out.println("ogout.body_base.length="+ogout.body_base.length+
797//                   ", ogout.body="+ogout.body+
798//                   ", ogout.body_len="+ogout.body_len);
799            //goto cleanup;
800            return -1;
801          }
802        }
803      }
804//System.out.println("%2 eosin="+eosin);
805      else if (needout != 0)
806      {
807//System.out.println("##2");
808        if (streamout.pageout(ogout) != 0)
809        {
810          try
811          {
812            out.write(ogout.header_base, ogout.header, ogout.header_len);
813            out.flush();
814          }
815          catch (Exception e)
816          {
817            e.printStackTrace();
818            //goto cleanup;
819            return -1;
820          }
821          try
822          {
823            out.write(ogout.body_base, ogout.body, ogout.body_len);
824            out.flush();
825          }
826          catch (Exception e)
827          {
828            e.printStackTrace();
829//System.out.println("ogout.body_base.length="+ogout.body_base.length+
830//                   ", ogout.body="+ogout.body+
831//                   ", ogout.body_len="+ogout.body_len);
832            //goto cleanup;
833            return -1;
834          }
835        }
836      }
837
838//System.out.println("#2");
839
840      needflush = needout = 0;
841
842      if (op.granulepos == -1)
843      {
844        op.granulepos = granpos;
845        streamout.packetin(op);
846      }
847      else
848      {
849        if (granpos > op.granulepos)
850        {
851          granpos = op.granulepos;
852          streamout.packetin(op);
853          needflush = 1;
854        }
855        else
856        {
857          streamout.packetin(op);
858          needout = 1;
859        }
860      }
861//System.out.println("#3");
862    }
863
864//System.out.println("%3");
865
866    streamout.e_o_s = 1;
867    while (streamout.flush(ogout) != 0)
868    {
869      try
870      {
871        out.write(ogout.header_base, ogout.header, ogout.header_len);
872        out.flush();
873      }
874      catch (Exception e)
875      {
876        e.printStackTrace();
877        //goto cleanup;
878        return -1;
879      }
880      try
881      {
882        out.write(ogout.body_base, ogout.body, ogout.body_len);
883        out.flush();
884      }
885      catch (Exception e)
886      {
887        e.printStackTrace();
888//System.out.println("ogout.body_base.length="+ogout.body_base.length+
889//                   ", ogout.body="+ogout.body+
890//                   ", ogout.body_len="+ogout.body_len);
891        //goto cleanup;
892        return -1;
893      }
894    }
895
896//System.out.println("%4");
897
898    state.vi.clear();
899//System.out.println("%3 eosin="+eosin);
900
901//System.out.println("%5");
902
903    eosin = 0;
904    /*
905     *  clear it, because not all paths to here do
906     */
907    while (eosin == 0)
908    {
909      /*
910       *  We reached eos, not eof
911       */
912      /*
913       *  We copy the rest of the stream (other logical streams)
914       *  through, a page at a time.
915       */
916      while (true)
917      {
918        result = state.oy.pageout(ogout);
919//System.out.println(" result4="+result);
920        if (result == 0)
921        {
922          break;
923        }
924        if (result < 0)
925        {
926          System.out.println("Corrupt or missing data, continuing...");
927        }
928        else
929        {
930          /*
931           *  Don't bother going through the rest, we can just
932           *  write the page out now
933           */
934          try
935          {
936            out.write(ogout.header_base, ogout.header, ogout.header_len);
937            out.flush();
938          }
939          catch (Exception e)
940          {
941            //goto cleanup;
942            return -1;
943          }
944          try
945          {
946            out.write(ogout.body_base, ogout.body, ogout.body_len);
947            out.flush();
948          }
949          catch (Exception e)
950          {
951            //goto cleanup;
952            return -1;
953          }
954        }
955      }
956
957      index = state.oy.buffer(CHUNKSIZE);
958      buffer = state.oy.data;
959      try
960      {
961        bytes = state.in.read(buffer, index, CHUNKSIZE);
962      }
963      catch (Exception e)
964      {
965        System.err.println(e);
966        return -1;
967      }
968//System.out.println("bytes="+bytes);
969      state.oy.wrote(bytes);
970
971      if (bytes == 0 || bytes == -1)
972      {
973        eosin = 1;
974        break;
975      }
976    }
977
978    /*
979     *  cleanup:
980     *  ogg_stream_clear(&streamout);
981     *  ogg_packet_clear(&header_comments);
982     *  free(state->mainbuf);
983     *  free(state->bookbuf);
984     *  jorbiscomment_clear_internals(state);
985     *  if(!eosin)
986     *  {
987     *  state->lasterror =
988     *  "Error writing stream to output. "
989     *  "Output stream may be corrupted or truncated.";
990     *  return -1;
991     *  }
992     *  return 0;
993     *  }
994     */
995    return 0;
996  }
997}
998
999
1000/**
1001 *  Description of the Class
1002 *
1003 * @author    tgutwin
1004 */
1005class State
1006{
1007
1008
1009  /**  Description of the Field */
1010  private static int CHUNKSIZE = 4096;
1011  /**  Description of the Field */
1012  SyncState oy;
1013  /**  Description of the Field */
1014  StreamState os;
1015  /**  Description of the Field */
1016  Comment vc;
1017  /**  Description of the Field */
1018  Info vi;
1019
1020  /**  Description of the Field */
1021  InputStream in;
1022  /**  Description of the Field */
1023  int serial;
1024  /**  Description of the Field */
1025  byte[] mainbuf;
1026  /**  Description of the Field */
1027  byte[] bookbuf;
1028  /**  Description of the Field */
1029  int mainlen;
1030  /**  Description of the Field */
1031  int booklen;
1032  /**  Description of the Field */
1033  String lasterror;
1034
1035  /**  Description of the Field */
1036  int prevW;
1037
1038  /**  Description of the Field */
1039  Page og = new Page();
1040
1041
1042  /**
1043   *  Description of the Method
1044   *
1045   * @param  p  Description of the Parameter
1046   * @return    Description of the Return Value
1047   */
1048  int blocksize(Packet p)
1049  {
1050    int _this = vi.blocksize(p);
1051    int ret = (_this + prevW) / 4;
1052
1053    if (prevW == 0)
1054    {
1055      prevW = _this;
1056      return 0;
1057    }
1058
1059    prevW = _this;
1060    return ret;
1061  }
1062
1063
1064  /**
1065   *  Description of the Method
1066   *
1067   * @param  p  Description of the Parameter
1068   * @return    Description of the Return Value
1069   */
1070  int fetch_next_packet(Packet p)
1071  {
1072    int result;
1073    byte[] buffer;
1074    int index;
1075    int bytes;
1076
1077    result = os.packetout(p);
1078
1079    if (result > 0)
1080    {
1081      return 1;
1082    }
1083
1084    while (oy.pageout(og) <= 0)
1085    {
1086      index = oy.buffer(CHUNKSIZE);
1087      buffer = oy.data;
1088      try
1089      {
1090        bytes = in.read(buffer, index, CHUNKSIZE);
1091      }
1092      catch (Exception e)
1093      {
1094        System.err.println(e);
1095        return 0;
1096      }
1097      if (bytes > 0)
1098      {
1099        oy.wrote(bytes);
1100      }
1101      if (bytes == 0 || bytes == -1)
1102      {
1103        return 0;
1104      }
1105    }
1106    os.pagein(og);
1107
1108    return fetch_next_packet(p);
1109  }
1110}
1111