Fixed a memory management error in the new codebook code
[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.53 2002/01/22 08:06:07 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->times;i++) /* unpack does the range checking */
167       _time_P[ci->time_type[i]]->free_info(ci->time_param[i]);
168
169     for(i=0;i<ci->floors;i++) /* unpack does the range checking */
170       _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
171     
172     for(i=0;i<ci->residues;i++) /* unpack does the range checking */
173       _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
174
175     for(i=0;i<ci->books;i++){
176       if(ci->book_param[i]){
177         /* knows if the book was not alloced */
178         vorbis_staticbook_destroy(ci->book_param[i]);
179       }
180       if(ci->fullbooks)
181         vorbis_book_clear(ci->fullbooks+i);
182     }
183     if(ci->fullbooks)
184         _ogg_free(ci->fullbooks);
185     
186     for(i=0;i<ci->psys;i++)
187       _vi_psy_free(ci->psy_param[i]);
188
189     _ogg_free(ci);
190   }
191
192   memset(vi,0,sizeof(*vi));
193 }
194
195 /* Header packing/unpacking ********************************************/
196
197 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
198   codec_setup_info     *ci=vi->codec_setup;
199   if(!ci)return(OV_EFAULT);
200
201   vi->version=oggpack_read(opb,32);
202   if(vi->version!=0)return(OV_EVERSION);
203
204   vi->channels=oggpack_read(opb,8);
205   vi->rate=oggpack_read(opb,32);
206
207   vi->bitrate_upper=oggpack_read(opb,32);
208   vi->bitrate_nominal=oggpack_read(opb,32);
209   vi->bitrate_lower=oggpack_read(opb,32);
210
211   ci->blocksizes[0]=1<<oggpack_read(opb,4);
212   ci->blocksizes[1]=1<<oggpack_read(opb,4);
213   
214   if(vi->rate<1)goto err_out;
215   if(vi->channels<1)goto err_out;
216   if(ci->blocksizes[0]<8)goto err_out; 
217   if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
218   
219   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
220
221   return(0);
222  err_out:
223   vorbis_info_clear(vi);
224   return(OV_EBADHEADER);
225 }
226
227 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
228   int i;
229   int vendorlen=oggpack_read(opb,32);
230   if(vendorlen<0)goto err_out;
231   vc->vendor=_ogg_calloc(vendorlen+1,1);
232   _v_readstring(opb,vc->vendor,vendorlen);
233   vc->comments=oggpack_read(opb,32);
234   if(vc->comments<0)goto err_out;
235   vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
236   vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
237             
238   for(i=0;i<vc->comments;i++){
239     int len=oggpack_read(opb,32);
240     if(len<0)goto err_out;
241         vc->comment_lengths[i]=len;
242     vc->user_comments[i]=_ogg_calloc(len+1,1);
243     _v_readstring(opb,vc->user_comments[i],len);
244   }       
245   if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
246
247   return(0);
248  err_out:
249   vorbis_comment_clear(vc);
250   return(OV_EBADHEADER);
251 }
252
253 /* all of the real encoding details are here.  The modes, books,
254    everything */
255 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
256   codec_setup_info     *ci=vi->codec_setup;
257   int i;
258   if(!ci)return(OV_EFAULT);
259
260   /* codebooks */
261   ci->books=oggpack_read(opb,8)+1;
262   /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/
263   for(i=0;i<ci->books;i++){
264     ci->book_param[i]=_ogg_calloc(1,sizeof(*ci->book_param[i]));
265     if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out;
266   }
267
268   /* time backend settings */
269   ci->times=oggpack_read(opb,6)+1;
270   /*ci->time_type=_ogg_malloc(ci->times*sizeof(*ci->time_type));*/
271   /*ci->time_param=_ogg_calloc(ci->times,sizeof(void *));*/
272   for(i=0;i<ci->times;i++){
273     ci->time_type[i]=oggpack_read(opb,16);
274     if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out;
275     ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb);
276     if(!ci->time_param[i])goto err_out;
277   }
278
279   /* floor backend settings */
280   ci->floors=oggpack_read(opb,6)+1;
281   /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/
282   /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/
283   for(i=0;i<ci->floors;i++){
284     ci->floor_type[i]=oggpack_read(opb,16);
285     if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
286     ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
287     if(!ci->floor_param[i])goto err_out;
288   }
289
290   /* residue backend settings */
291   ci->residues=oggpack_read(opb,6)+1;
292   /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/
293   /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/
294   for(i=0;i<ci->residues;i++){
295     ci->residue_type[i]=oggpack_read(opb,16);
296     if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
297     ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
298     if(!ci->residue_param[i])goto err_out;
299   }
300
301   /* map backend settings */
302   ci->maps=oggpack_read(opb,6)+1;
303   /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/
304   /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/
305   for(i=0;i<ci->maps;i++){
306     ci->map_type[i]=oggpack_read(opb,16);
307     if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
308     ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
309     if(!ci->map_param[i])goto err_out;
310   }
311   
312   /* mode settings */
313   ci->modes=oggpack_read(opb,6)+1;
314   /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/
315   for(i=0;i<ci->modes;i++){
316     ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i]));
317     ci->mode_param[i]->blockflag=oggpack_read(opb,1);
318     ci->mode_param[i]->windowtype=oggpack_read(opb,16);
319     ci->mode_param[i]->transformtype=oggpack_read(opb,16);
320     ci->mode_param[i]->mapping=oggpack_read(opb,8);
321
322     if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
323     if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
324     if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
325   }
326   
327   if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
328
329   return(0);
330  err_out:
331   vorbis_info_clear(vi);
332   return(OV_EBADHEADER);
333 }
334
335 /* The Vorbis header is in three packets; the initial small packet in
336    the first page that identifies basic parameters, a second packet
337    with bitstream comments and a third packet that holds the
338    codebook. */
339
340 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
341   oggpack_buffer opb;
342   
343   if(op){
344     oggpack_readinit(&opb,op->packet,op->bytes);
345
346     /* Which of the three types of header is this? */
347     /* Also verify header-ness, vorbis */
348     {
349       char buffer[6];
350       int packtype=oggpack_read(&opb,8);
351       memset(buffer,0,6);
352       _v_readstring(&opb,buffer,6);
353       if(memcmp(buffer,"vorbis",6)){
354         /* not a vorbis header */
355         return(OV_ENOTVORBIS);
356       }
357       switch(packtype){
358       case 0x01: /* least significant *bit* is read first */
359         if(!op->b_o_s){
360           /* Not the initial packet */
361           return(OV_EBADHEADER);
362         }
363         if(vi->rate!=0){
364           /* previously initialized info header */
365           return(OV_EBADHEADER);
366         }
367
368         return(_vorbis_unpack_info(vi,&opb));
369
370       case 0x03: /* least significant *bit* is read first */
371         if(vi->rate==0){
372           /* um... we didn't get the initial header */
373           return(OV_EBADHEADER);
374         }
375
376         return(_vorbis_unpack_comment(vc,&opb));
377
378       case 0x05: /* least significant *bit* is read first */
379         if(vi->rate==0 || vc->vendor==NULL){
380           /* um... we didn;t get the initial header or comments yet */
381           return(OV_EBADHEADER);
382         }
383
384         return(_vorbis_unpack_books(vi,&opb));
385
386       default:
387         /* Not a valid vorbis header type */
388         return(OV_EBADHEADER);
389         break;
390       }
391     }
392   }
393   return(OV_EBADHEADER);
394 }
395
396 /* pack side **********************************************************/
397
398 static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){
399   codec_setup_info     *ci=vi->codec_setup;
400   if(!ci)return(OV_EFAULT);
401
402   /* preamble */  
403   oggpack_write(opb,0x01,8);
404   _v_writestring(opb,"vorbis", 6);
405
406   /* basic information about the stream */
407   oggpack_write(opb,0x00,32);
408   oggpack_write(opb,vi->channels,8);
409   oggpack_write(opb,vi->rate,32);
410
411   oggpack_write(opb,vi->bitrate_upper,32);
412   oggpack_write(opb,vi->bitrate_nominal,32);
413   oggpack_write(opb,vi->bitrate_lower,32);
414
415   oggpack_write(opb,ilog2(ci->blocksizes[0]),4);
416   oggpack_write(opb,ilog2(ci->blocksizes[1]),4);
417   oggpack_write(opb,1,1);
418
419   return(0);
420 }
421
422 static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){
423   char temp[]="Xiphophorus libVorbis I 20011231";
424   int bytes = strlen(temp);
425
426   /* preamble */  
427   oggpack_write(opb,0x03,8);
428   _v_writestring(opb,"vorbis", 6);
429
430   /* vendor */
431   oggpack_write(opb,bytes,32);
432   _v_writestring(opb,temp, bytes);
433   
434   /* comments */
435
436   oggpack_write(opb,vc->comments,32);
437   if(vc->comments){
438     int i;
439     for(i=0;i<vc->comments;i++){
440       if(vc->user_comments[i]){
441         oggpack_write(opb,vc->comment_lengths[i],32);
442         _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]);
443       }else{
444         oggpack_write(opb,0,32);
445       }
446     }
447   }
448   oggpack_write(opb,1,1);
449
450   return(0);
451 }
452  
453 static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){
454   codec_setup_info     *ci=vi->codec_setup;
455   int i;
456   if(!ci)return(OV_EFAULT);
457
458   oggpack_write(opb,0x05,8);
459   _v_writestring(opb,"vorbis", 6);
460
461   /* books */
462   oggpack_write(opb,ci->books-1,8);
463   for(i=0;i<ci->books;i++)
464     if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out;
465
466   /* times */
467   oggpack_write(opb,ci->times-1,6);
468   for(i=0;i<ci->times;i++){
469     oggpack_write(opb,ci->time_type[i],16);
470     _time_P[ci->time_type[i]]->pack(ci->time_param[i],opb);
471   }
472
473   /* floors */
474   oggpack_write(opb,ci->floors-1,6);
475   for(i=0;i<ci->floors;i++){
476     oggpack_write(opb,ci->floor_type[i],16);
477     _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb);
478   }
479
480   /* residues */
481   oggpack_write(opb,ci->residues-1,6);
482   for(i=0;i<ci->residues;i++){
483     oggpack_write(opb,ci->residue_type[i],16);
484     _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb);
485   }
486
487   /* maps */
488   oggpack_write(opb,ci->maps-1,6);
489   for(i=0;i<ci->maps;i++){
490     oggpack_write(opb,ci->map_type[i],16);
491     _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb);
492   }
493
494   /* modes */
495   oggpack_write(opb,ci->modes-1,6);
496   for(i=0;i<ci->modes;i++){
497     oggpack_write(opb,ci->mode_param[i]->blockflag,1);
498     oggpack_write(opb,ci->mode_param[i]->windowtype,16);
499     oggpack_write(opb,ci->mode_param[i]->transformtype,16);
500     oggpack_write(opb,ci->mode_param[i]->mapping,8);
501   }
502   oggpack_write(opb,1,1);
503
504   return(0);
505 err_out:
506   return(-1);
507
508
509 int vorbis_commentheader_out(vorbis_comment *vc,
510                                       ogg_packet *op){
511
512   oggpack_buffer opb;
513
514   oggpack_writeinit(&opb);
515   if(_vorbis_pack_comment(&opb,vc)) return OV_EIMPL;
516
517   op->packet = _ogg_malloc(oggpack_bytes(&opb));
518   memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));
519
520   op->bytes=oggpack_bytes(&opb);
521   op->b_o_s=0;
522   op->e_o_s=0;
523   op->granulepos=0;
524
525   return 0;
526 }
527
528 int vorbis_analysis_headerout(vorbis_dsp_state *v,
529                               vorbis_comment *vc,
530                               ogg_packet *op,
531                               ogg_packet *op_comm,
532                               ogg_packet *op_code){
533   int ret=OV_EIMPL;
534   vorbis_info *vi=v->vi;
535   oggpack_buffer opb;
536   backend_lookup_state *b=v->backend_state;
537
538   if(!b){
539     ret=OV_EFAULT;
540     goto err_out;
541   }
542
543   /* first header packet **********************************************/
544
545   oggpack_writeinit(&opb);
546   if(_vorbis_pack_info(&opb,vi))goto err_out;
547
548   /* build the packet */
549   if(b->header)_ogg_free(b->header);
550   b->header=_ogg_malloc(oggpack_bytes(&opb));
551   memcpy(b->header,opb.buffer,oggpack_bytes(&opb));
552   op->packet=b->header;
553   op->bytes=oggpack_bytes(&opb);
554   op->b_o_s=1;
555   op->e_o_s=0;
556   op->granulepos=0;
557
558   /* second header packet (comments) **********************************/
559
560   oggpack_reset(&opb);
561   if(_vorbis_pack_comment(&opb,vc))goto err_out;
562
563   if(b->header1)_ogg_free(b->header1);
564   b->header1=_ogg_malloc(oggpack_bytes(&opb));
565   memcpy(b->header1,opb.buffer,oggpack_bytes(&opb));
566   op_comm->packet=b->header1;
567   op_comm->bytes=oggpack_bytes(&opb);
568   op_comm->b_o_s=0;
569   op_comm->e_o_s=0;
570   op_comm->granulepos=0;
571
572   /* third header packet (modes/codebooks) ****************************/
573
574   oggpack_reset(&opb);
575   if(_vorbis_pack_books(&opb,vi))goto err_out;
576
577   if(b->header2)_ogg_free(b->header2);
578   b->header2=_ogg_malloc(oggpack_bytes(&opb));
579   memcpy(b->header2,opb.buffer,oggpack_bytes(&opb));
580   op_code->packet=b->header2;
581   op_code->bytes=oggpack_bytes(&opb);
582   op_code->b_o_s=0;
583   op_code->e_o_s=0;
584   op_code->granulepos=0;
585
586   oggpack_writeclear(&opb);
587   return(0);
588  err_out:
589   oggpack_writeclear(&opb);
590   memset(op,0,sizeof(*op));
591   memset(op_comm,0,sizeof(*op_comm));
592   memset(op_code,0,sizeof(*op_code));
593
594   if(b->header)_ogg_free(b->header);
595   if(b->header1)_ogg_free(b->header1);
596   if(b->header2)_ogg_free(b->header2);
597   b->header=NULL;
598   b->header1=NULL;
599   b->header2=NULL;
600   return(ret);
601 }
602