1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE libopusfile 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 libopusfile SOURCE CODE IS (C) COPYRIGHT 2012                *
9  * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
10  *                                                                  *
11  ********************************************************************/
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15 
16 #include "internal.h"
17 #include <limits.h>
18 #include <string.h>
19 
op_parse_uint16le(const unsigned char * _data)20 static unsigned op_parse_uint16le(const unsigned char *_data){
21   return _data[0]|_data[1]<<8;
22 }
23 
op_parse_int16le(const unsigned char * _data)24 static int op_parse_int16le(const unsigned char *_data){
25   int ret;
26   ret=_data[0]|_data[1]<<8;
27   return (ret^0x8000)-0x8000;
28 }
29 
op_parse_uint32le(const unsigned char * _data)30 static opus_uint32 op_parse_uint32le(const unsigned char *_data){
31   return _data[0]|(opus_uint32)_data[1]<<8|
32    (opus_uint32)_data[2]<<16|(opus_uint32)_data[3]<<24;
33 }
34 
op_parse_uint32be(const unsigned char * _data)35 static opus_uint32 op_parse_uint32be(const unsigned char *_data){
36   return _data[3]|(opus_uint32)_data[2]<<8|
37    (opus_uint32)_data[1]<<16|(opus_uint32)_data[0]<<24;
38 }
39 
opus_head_parse(OpusHead * _head,const unsigned char * _data,size_t _len)40 int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){
41   OpusHead head;
42   if(_len<8)return OP_ENOTFORMAT;
43   if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT;
44   if(_len<9)return OP_EBADHEADER;
45   head.version=_data[8];
46   if(head.version>15)return OP_EVERSION;
47   if(_len<19)return OP_EBADHEADER;
48   head.channel_count=_data[9];
49   head.pre_skip=op_parse_uint16le(_data+10);
50   head.input_sample_rate=op_parse_uint32le(_data+12);
51   head.output_gain=op_parse_int16le(_data+16);
52   head.mapping_family=_data[18];
53   if(head.mapping_family==0){
54     if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER;
55     if(head.version<=1&&_len>19)return OP_EBADHEADER;
56     head.stream_count=1;
57     head.coupled_count=head.channel_count-1;
58     if(_head!=NULL){
59       _head->mapping[0]=0;
60       _head->mapping[1]=1;
61     }
62   }
63   else if(head.mapping_family==1){
64     size_t size;
65     int    ci;
66     if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER;
67     size=21+head.channel_count;
68     if(_len<size||head.version<=1&&_len>size)return OP_EBADHEADER;
69     head.stream_count=_data[19];
70     if(head.stream_count<1)return OP_EBADHEADER;
71     head.coupled_count=_data[20];
72     if(head.coupled_count>head.stream_count)return OP_EBADHEADER;
73     for(ci=0;ci<head.channel_count;ci++){
74       if(_data[21+ci]>=head.stream_count+head.coupled_count
75        &&_data[21+ci]!=255){
76         return OP_EBADHEADER;
77       }
78     }
79     if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count);
80   }
81   /*General purpose players should not attempt to play back content with
82      channel mapping family 255.*/
83   else if(head.mapping_family==255)return OP_EIMPL;
84   /*No other channel mapping families are currently defined.*/
85   else return OP_EBADHEADER;
86   if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head);
87   return 0;
88 }
89 
opus_tags_init(OpusTags * _tags)90 void opus_tags_init(OpusTags *_tags){
91   memset(_tags,0,sizeof(*_tags));
92 }
93 
opus_tags_clear(OpusTags * _tags)94 void opus_tags_clear(OpusTags *_tags){
95   int ncomments;
96   int ci;
97   ncomments=_tags->comments;
98   if(_tags->user_comments!=NULL)ncomments++;
99   for(ci=ncomments;ci-->0;)_ogg_free(_tags->user_comments[ci]);
100   _ogg_free(_tags->user_comments);
101   _ogg_free(_tags->comment_lengths);
102   _ogg_free(_tags->vendor);
103 }
104 
105 /*Ensure there's room for up to _ncomments comments.*/
op_tags_ensure_capacity(OpusTags * _tags,size_t _ncomments)106 static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){
107   char   **user_comments;
108   int     *comment_lengths;
109   int      cur_ncomments;
110   char    *binary_suffix_data;
111   int      binary_suffix_len;
112   size_t   size;
113   if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT;
114   size=sizeof(*_tags->comment_lengths)*(_ncomments+1);
115   if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT;
116   cur_ncomments=_tags->comments;
117   comment_lengths=_tags->comment_lengths;
118   binary_suffix_len=comment_lengths==NULL?0:comment_lengths[cur_ncomments];
119   comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size);
120   if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
121   comment_lengths[_ncomments]=binary_suffix_len;
122   _tags->comment_lengths=comment_lengths;
123   size=sizeof(*_tags->user_comments)*(_ncomments+1);
124   if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT;
125   user_comments=_tags->user_comments;
126   binary_suffix_data=user_comments==NULL?NULL:user_comments[cur_ncomments];
127   user_comments=(char **)_ogg_realloc(_tags->user_comments,size);
128   if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
129   user_comments[_ncomments]=binary_suffix_data;
130   _tags->user_comments=user_comments;
131   return 0;
132 }
133 
134 /*Duplicate a (possibly non-NUL terminated) string with a known length.*/
op_strdup_with_len(const char * _s,size_t _len)135 static char *op_strdup_with_len(const char *_s,size_t _len){
136   size_t  size;
137   char   *ret;
138   size=sizeof(*ret)*(_len+1);
139   if(OP_UNLIKELY(size<_len))return NULL;
140   ret=(char *)_ogg_malloc(size);
141   if(OP_LIKELY(ret!=NULL)){
142     ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len);
143     ret[_len]='\0';
144   }
145   return ret;
146 }
147 
148 /*The actual implementation of opus_tags_parse().
149   Unlike the public API, this function requires _tags to already be
150    initialized, modifies its contents before success is guaranteed, and assumes
151    the caller will clear it on error.*/
opus_tags_parse_impl(OpusTags * _tags,const unsigned char * _data,size_t _len)152 static int opus_tags_parse_impl(OpusTags *_tags,
153  const unsigned char *_data,size_t _len){
154   opus_uint32 count;
155   size_t      len;
156   int         ncomments;
157   int         ci;
158   len=_len;
159   if(len<8)return OP_ENOTFORMAT;
160   if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT;
161   if(len<16)return OP_EBADHEADER;
162   _data+=8;
163   len-=8;
164   count=op_parse_uint32le(_data);
165   _data+=4;
166   len-=4;
167   if(count>len)return OP_EBADHEADER;
168   if(_tags!=NULL){
169     _tags->vendor=op_strdup_with_len((char *)_data,count);
170     if(_tags->vendor==NULL)return OP_EFAULT;
171   }
172   _data+=count;
173   len-=count;
174   if(len<4)return OP_EBADHEADER;
175   count=op_parse_uint32le(_data);
176   _data+=4;
177   len-=4;
178   /*Check to make sure there's minimally sufficient data left in the packet.*/
179   if(count>len>>2)return OP_EBADHEADER;
180   /*Check for overflow (the API limits this to an int).*/
181   if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT;
182   if(_tags!=NULL){
183     int ret;
184     ret=op_tags_ensure_capacity(_tags,count);
185     if(ret<0)return ret;
186   }
187   ncomments=(int)count;
188   for(ci=0;ci<ncomments;ci++){
189     /*Check to make sure there's minimally sufficient data left in the packet.*/
190     if((size_t)(ncomments-ci)>len>>2)return OP_EBADHEADER;
191     count=op_parse_uint32le(_data);
192     _data+=4;
193     len-=4;
194     if(count>len)return OP_EBADHEADER;
195     /*Check for overflow (the API limits this to an int).*/
196     if(count>(opus_uint32)INT_MAX)return OP_EFAULT;
197     if(_tags!=NULL){
198       _tags->user_comments[ci]=op_strdup_with_len((char *)_data,count);
199       if(_tags->user_comments[ci]==NULL)return OP_EFAULT;
200       _tags->comment_lengths[ci]=(int)count;
201       _tags->comments=ci+1;
202       /*Needed by opus_tags_clear() if we fail before parsing the (optional)
203          binary metadata.*/
204       _tags->user_comments[ci+1]=NULL;
205     }
206     _data+=count;
207     len-=count;
208   }
209   if(len>0&&(_data[0]&1)){
210     if(len>(opus_uint32)INT_MAX)return OP_EFAULT;
211     if(_tags!=NULL){
212       _tags->user_comments[ncomments]=(char *)_ogg_malloc(len);
213       if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT;
214       memcpy(_tags->user_comments[ncomments],_data,len);
215       _tags->comment_lengths[ncomments]=(int)len;
216     }
217   }
218   return 0;
219 }
220 
opus_tags_parse(OpusTags * _tags,const unsigned char * _data,size_t _len)221 int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){
222   if(_tags!=NULL){
223     OpusTags tags;
224     int      ret;
225     opus_tags_init(&tags);
226     ret=opus_tags_parse_impl(&tags,_data,_len);
227     if(ret<0)opus_tags_clear(&tags);
228     else *_tags=*&tags;
229     return ret;
230   }
231   else return opus_tags_parse_impl(NULL,_data,_len);
232 }
233 
234 /*The actual implementation of opus_tags_copy().
235   Unlike the public API, this function requires _dst to already be
236    initialized, modifies its contents before success is guaranteed, and assumes
237    the caller will clear it on error.*/
opus_tags_copy_impl(OpusTags * _dst,const OpusTags * _src)238 static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){
239   char *vendor;
240   int   ncomments;
241   int   ret;
242   int   ci;
243   vendor=_src->vendor;
244   _dst->vendor=op_strdup_with_len(vendor,strlen(vendor));
245   if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT;
246   ncomments=_src->comments;
247   ret=op_tags_ensure_capacity(_dst,ncomments);
248   if(OP_UNLIKELY(ret<0))return ret;
249   for(ci=0;ci<ncomments;ci++){
250     int len;
251     len=_src->comment_lengths[ci];
252     OP_ASSERT(len>=0);
253     _dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len);
254     if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT;
255     _dst->comment_lengths[ci]=len;
256     _dst->comments=ci+1;
257   }
258   if(_src->comment_lengths!=NULL){
259     int len;
260     len=_src->comment_lengths[ncomments];
261     if(len>0){
262       _dst->user_comments[ncomments]=(char *)_ogg_malloc(len);
263       if(OP_UNLIKELY(_dst->user_comments[ncomments]==NULL))return OP_EFAULT;
264       memcpy(_dst->user_comments[ncomments],_src->user_comments[ncomments],len);
265       _dst->comment_lengths[ncomments]=len;
266     }
267   }
268   return 0;
269 }
270 
opus_tags_copy(OpusTags * _dst,const OpusTags * _src)271 int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){
272   OpusTags dst;
273   int      ret;
274   opus_tags_init(&dst);
275   ret=opus_tags_copy_impl(&dst,_src);
276   if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst);
277   else *_dst=*&dst;
278   return 0;
279 }
280 
opus_tags_add(OpusTags * _tags,const char * _tag,const char * _value)281 int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
282   char *comment;
283   int   tag_len;
284   int   value_len;
285   int   ncomments;
286   int   ret;
287   ncomments=_tags->comments;
288   ret=op_tags_ensure_capacity(_tags,ncomments+1);
289   if(OP_UNLIKELY(ret<0))return ret;
290   tag_len=strlen(_tag);
291   value_len=strlen(_value);
292   /*+2 for '=' and '\0'.*/
293   comment=(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
294   if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
295   memcpy(comment,_tag,sizeof(*comment)*tag_len);
296   comment[tag_len]='=';
297   memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
298   _tags->user_comments[ncomments]=comment;
299   _tags->comment_lengths[ncomments]=tag_len+value_len+1;
300   _tags->comments=ncomments+1;
301   return 0;
302 }
303 
opus_tags_add_comment(OpusTags * _tags,const char * _comment)304 int opus_tags_add_comment(OpusTags *_tags,const char *_comment){
305   char *comment;
306   int   comment_len;
307   int   ncomments;
308   int   ret;
309   ncomments=_tags->comments;
310   ret=op_tags_ensure_capacity(_tags,ncomments+1);
311   if(OP_UNLIKELY(ret<0))return ret;
312   comment_len=(int)strlen(_comment);
313   comment=op_strdup_with_len(_comment,comment_len);
314   if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
315   _tags->user_comments[ncomments]=comment;
316   _tags->comment_lengths[ncomments]=comment_len;
317   _tags->comments=ncomments+1;
318   return 0;
319 }
320 
opus_tags_set_binary_suffix(OpusTags * _tags,const unsigned char * _data,int _len)321 int opus_tags_set_binary_suffix(OpusTags *_tags,
322  const unsigned char *_data,int _len){
323   unsigned char *binary_suffix_data;
324   int            ncomments;
325   int            ret;
326   if(_len<0||_len>0&&(_data==NULL||!(_data[0]&1)))return OP_EINVAL;
327   ncomments=_tags->comments;
328   ret=op_tags_ensure_capacity(_tags,ncomments);
329   if(OP_UNLIKELY(ret<0))return ret;
330   binary_suffix_data=
331    (unsigned char *)_ogg_realloc(_tags->user_comments[ncomments],_len);
332   if(OP_UNLIKELY(binary_suffix_data==NULL))return OP_EFAULT;
333   memcpy(binary_suffix_data,_data,_len);
334   _tags->user_comments[ncomments]=(char *)binary_suffix_data;
335   _tags->comment_lengths[ncomments]=_len;
336   return 0;
337 }
338 
opus_tagcompare(const char * _tag_name,const char * _comment)339 int opus_tagcompare(const char *_tag_name,const char *_comment){
340   return opus_tagncompare(_tag_name,strlen(_tag_name),_comment);
341 }
342 
opus_tagncompare(const char * _tag_name,int _tag_len,const char * _comment)343 int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
344   int ret;
345   OP_ASSERT(_tag_len>=0);
346   ret=op_strncasecmp(_tag_name,_comment,_tag_len);
347   return ret?ret:'='-_comment[_tag_len];
348 }
349 
opus_tags_query(const OpusTags * _tags,const char * _tag,int _count)350 const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
351   char **user_comments;
352   int    tag_len;
353   int    found;
354   int    ncomments;
355   int    ci;
356   tag_len=strlen(_tag);
357   ncomments=_tags->comments;
358   user_comments=_tags->user_comments;
359   found=0;
360   for(ci=0;ci<ncomments;ci++){
361     if(!opus_tagncompare(_tag,tag_len,user_comments[ci])){
362       /*We return a pointer to the data, not a copy.*/
363       if(_count==found++)return user_comments[ci]+tag_len+1;
364     }
365   }
366   /*Didn't find anything.*/
367   return NULL;
368 }
369 
opus_tags_query_count(const OpusTags * _tags,const char * _tag)370 int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
371   char **user_comments;
372   int    tag_len;
373   int    found;
374   int    ncomments;
375   int    ci;
376   tag_len=strlen(_tag);
377   ncomments=_tags->comments;
378   user_comments=_tags->user_comments;
379   found=0;
380   for(ci=0;ci<ncomments;ci++){
381     if(!opus_tagncompare(_tag,tag_len,user_comments[ci]))found++;
382   }
383   return found;
384 }
385 
opus_tags_get_binary_suffix(const OpusTags * _tags,int * _len)386 const unsigned char *opus_tags_get_binary_suffix(const OpusTags *_tags,
387  int *_len){
388   int ncomments;
389   int len;
390   ncomments=_tags->comments;
391   len=_tags->comment_lengths==NULL?0:_tags->comment_lengths[ncomments];
392   *_len=len;
393   OP_ASSERT(len==0||_tags->user_comments!=NULL);
394   return len>0?(const unsigned char *)_tags->user_comments[ncomments]:NULL;
395 }
396 
opus_tags_get_gain(const OpusTags * _tags,int * _gain_q8,const char * _tag_name,size_t _tag_len)397 static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8,
398  const char *_tag_name,size_t _tag_len){
399   char **comments;
400   int    ncomments;
401   int    ci;
402   comments=_tags->user_comments;
403   ncomments=_tags->comments;
404   /*Look for the first valid tag with the name _tag_name and use that.*/
405   for(ci=0;ci<ncomments;ci++){
406     if(opus_tagncompare(_tag_name,_tag_len,comments[ci])==0){
407       char       *p;
408       opus_int32  gain_q8;
409       int         negative;
410       p=comments[ci]+_tag_len+1;
411       negative=0;
412       if(*p=='-'){
413         negative=-1;
414         p++;
415       }
416       else if(*p=='+')p++;
417       gain_q8=0;
418       while(*p>='0'&&*p<='9'){
419         gain_q8=10*gain_q8+*p-'0';
420         if(gain_q8>32767-negative)break;
421         p++;
422       }
423       /*This didn't look like a signed 16-bit decimal integer.
424         Not a valid gain tag.*/
425       if(*p!='\0')continue;
426       *_gain_q8=(int)(gain_q8+negative^negative);
427       return 0;
428     }
429   }
430   return OP_FALSE;
431 }
432 
opus_tags_get_album_gain(const OpusTags * _tags,int * _gain_q8)433 int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8){
434   return opus_tags_get_gain(_tags,_gain_q8,"R128_ALBUM_GAIN",15);
435 }
436 
opus_tags_get_track_gain(const OpusTags * _tags,int * _gain_q8)437 int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
438   return opus_tags_get_gain(_tags,_gain_q8,"R128_TRACK_GAIN",15);
439 }
440 
op_is_jpeg(const unsigned char * _buf,size_t _buf_sz)441 static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
442   return _buf_sz>=11&&memcmp(_buf,"\xFF\xD8\xFF\xE0",4)==0
443    &&(_buf[4]<<8|_buf[5])>=16&&memcmp(_buf+6,"JFIF",5)==0;
444 }
445 
446 /*Tries to extract the width, height, bits per pixel, and palette size of a
447    JPEG.
448   On failure, simply leaves its outputs unmodified.*/
op_extract_jpeg_params(const unsigned char * _buf,size_t _buf_sz,opus_uint32 * _width,opus_uint32 * _height,opus_uint32 * _depth,opus_uint32 * _colors,int * _has_palette)449 static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz,
450  opus_uint32 *_width,opus_uint32 *_height,
451  opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
452   if(op_is_jpeg(_buf,_buf_sz)){
453     size_t offs;
454     offs=2;
455     for(;;){
456       size_t segment_len;
457       int    marker;
458       while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++;
459       while(offs<_buf_sz&&_buf[offs]==0xFF)offs++;
460       marker=_buf[offs];
461       offs++;
462       /*If we hit EOI* (end of image), or another SOI* (start of image),
463          or SOS (start of scan), then stop now.*/
464       if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break;
465       /*RST* (restart markers): skip (no segment length).*/
466       else if(marker>=0xD0&&marker<=0xD7)continue;
467       /*Read the length of the marker segment.*/
468       if(_buf_sz-offs<2)break;
469       segment_len=_buf[offs]<<8|_buf[offs+1];
470       if(segment_len<2||_buf_sz-offs<segment_len)break;
471       if(marker==0xC0||(marker>0xC0&&marker<0xD0&&(marker&3)!=0)){
472         /*Found a SOFn (start of frame) marker segment:*/
473         if(segment_len>=8){
474           *_height=_buf[offs+3]<<8|_buf[offs+4];
475           *_width=_buf[offs+5]<<8|_buf[offs+6];
476           *_depth=_buf[offs+2]*_buf[offs+7];
477           *_colors=0;
478           *_has_palette=0;
479         }
480         break;
481       }
482       /*Other markers: skip the whole marker segment.*/
483       offs+=segment_len;
484     }
485   }
486 }
487 
op_is_png(const unsigned char * _buf,size_t _buf_sz)488 static int op_is_png(const unsigned char *_buf,size_t _buf_sz){
489   return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0;
490 }
491 
492 /*Tries to extract the width, height, bits per pixel, and palette size of a
493    PNG.
494   On failure, simply leaves its outputs unmodified.*/
op_extract_png_params(const unsigned char * _buf,size_t _buf_sz,opus_uint32 * _width,opus_uint32 * _height,opus_uint32 * _depth,opus_uint32 * _colors,int * _has_palette)495 static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz,
496  opus_uint32 *_width,opus_uint32 *_height,
497  opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
498   if(op_is_png(_buf,_buf_sz)){
499     size_t offs;
500     offs=8;
501     while(_buf_sz-offs>=12){
502       ogg_uint32_t chunk_len;
503       chunk_len=op_parse_uint32be(_buf+offs);
504       if(chunk_len>_buf_sz-(offs+12))break;
505       else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){
506         int color_type;
507         *_width=op_parse_uint32be(_buf+offs+8);
508         *_height=op_parse_uint32be(_buf+offs+12);
509         color_type=_buf[offs+17];
510         if(color_type==3){
511           *_depth=24;
512           *_has_palette=1;
513         }
514         else{
515           int sample_depth;
516           sample_depth=_buf[offs+16];
517           if(color_type==0)*_depth=sample_depth;
518           else if(color_type==2)*_depth=sample_depth*3;
519           else if(color_type==4)*_depth=sample_depth*2;
520           else if(color_type==6)*_depth=sample_depth*4;
521           *_colors=0;
522           *_has_palette=0;
523           break;
524         }
525       }
526       else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){
527         *_colors=chunk_len/3;
528         break;
529       }
530       offs+=12+chunk_len;
531     }
532   }
533 }
534 
op_is_gif(const unsigned char * _buf,size_t _buf_sz)535 static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){
536   return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0);
537 }
538 
539 /*Tries to extract the width, height, bits per pixel, and palette size of a
540    GIF.
541   On failure, simply leaves its outputs unmodified.*/
op_extract_gif_params(const unsigned char * _buf,size_t _buf_sz,opus_uint32 * _width,opus_uint32 * _height,opus_uint32 * _depth,opus_uint32 * _colors,int * _has_palette)542 static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz,
543  opus_uint32 *_width,opus_uint32 *_height,
544  opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
545   if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){
546     *_width=_buf[6]|_buf[7]<<8;
547     *_height=_buf[8]|_buf[9]<<8;
548     /*libFLAC hard-codes the depth to 24.*/
549     *_depth=24;
550     *_colors=1<<((_buf[10]&7)+1);
551     *_has_palette=1;
552   }
553 }
554 
555 /*The actual implementation of opus_picture_tag_parse().
556   Unlike the public API, this function requires _pic to already be
557    initialized, modifies its contents before success is guaranteed, and assumes
558    the caller will clear it on error.*/
opus_picture_tag_parse_impl(OpusPictureTag * _pic,const char * _tag,unsigned char * _buf,size_t _buf_sz,size_t _base64_sz)559 static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag,
560  unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){
561   opus_int32   picture_type;
562   opus_uint32  mime_type_length;
563   char        *mime_type;
564   opus_uint32  description_length;
565   char        *description;
566   opus_uint32  width;
567   opus_uint32  height;
568   opus_uint32  depth;
569   opus_uint32  colors;
570   opus_uint32  data_length;
571   opus_uint32  file_width;
572   opus_uint32  file_height;
573   opus_uint32  file_depth;
574   opus_uint32  file_colors;
575   int          format;
576   int          has_palette;
577   int          colors_set;
578   size_t       i;
579   /*Decode the BASE64 data.*/
580   for(i=0;i<_base64_sz;i++){
581     opus_uint32 value;
582     int         j;
583     value=0;
584     for(j=0;j<4;j++){
585       unsigned c;
586       unsigned d;
587       c=(unsigned char)_tag[4*i+j];
588       if(c=='+')d=62;
589       else if(c=='/')d=63;
590       else if(c>='0'&&c<='9')d=52+c-'0';
591       else if(c>='a'&&c<='z')d=26+c-'a';
592       else if(c>='A'&&c<='Z')d=c-'A';
593       else if(c=='='&&3*i+j>_buf_sz)d=0;
594       else return OP_ENOTFORMAT;
595       value=value<<6|d;
596     }
597     _buf[3*i]=(unsigned char)(value>>16);
598     if(3*i+1<_buf_sz){
599       _buf[3*i+1]=(unsigned char)(value>>8);
600       if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value;
601     }
602   }
603   i=0;
604   picture_type=op_parse_uint32be(_buf+i);
605   i+=4;
606   /*Extract the MIME type.*/
607   mime_type_length=op_parse_uint32be(_buf+i);
608   i+=4;
609   if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT;
610   mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1));
611   if(mime_type==NULL)return OP_EFAULT;
612   memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length);
613   mime_type[mime_type_length]='\0';
614   _pic->mime_type=mime_type;
615   i+=mime_type_length;
616   /*Extract the description string.*/
617   description_length=op_parse_uint32be(_buf+i);
618   i+=4;
619   if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT;
620   description=
621    (char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1));
622   if(description==NULL)return OP_EFAULT;
623   memcpy(description,_buf+i,sizeof(*description)*description_length);
624   description[description_length]='\0';
625   _pic->description=description;
626   i+=description_length;
627   /*Extract the remaining fields.*/
628   width=op_parse_uint32be(_buf+i);
629   i+=4;
630   height=op_parse_uint32be(_buf+i);
631   i+=4;
632   depth=op_parse_uint32be(_buf+i);
633   i+=4;
634   colors=op_parse_uint32be(_buf+i);
635   i+=4;
636   /*If one of these is set, they all must be, but colors==0 is a valid value.*/
637   colors_set=width!=0||height!=0||depth!=0||colors!=0;
638   if((width==0||height==0||depth==0)&&colors_set)return OP_ENOTFORMAT;
639   data_length=op_parse_uint32be(_buf+i);
640   i+=4;
641   if(data_length>_buf_sz-i)return OP_ENOTFORMAT;
642   /*Trim extraneous data so we don't copy it below.*/
643   _buf_sz=i+data_length;
644   /*Attempt to determine the image format.*/
645   format=OP_PIC_FORMAT_UNKNOWN;
646   if(mime_type_length==3&&strcmp(mime_type,"-->")==0){
647     format=OP_PIC_FORMAT_URL;
648     /*Picture type 1 must be a 32x32 PNG.*/
649     if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){
650       return OP_ENOTFORMAT;
651     }
652     /*Append a terminating NUL for the convenience of our callers.*/
653     _buf[_buf_sz++]='\0';
654   }
655   else{
656     if(mime_type_length==10
657      &&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){
658       if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
659     }
660     else if(mime_type_length==9
661      &&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){
662       if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
663     }
664     else if(mime_type_length==9
665      &&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){
666       if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
667     }
668     else if(mime_type_length==0||(mime_type_length==6
669      &&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){
670       if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
671       else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
672       else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
673     }
674     file_width=file_height=file_depth=file_colors=0;
675     has_palette=-1;
676     switch(format){
677       case OP_PIC_FORMAT_JPEG:{
678         op_extract_jpeg_params(_buf+i,data_length,
679          &file_width,&file_height,&file_depth,&file_colors,&has_palette);
680       }break;
681       case OP_PIC_FORMAT_PNG:{
682         op_extract_png_params(_buf+i,data_length,
683          &file_width,&file_height,&file_depth,&file_colors,&has_palette);
684       }break;
685       case OP_PIC_FORMAT_GIF:{
686         op_extract_gif_params(_buf+i,data_length,
687          &file_width,&file_height,&file_depth,&file_colors,&has_palette);
688       }break;
689     }
690     if(has_palette>=0){
691       /*If we successfully extracted these parameters from the image, override
692          any declared values.*/
693       width=file_width;
694       height=file_height;
695       depth=file_depth;
696       colors=file_colors;
697     }
698     /*Picture type 1 must be a 32x32 PNG.*/
699     if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){
700       return OP_ENOTFORMAT;
701     }
702   }
703   /*Adjust _buf_sz instead of using data_length to capture the terminating NUL
704      for URLs.*/
705   _buf_sz-=i;
706   memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz);
707   _buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz);
708   if(_buf_sz>0&&_buf==NULL)return OP_EFAULT;
709   _pic->type=picture_type;
710   _pic->width=width;
711   _pic->height=height;
712   _pic->depth=depth;
713   _pic->colors=colors;
714   _pic->data_length=data_length;
715   _pic->data=_buf;
716   _pic->format=format;
717   return 0;
718 }
719 
opus_picture_tag_parse(OpusPictureTag * _pic,const char * _tag)720 int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){
721   OpusPictureTag  pic;
722   unsigned char  *buf;
723   size_t          base64_sz;
724   size_t          buf_sz;
725   size_t          tag_length;
726   int             ret;
727   if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23;
728   /*Figure out how much BASE64-encoded data we have.*/
729   tag_length=strlen(_tag);
730   if(tag_length&3)return OP_ENOTFORMAT;
731   base64_sz=tag_length>>2;
732   buf_sz=3*base64_sz;
733   if(buf_sz<32)return OP_ENOTFORMAT;
734   if(_tag[tag_length-1]=='=')buf_sz--;
735   if(_tag[tag_length-2]=='=')buf_sz--;
736   if(buf_sz<32)return OP_ENOTFORMAT;
737   /*Allocate an extra byte to allow appending a terminating NUL to URL data.*/
738   buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1));
739   if(buf==NULL)return OP_EFAULT;
740   opus_picture_tag_init(&pic);
741   ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz);
742   if(ret<0){
743     opus_picture_tag_clear(&pic);
744     _ogg_free(buf);
745   }
746   else *_pic=*&pic;
747   return ret;
748 }
749 
opus_picture_tag_init(OpusPictureTag * _pic)750 void opus_picture_tag_init(OpusPictureTag *_pic){
751   memset(_pic,0,sizeof(*_pic));
752 }
753 
opus_picture_tag_clear(OpusPictureTag * _pic)754 void opus_picture_tag_clear(OpusPictureTag *_pic){
755   _ogg_free(_pic->description);
756   _ogg_free(_pic->mime_type);
757   _ogg_free(_pic->data);
758 }
759