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