The 'Grand Simplification' officially becomes the mainline toward rc4.
[platform/upstream/libvorbis.git] / lib / info.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
9  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
10  *                                                                  *
11  ********************************************************************
12
13  function: maintain the info structure, info <-> header packets
14  last mod: $Id: info.c,v 1.54 2002/06/28 22:19:35 xiphmont Exp $
15
16  ********************************************************************/
17
18 /* general handling of the header and the vorbis_info structure (and
19    substructures) */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <ogg/ogg.h>
25 #include "vorbis/codec.h"
26 #include "codec_internal.h"
27 #include "codebook.h"
28 #include "registry.h"
29 #include "window.h"
30 #include "psy.h"
31 #include "misc.h"
32 #include "os.h"
33
34 /* helpers */
35 static int ilog2(unsigned int v){
36   int ret=0;
37   while(v>1){
38     ret++;
39     v>>=1;
40   }
41   return(ret);
42 }
43
44 static void _v_writestring(oggpack_buffer *o,char *s, int bytes){
45
46   while(bytes--){
47     oggpack_write(o,*s++,8);
48   }
49 }
50
51 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
52   while(bytes--){
53     *buf++=oggpack_read(o,8);
54   }
55 }
56
57 void vorbis_comment_init(vorbis_comment *vc){
58   memset(vc,0,sizeof(*vc));
59 }
60
61 void vorbis_comment_add(vorbis_comment *vc,char *comment){
62   vc->user_comments=_ogg_realloc(vc->user_comments,
63                             (vc->comments+2)*sizeof(*vc->user_comments));
64   vc->comment_lengths=_ogg_realloc(vc->comment_lengths,
65                             (vc->comments+2)*sizeof(*vc->comment_lengths));
66   vc->comment_lengths[vc->comments]=strlen(comment);
67   vc->user_comments[vc->comments]=_ogg_malloc(vc->comment_lengths[vc->comments]+1);
68   strcpy(vc->user_comments[vc->comments], comment);
69   vc->comments++;
70   vc->user_comments[vc->comments]=NULL;
71 }
72
73 void vorbis_comment_add_tag(vorbis_comment *vc, char *tag, char *contents){
74   char *comment=alloca(strlen(tag)+strlen(contents)+2); /* +2 for = and \0 */
75   strcpy(comment, tag);
76   strcat(comment, "=");
77   strcat(comment, contents);
78   vorbis_comment_add(vc, comment);
79 }
80
81 /* This is more or less the same as strncasecmp - but that doesn't exist
82  * everywhere, and this is a fairly trivial function, so we include it */
83 static int tagcompare(const char *s1, const char *s2, int n){
84   int c=0;
85   while(c < n){
86     if(toupper(s1[c]) != toupper(s2[c]))
87       return !0;
88     c++;
89   }
90   return 0;
91 }
92
93 char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){
94   long i;
95   int found = 0;
96   int taglen = strlen(tag)+1; /* +1 for the = we append */
97   char *fulltag = alloca(taglen+ 1);
98
99   strcpy(fulltag, tag);
100   strcat(fulltag, "=");
101   
102   for(i=0;i<vc->comments;i++){
103     if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
104       if(count == found)
105         /* We return a pointer to the data, not a copy */
106         return vc->user_comments[i] + taglen;
107       else
108         found++;
109     }
110   }
111   return NULL; /* didn't find anything */
112 }
113
114 int vorbis_comment_query_count(vorbis_comment *vc, char *tag){
115   int i,count=0;
116   int taglen = strlen(tag)+1; /* +1 for the = we append */
117   char *fulltag = alloca(taglen+1);
118   strcpy(fulltag,tag);
119   strcat(fulltag, "=");
120
121   for(i=0;i<vc->comments;i++){
122     if(!tagcompare(vc->user_comments[i], fulltag, taglen))
123       count++;
124   }
125
126   return count;
127 }
128
129 void vorbis_comment_clear(vorbis_comment *vc){
130   if(vc){
131     long i;
132     for(i=0;i<vc->comments;i++)
133       if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
134     if(vc->user_comments)_ogg_free(vc->user_comments);
135         if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
136     if(vc->vendor)_ogg_free(vc->vendor);
137   }
138   memset(vc,0,sizeof(*vc));
139 }
140
141 /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
142    They may be equal, but short will never ge greater than long */
143 int vorbis_info_blocksize(vorbis_info *vi,int zo){
144   codec_setup_info *ci = vi->codec_setup;
145   return ci ? ci->blocksizes[zo] : -1;
146 }
147
148 /* used by synthesis, which has a full, alloced vi */
149 void vorbis_info_init(vorbis_info *vi){
150   memset(vi,0,sizeof(*vi));
151   vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info));
152 }
153
154 void vorbis_info_clear(vorbis_info *vi){
155   codec_setup_info     *ci=vi->codec_setup;
156   int i;
157
158   if(ci){
159
160     for(i=0;i<ci->modes;i++)
161       if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
162
163     for(i=0;i<ci->maps;i++) /* unpack does the range checking */
164       _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
165
166     for(i=0;i<ci->floors;i++) /* unpack does the range checking */
167       _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
168     
169     for(i=0;i<ci->residues;i++) /* unpack does the range checking */
170       _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
171
172     for(i=0;i<ci->books;i++){
173       if(ci->book_param[i]){
174         /* knows if the book was not alloced */
175         vorbis_staticbook_destroy(ci->book_param[i]);
176       }
177       if(ci->fullbooks)
178         vorbis_book_clear(ci->fullbooks+i);
179     }
180     if(ci->fullbooks)
181         _ogg_free(ci->fullbooks);
182     
183     for(i=0;i<ci->psys;i++)
184       _vi_psy_free(ci->psy_param[i]);
185
186     _ogg_free(ci);
187   }
188
189   memset(vi,0,sizeof(*vi));
190 }
191
192 /* Header packing/unpacking ********************************************/
193
194 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
195   codec_setup_info     *ci=vi->codec_setup;
196   if(!ci)return(OV_EFAULT);
197
198   vi->version=oggpack_read(opb,32);
199   if(vi->version!=0)return(OV_EVERSION);
200
201   vi->channels=oggpack_read(opb,8);
202   vi->rate=oggpack_read(opb,32);
203
204   vi->bitrate_upper=oggpack_read(opb,32);
205   vi->bitrate_nominal=oggpack_read(opb,32);
206   vi->bitrate_lower=oggpack_read(opb,32);
207
208   ci->blocksizes[0]=1<<oggpack_read(opb,4);
209   ci->blocksizes[1]=1<<oggpack_read(opb,4);
210   
211   if(vi->rate<1)goto err_out;
212   if(vi->channels<1)goto err_out;
213   if(ci->blocksizes[0]<8)goto err_out; 
214   if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
215   
216   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
217
218   return(0);
219  err_out:
220   vorbis_info_clear(vi);
221   return(OV_EBADHEADER);
222 }
223
224 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
225   int i;
226   int vendorlen=oggpack_read(opb,32);
227   if(vendorlen<0)goto err_out;
228   vc->vendor=_ogg_calloc(vendorlen+1,1);
229   _v_readstring(opb,vc->vendor,vendorlen);
230   vc->comments=oggpack_read(opb,32);
231   if(vc->comments<0)goto err_out;
232   vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
233   vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
234             
235   for(i=0;i<vc->comments;i++){
236     int len=oggpack_read(opb,32);
237     if(len<0)goto err_out;
238         vc->comment_lengths[i]=len;
239     vc->user_comments[i]=_ogg_calloc(len+1,1);
240     _v_readstring(opb,vc->user_comments[i],len);
241   }       
242   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
243
244   return(0);
245  err_out:
246   vorbis_comment_clear(vc);
247   return(OV_EBADHEADER);
248 }
249
250 /* all of the real encoding details are here.  The modes, books,
251    everything */
252 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
253   codec_setup_info     *ci=vi->codec_setup;
254   int i;
255   if(!ci)return(OV_EFAULT);
256
257   /* codebooks */
258   ci->books=oggpack_read(opb,8)+1;
259   /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/
260   for(i=0;i<ci->books;i++){
261     ci->book_param[i]=_ogg_calloc(1,sizeof(*ci->book_param[i]));
262     if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out;
263   }
264
265   /* time backend settings; hooks are unused */
266   {
267     int times=oggpack_read(opb,6)+1;
268     for(i=0;i<times;i++){
269       int test=oggpack_read(opb,16);
270       if(test<0 || test>=VI_TIMEB)goto err_out;
271     }
272   }
273
274   /* floor backend settings */
275   ci->floors=oggpack_read(opb,6)+1;
276   /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/
277   /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/
278   for(i=0;i<ci->floors;i++){
279     ci->floor_type[i]=oggpack_read(opb,16);
280     if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
281     ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
282     if(!ci->floor_param[i])goto err_out;
283   }
284
285   /* residue backend settings */
286   ci->residues=oggpack_read(opb,6)+1;
287   /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/
288   /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/
289   for(i=0;i<ci->residues;i++){
290     ci->residue_type[i]=oggpack_read(opb,16);
291     if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
292     ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
293     if(!ci->residue_param[i])goto err_out;
294   }
295
296   /* map backend settings */
297   ci->maps=oggpack_read(opb,6)+1;
298   /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/
299   /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/
300   for(i=0;i<ci->maps;i++){
301     ci->map_type[i]=oggpack_read(opb,16);
302     if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
303     ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
304     if(!ci->map_param[i])goto err_out;
305   }
306   
307   /* mode settings */
308   ci->modes=oggpack_read(opb,6)+1;
309   /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/
310   for(i=0;i<ci->modes;i++){
311     ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i]));
312     ci->mode_param[i]->blockflag=oggpack_read(opb,1);
313     ci->mode_param[i]->windowtype=oggpack_read(opb,16);
314     ci->mode_param[i]->transformtype=oggpack_read(opb,16);
315     ci->mode_param[i]->mapping=oggpack_read(opb,8);
316
317     if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
318     if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
319     if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
320   }
321   
322   if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
323
324   return(0);
325  err_out:
326   vorbis_info_clear(vi);
327   return(OV_EBADHEADER);
328 }
329
330 /* The Vorbis header is in three packets; the initial small packet in
331    the first page that identifies basic parameters, a second packet
332    with bitstream comments and a third packet that holds the
333    codebook. */
334
335 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
336   oggpack_buffer opb;
337   
338   if(op){
339     oggpack_readinit(&opb,op->packet,op->bytes);
340
341     /* Which of the three types of header is this? */
342     /* Also verify header-ness, vorbis */
343     {
344       char buffer[6];
345       int packtype=oggpack_read(&opb,8);
346       memset(buffer,0,6);
347       _v_readstring(&opb,buffer,6);
348       if(memcmp(buffer,"vorbis",6)){
349         /* not a vorbis header */
350         return(OV_ENOTVORBIS);
351       }
352       switch(packtype){
353       case 0x01: /* least significant *bit* is read first */
354         if(!op->b_o_s){
355           /* Not the initial packet */
356           return(OV_EBADHEADER);
357         }
358         if(vi->rate!=0){
359           /* previously initialized info header */
360           return(OV_EBADHEADER);
361         }
362
363         return(_vorbis_unpack_info(vi,&opb));
364
365       case 0x03: /* least significant *bit* is read first */
366         if(vi->rate==0){
367           /* um... we didn't get the initial header */
368           return(OV_EBADHEADER);
369         }
370
371         return(_vorbis_unpack_comment(vc,&opb));
372
373       case 0x05: /* least significant *bit* is read first */
374         if(vi->rate==0 || vc->vendor==NULL){
375           /* um... we didn;t get the initial header or comments yet */
376           return(OV_EBADHEADER);
377         }
378
379         return(_vorbis_unpack_books(vi,&opb));
380
381       default:
382         /* Not a valid vorbis header type */
383         return(OV_EBADHEADER);
384         break;
385       }
386     }
387   }
388   return(OV_EBADHEADER);
389 }
390
391 /* pack side **********************************************************/
392
393 static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){
394   codec_setup_info     *ci=vi->codec_setup;
395   if(!ci)return(OV_EFAULT);
396
397   /* preamble */  
398   oggpack_write(opb,0x01,8);
399   _v_writestring(opb,"vorbis", 6);
400
401   /* basic information about the stream */
402   oggpack_write(opb,0x00,32);
403   oggpack_write(opb,vi->channels,8);
404   oggpack_write(opb,vi->rate,32);
405
406   oggpack_write(opb,vi->bitrate_upper,32);
407   oggpack_write(opb,vi->bitrate_nominal,32);
408   oggpack_write(opb,vi->bitrate_lower,32);
409
410   oggpack_write(opb,ilog2(ci->blocksizes[0]),4);
411   oggpack_write(opb,ilog2(ci->blocksizes[1]),4);
412   oggpack_write(opb,1,1);
413
414   return(0);
415 }
416
417 static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){
418   char temp[]="Xiphophorus libVorbis I 20020623";
419   int bytes = strlen(temp);
420
421   /* preamble */  
422   oggpack_write(opb,0x03,8);
423   _v_writestring(opb,"vorbis", 6);
424
425   /* vendor */
426   oggpack_write(opb,bytes,32);
427   _v_writestring(opb,temp, bytes);
428   
429   /* comments */
430
431   oggpack_write(opb,vc->comments,32);
432   if(vc->comments){
433     int i;
434     for(i=0;i<vc->comments;i++){
435       if(vc->user_comments[i]){
436         oggpack_write(opb,vc->comment_lengths[i],32);
437         _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]);
438       }else{
439         oggpack_write(opb,0,32);
440       }
441     }
442   }
443   oggpack_write(opb,1,1);
444
445   return(0);
446 }
447  
448 static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){
449   codec_setup_info     *ci=vi->codec_setup;
450   int i;
451   if(!ci)return(OV_EFAULT);
452
453   oggpack_write(opb,0x05,8);
454   _v_writestring(opb,"vorbis", 6);
455
456   /* books */
457   oggpack_write(opb,ci->books-1,8);
458   for(i=0;i<ci->books;i++)
459     if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out;
460
461   /* times; hook placeholders */
462   oggpack_write(opb,0,6);
463   oggpack_write(opb,0,16);
464
465   /* floors */
466   oggpack_write(opb,ci->floors-1,6);
467   for(i=0;i<ci->floors;i++){
468     oggpack_write(opb,ci->floor_type[i],16);
469     if(_floor_P[ci->floor_type[i]]->pack)
470       _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb);
471     else
472       goto err_out;
473   }
474
475   /* residues */
476   oggpack_write(opb,ci->residues-1,6);
477   for(i=0;i<ci->residues;i++){
478     oggpack_write(opb,ci->residue_type[i],16);
479     _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb);
480   }
481
482   /* maps */
483   oggpack_write(opb,ci->maps-1,6);
484   for(i=0;i<ci->maps;i++){
485     oggpack_write(opb,ci->map_type[i],16);
486     _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb);
487   }
488
489   /* modes */
490   oggpack_write(opb,ci->modes-1,6);
491   for(i=0;i<ci->modes;i++){
492     oggpack_write(opb,ci->mode_param[i]->blockflag,1);
493     oggpack_write(opb,ci->mode_param[i]->windowtype,16);
494     oggpack_write(opb,ci->mode_param[i]->transformtype,16);
495     oggpack_write(opb,ci->mode_param[i]->mapping,8);
496   }
497   oggpack_write(opb,1,1);
498
499   return(0);
500 err_out:
501   return(-1);
502
503
504 int vorbis_commentheader_out(vorbis_comment *vc,
505                                       ogg_packet *op){
506
507   oggpack_buffer opb;
508
509   oggpack_writeinit(&opb);
510   if(_vorbis_pack_comment(&opb,vc)) return OV_EIMPL;
511
512   op->packet = _ogg_malloc(oggpack_bytes(&opb));
513   memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));
514
515   op->bytes=oggpack_bytes(&opb);
516   op->b_o_s=0;
517   op->e_o_s=0;
518   op->granulepos=0;
519
520   return 0;
521 }
522
523 int vorbis_analysis_headerout(vorbis_dsp_state *v,
524                               vorbis_comment *vc,
525                               ogg_packet *op,
526                               ogg_packet *op_comm,
527                               ogg_packet *op_code){
528   int ret=OV_EIMPL;
529   vorbis_info *vi=v->vi;
530   oggpack_buffer opb;
531   backend_lookup_state *b=v->backend_state;
532
533   if(!b){
534     ret=OV_EFAULT;
535     goto err_out;
536   }
537
538   /* first header packet **********************************************/
539
540   oggpack_writeinit(&opb);
541   if(_vorbis_pack_info(&opb,vi))goto err_out;
542
543   /* build the packet */
544   if(b->header)_ogg_free(b->header);
545   b->header=_ogg_malloc(oggpack_bytes(&opb));
546   memcpy(b->header,opb.buffer,oggpack_bytes(&opb));
547   op->packet=b->header;
548   op->bytes=oggpack_bytes(&opb);
549   op->b_o_s=1;
550   op->e_o_s=0;
551   op->granulepos=0;
552
553   /* second header packet (comments) **********************************/
554
555   oggpack_reset(&opb);
556   if(_vorbis_pack_comment(&opb,vc))goto err_out;
557
558   if(b->header1)_ogg_free(b->header1);
559   b->header1=_ogg_malloc(oggpack_bytes(&opb));
560   memcpy(b->header1,opb.buffer,oggpack_bytes(&opb));
561   op_comm->packet=b->header1;
562   op_comm->bytes=oggpack_bytes(&opb);
563   op_comm->b_o_s=0;
564   op_comm->e_o_s=0;
565   op_comm->granulepos=0;
566
567   /* third header packet (modes/codebooks) ****************************/
568
569   oggpack_reset(&opb);
570   if(_vorbis_pack_books(&opb,vi))goto err_out;
571
572   if(b->header2)_ogg_free(b->header2);
573   b->header2=_ogg_malloc(oggpack_bytes(&opb));
574   memcpy(b->header2,opb.buffer,oggpack_bytes(&opb));
575   op_code->packet=b->header2;
576   op_code->bytes=oggpack_bytes(&opb);
577   op_code->b_o_s=0;
578   op_code->e_o_s=0;
579   op_code->granulepos=0;
580
581   oggpack_writeclear(&opb);
582   return(0);
583  err_out:
584   oggpack_writeclear(&opb);
585   memset(op,0,sizeof(*op));
586   memset(op_comm,0,sizeof(*op_comm));
587   memset(op_code,0,sizeof(*op_code));
588
589   if(b->header)_ogg_free(b->header);
590   if(b->header1)_ogg_free(b->header1);
591   if(b->header2)_ogg_free(b->header2);
592   b->header=NULL;
593   b->header1=NULL;
594   b->header2=NULL;
595   return(ret);
596 }
597