info.c 25 KB

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