Coverage Report

Created: 2024-09-06 07:53

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