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