annotate src/libid3tag-0.15.1b/frame.c @ 23:619f715526df sv_v2.1

Update Vamp plugin SDK to 2.5
author Chris Cannam
date Thu, 09 May 2013 10:52:46 +0100
parents c7265573341e
children
rev   line source
Chris@0 1 /*
Chris@0 2 * libid3tag - ID3 tag manipulation library
Chris@0 3 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
Chris@0 4 *
Chris@0 5 * This program is free software; you can redistribute it and/or modify
Chris@0 6 * it under the terms of the GNU General Public License as published by
Chris@0 7 * the Free Software Foundation; either version 2 of the License, or
Chris@0 8 * (at your option) any later version.
Chris@0 9 *
Chris@0 10 * This program is distributed in the hope that it will be useful,
Chris@0 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 13 * GNU General Public License for more details.
Chris@0 14 *
Chris@0 15 * You should have received a copy of the GNU General Public License
Chris@0 16 * along with this program; if not, write to the Free Software
Chris@0 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Chris@0 18 *
Chris@0 19 * $Id: frame.c,v 1.15 2004/01/23 09:41:32 rob Exp $
Chris@0 20 */
Chris@0 21
Chris@0 22 # ifdef HAVE_CONFIG_H
Chris@0 23 # include "config.h"
Chris@0 24 # endif
Chris@0 25
Chris@0 26 # include "global.h"
Chris@0 27
Chris@0 28 # include <stdlib.h>
Chris@0 29 # include <string.h>
Chris@0 30
Chris@0 31 # ifdef HAVE_ASSERT_H
Chris@0 32 # include <assert.h>
Chris@0 33 # endif
Chris@0 34
Chris@0 35 # include "id3tag.h"
Chris@0 36 # include "frame.h"
Chris@0 37 # include "frametype.h"
Chris@0 38 # include "compat.h"
Chris@0 39 # include "field.h"
Chris@0 40 # include "render.h"
Chris@0 41 # include "parse.h"
Chris@0 42 # include "util.h"
Chris@0 43
Chris@0 44 static
Chris@0 45 int valid_idchar(char c)
Chris@0 46 {
Chris@0 47 return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
Chris@0 48 }
Chris@0 49
Chris@0 50 /*
Chris@0 51 * NAME: frame->validid()
Chris@0 52 * DESCRIPTION: return true if the parameter string is a legal frame ID
Chris@0 53 */
Chris@0 54 int id3_frame_validid(char const *id)
Chris@0 55 {
Chris@0 56 return id &&
Chris@0 57 valid_idchar(id[0]) &&
Chris@0 58 valid_idchar(id[1]) &&
Chris@0 59 valid_idchar(id[2]) &&
Chris@0 60 valid_idchar(id[3]);
Chris@0 61 }
Chris@0 62
Chris@0 63 /*
Chris@0 64 * NAME: frame->new()
Chris@0 65 * DESCRIPTION: allocate and return a new frame
Chris@0 66 */
Chris@0 67 struct id3_frame *id3_frame_new(char const *id)
Chris@0 68 {
Chris@0 69 struct id3_frametype const *frametype;
Chris@0 70 struct id3_frame *frame;
Chris@0 71 unsigned int i;
Chris@0 72
Chris@0 73 if (!id3_frame_validid(id))
Chris@0 74 return 0;
Chris@0 75
Chris@0 76 frametype = id3_frametype_lookup(id, 4);
Chris@0 77 if (frametype == 0) {
Chris@0 78 switch (id[0]) {
Chris@0 79 case 'T':
Chris@0 80 frametype = &id3_frametype_text;
Chris@0 81 break;
Chris@0 82
Chris@0 83 case 'W':
Chris@0 84 frametype = &id3_frametype_url;
Chris@0 85 break;
Chris@0 86
Chris@0 87 case 'X':
Chris@0 88 case 'Y':
Chris@0 89 case 'Z':
Chris@0 90 frametype = &id3_frametype_experimental;
Chris@0 91 break;
Chris@0 92
Chris@0 93 default:
Chris@0 94 frametype = &id3_frametype_unknown;
Chris@0 95 if (id3_compat_lookup(id, 4))
Chris@0 96 frametype = &id3_frametype_obsolete;
Chris@0 97 break;
Chris@0 98 }
Chris@0 99 }
Chris@0 100
Chris@0 101 frame = malloc(sizeof(*frame) + frametype->nfields * sizeof(*frame->fields));
Chris@0 102 if (frame) {
Chris@0 103 frame->id[0] = id[0];
Chris@0 104 frame->id[1] = id[1];
Chris@0 105 frame->id[2] = id[2];
Chris@0 106 frame->id[3] = id[3];
Chris@0 107 frame->id[4] = 0;
Chris@0 108
Chris@0 109 frame->description = frametype->description;
Chris@0 110 frame->refcount = 0;
Chris@0 111 frame->flags = frametype->defaultflags;
Chris@0 112 frame->group_id = 0;
Chris@0 113 frame->encryption_method = 0;
Chris@0 114 frame->encoded = 0;
Chris@0 115 frame->encoded_length = 0;
Chris@0 116 frame->decoded_length = 0;
Chris@0 117 frame->nfields = frametype->nfields;
Chris@0 118 frame->fields = (union id3_field *) &frame[1];
Chris@0 119
Chris@0 120 for (i = 0; i < frame->nfields; ++i)
Chris@0 121 id3_field_init(&frame->fields[i], frametype->fields[i]);
Chris@0 122 }
Chris@0 123
Chris@0 124 return frame;
Chris@0 125 }
Chris@0 126
Chris@0 127 void id3_frame_delete(struct id3_frame *frame)
Chris@0 128 {
Chris@0 129 assert(frame);
Chris@0 130
Chris@0 131 if (frame->refcount == 0) {
Chris@0 132 unsigned int i;
Chris@0 133
Chris@0 134 for (i = 0; i < frame->nfields; ++i)
Chris@0 135 id3_field_finish(&frame->fields[i]);
Chris@0 136
Chris@0 137 if (frame->encoded)
Chris@0 138 free(frame->encoded);
Chris@0 139
Chris@0 140 free(frame);
Chris@0 141 }
Chris@0 142 }
Chris@0 143
Chris@0 144 /*
Chris@0 145 * NAME: frame->addref()
Chris@0 146 * DESCRIPTION: add an external reference to a frame
Chris@0 147 */
Chris@0 148 void id3_frame_addref(struct id3_frame *frame)
Chris@0 149 {
Chris@0 150 assert(frame);
Chris@0 151
Chris@0 152 ++frame->refcount;
Chris@0 153 }
Chris@0 154
Chris@0 155 /*
Chris@0 156 * NAME: frame->delref()
Chris@0 157 * DESCRIPTION: remove an external reference to a frame
Chris@0 158 */
Chris@0 159 void id3_frame_delref(struct id3_frame *frame)
Chris@0 160 {
Chris@0 161 assert(frame && frame->refcount > 0);
Chris@0 162
Chris@0 163 --frame->refcount;
Chris@0 164 }
Chris@0 165
Chris@0 166 /*
Chris@0 167 * NAME: frame->field()
Chris@0 168 * DESCRIPTION: return a pointer to a field in a frame
Chris@0 169 */
Chris@0 170 union id3_field *id3_frame_field(struct id3_frame const *frame,
Chris@0 171 unsigned int index)
Chris@0 172 {
Chris@0 173 assert(frame);
Chris@0 174
Chris@0 175 return (index < frame->nfields) ? &frame->fields[index] : 0;
Chris@0 176 }
Chris@0 177
Chris@0 178 static
Chris@0 179 struct id3_frame *obsolete(char const *id, id3_byte_t const *data,
Chris@0 180 id3_length_t length)
Chris@0 181 {
Chris@0 182 struct id3_frame *frame;
Chris@0 183
Chris@0 184 frame = id3_frame_new(ID3_FRAME_OBSOLETE);
Chris@0 185 if (frame) {
Chris@0 186 if (id3_field_setframeid(&frame->fields[0], id) == -1 ||
Chris@0 187 id3_field_setbinarydata(&frame->fields[1], data, length) == -1)
Chris@0 188 goto fail;
Chris@0 189 }
Chris@0 190
Chris@0 191 if (0) {
Chris@0 192 fail:
Chris@0 193 if (frame) {
Chris@0 194 id3_frame_delete(frame);
Chris@0 195 frame = 0;
Chris@0 196 }
Chris@0 197 }
Chris@0 198
Chris@0 199 return frame;
Chris@0 200 }
Chris@0 201
Chris@0 202 static
Chris@0 203 struct id3_frame *unparseable(char const *id, id3_byte_t const **ptr,
Chris@0 204 id3_length_t length, int flags,
Chris@0 205 int group_id, int encryption_method,
Chris@0 206 id3_length_t decoded_length)
Chris@0 207 {
Chris@0 208 struct id3_frame *frame = 0;
Chris@0 209 id3_byte_t *mem;
Chris@0 210
Chris@0 211 mem = malloc(length ? length : 1);
Chris@0 212 if (mem == 0)
Chris@0 213 goto fail;
Chris@0 214
Chris@0 215 frame = id3_frame_new(id);
Chris@0 216 if (frame == 0)
Chris@0 217 free(mem);
Chris@0 218 else {
Chris@0 219 memcpy(mem, *ptr, length);
Chris@0 220
Chris@0 221 frame->flags = flags;
Chris@0 222 frame->group_id = group_id;
Chris@0 223 frame->encryption_method = encryption_method;
Chris@0 224 frame->encoded = mem;
Chris@0 225 frame->encoded_length = length;
Chris@0 226 frame->decoded_length = decoded_length;
Chris@0 227 }
Chris@0 228
Chris@0 229 if (0) {
Chris@0 230 fail:
Chris@0 231 ;
Chris@0 232 }
Chris@0 233
Chris@0 234 *ptr += length;
Chris@0 235
Chris@0 236 return frame;
Chris@0 237 }
Chris@0 238
Chris@0 239 static
Chris@0 240 int parse_data(struct id3_frame *frame,
Chris@0 241 id3_byte_t const *data, id3_length_t length)
Chris@0 242 {
Chris@0 243 enum id3_field_textencoding encoding;
Chris@0 244 id3_byte_t const *end;
Chris@0 245 unsigned int i;
Chris@0 246
Chris@0 247 encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
Chris@0 248
Chris@0 249 end = data + length;
Chris@0 250
Chris@0 251 for (i = 0; i < frame->nfields; ++i) {
Chris@0 252 if (id3_field_parse(&frame->fields[i], &data, end - data, &encoding) == -1)
Chris@0 253 return -1;
Chris@0 254 }
Chris@0 255
Chris@0 256 return 0;
Chris@0 257 }
Chris@0 258
Chris@0 259 /*
Chris@0 260 * NAME: frame->parse()
Chris@0 261 * DESCRIPTION: parse raw frame data according to the specified ID3 tag version
Chris@0 262 */
Chris@0 263 struct id3_frame *id3_frame_parse(id3_byte_t const **ptr, id3_length_t length,
Chris@0 264 unsigned int version)
Chris@0 265 {
Chris@0 266 struct id3_frame *frame = 0;
Chris@0 267 id3_byte_t const *id, *end, *data;
Chris@0 268 id3_length_t size, decoded_length = 0;
Chris@0 269 int flags = 0, group_id = 0, encryption_method = 0;
Chris@0 270 struct id3_compat const *compat = 0;
Chris@0 271 id3_byte_t *mem = 0;
Chris@0 272 char xid[4];
Chris@0 273
Chris@0 274 id = *ptr;
Chris@0 275 end = *ptr + length;
Chris@0 276
Chris@0 277 if (ID3_TAG_VERSION_MAJOR(version) < 4) {
Chris@0 278 switch (ID3_TAG_VERSION_MAJOR(version)) {
Chris@0 279 case 2:
Chris@0 280 if (length < 6)
Chris@0 281 goto fail;
Chris@0 282
Chris@0 283 compat = id3_compat_lookup(id, 3);
Chris@0 284
Chris@0 285 *ptr += 3;
Chris@0 286 size = id3_parse_uint(ptr, 3);
Chris@0 287
Chris@0 288 if (size > end - *ptr)
Chris@0 289 goto fail;
Chris@0 290
Chris@0 291 end = *ptr + size;
Chris@0 292
Chris@0 293 break;
Chris@0 294
Chris@0 295 case 3:
Chris@0 296 if (length < 10)
Chris@0 297 goto fail;
Chris@0 298
Chris@0 299 compat = id3_compat_lookup(id, 4);
Chris@0 300
Chris@0 301 *ptr += 4;
Chris@0 302 size = id3_parse_uint(ptr, 4);
Chris@0 303 flags = id3_parse_uint(ptr, 2);
Chris@0 304
Chris@0 305 if (size > end - *ptr)
Chris@0 306 goto fail;
Chris@0 307
Chris@0 308 end = *ptr + size;
Chris@0 309
Chris@0 310 if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~0x00e0)) {
Chris@0 311 frame = unparseable(id, ptr, end - *ptr, 0, 0, 0, 0);
Chris@0 312 goto done;
Chris@0 313 }
Chris@0 314
Chris@0 315 flags =
Chris@0 316 ((flags >> 1) & ID3_FRAME_FLAG_STATUSFLAGS) |
Chris@0 317 ((flags >> 4) & (ID3_FRAME_FLAG_COMPRESSION |
Chris@0 318 ID3_FRAME_FLAG_ENCRYPTION)) |
Chris@0 319 ((flags << 1) & ID3_FRAME_FLAG_GROUPINGIDENTITY);
Chris@0 320
Chris@0 321 if (flags & ID3_FRAME_FLAG_COMPRESSION) {
Chris@0 322 if (end - *ptr < 4)
Chris@0 323 goto fail;
Chris@0 324
Chris@0 325 decoded_length = id3_parse_uint(ptr, 4);
Chris@0 326 }
Chris@0 327
Chris@0 328 if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
Chris@0 329 if (end - *ptr < 1)
Chris@0 330 goto fail;
Chris@0 331
Chris@0 332 encryption_method = id3_parse_uint(ptr, 1);
Chris@0 333 }
Chris@0 334
Chris@0 335 if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {
Chris@0 336 if (end - *ptr < 1)
Chris@0 337 goto fail;
Chris@0 338
Chris@0 339 group_id = id3_parse_uint(ptr, 1);
Chris@0 340 }
Chris@0 341
Chris@0 342 break;
Chris@0 343
Chris@0 344 default:
Chris@0 345 goto fail;
Chris@0 346 }
Chris@0 347
Chris@0 348 /* canonicalize frame ID for ID3v2.4 */
Chris@0 349
Chris@0 350 if (compat && compat->equiv)
Chris@0 351 id = compat->equiv;
Chris@0 352 else if (ID3_TAG_VERSION_MAJOR(version) == 2) {
Chris@0 353 xid[0] = 'Y';
Chris@0 354 xid[1] = id[0];
Chris@0 355 xid[2] = id[1];
Chris@0 356 xid[3] = id[2];
Chris@0 357
Chris@0 358 id = xid;
Chris@0 359
Chris@0 360 flags |=
Chris@0 361 ID3_FRAME_FLAG_TAGALTERPRESERVATION |
Chris@0 362 ID3_FRAME_FLAG_FILEALTERPRESERVATION;
Chris@0 363 }
Chris@0 364 }
Chris@0 365 else { /* ID3v2.4 */
Chris@0 366 if (length < 10)
Chris@0 367 goto fail;
Chris@0 368
Chris@0 369 *ptr += 4;
Chris@0 370 size = id3_parse_syncsafe(ptr, 4);
Chris@0 371 flags = id3_parse_uint(ptr, 2);
Chris@0 372
Chris@0 373 if (size > end - *ptr)
Chris@0 374 goto fail;
Chris@0 375
Chris@0 376 end = *ptr + size;
Chris@0 377
Chris@0 378 if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) {
Chris@0 379 frame = unparseable(id, ptr, end - *ptr, flags, 0, 0, 0);
Chris@0 380 goto done;
Chris@0 381 }
Chris@0 382
Chris@0 383 if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {
Chris@0 384 if (end - *ptr < 1)
Chris@0 385 goto fail;
Chris@0 386
Chris@0 387 group_id = id3_parse_uint(ptr, 1);
Chris@0 388 }
Chris@0 389
Chris@0 390 if ((flags & ID3_FRAME_FLAG_COMPRESSION) &&
Chris@0 391 !(flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR))
Chris@0 392 goto fail;
Chris@0 393
Chris@0 394 if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
Chris@0 395 if (end - *ptr < 1)
Chris@0 396 goto fail;
Chris@0 397
Chris@0 398 encryption_method = id3_parse_uint(ptr, 1);
Chris@0 399 }
Chris@0 400
Chris@0 401 if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {
Chris@0 402 if (end - *ptr < 4)
Chris@0 403 goto fail;
Chris@0 404
Chris@0 405 decoded_length = id3_parse_syncsafe(ptr, 4);
Chris@0 406 }
Chris@0 407 }
Chris@0 408
Chris@0 409 data = *ptr;
Chris@0 410 *ptr = end;
Chris@0 411
Chris@0 412 /* undo frame encodings */
Chris@0 413
Chris@0 414 if ((flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) && end - data > 0) {
Chris@0 415 mem = malloc(end - data);
Chris@0 416 if (mem == 0)
Chris@0 417 goto fail;
Chris@0 418
Chris@0 419 memcpy(mem, data, end - data);
Chris@0 420
Chris@0 421 end = mem + id3_util_deunsynchronise(mem, end - data);
Chris@0 422 data = mem;
Chris@0 423 }
Chris@0 424
Chris@0 425 if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
Chris@0 426 frame = unparseable(id, &data, end - data, flags,
Chris@0 427 group_id, encryption_method, decoded_length);
Chris@0 428 goto done;
Chris@0 429 }
Chris@0 430
Chris@0 431 if (flags & ID3_FRAME_FLAG_COMPRESSION) {
Chris@0 432 id3_byte_t *decomp;
Chris@0 433
Chris@0 434 decomp = id3_util_decompress(data, end - data, decoded_length);
Chris@0 435 if (decomp == 0)
Chris@0 436 goto fail;
Chris@0 437
Chris@0 438 if (mem)
Chris@0 439 free(mem);
Chris@0 440
Chris@0 441 data = mem = decomp;
Chris@0 442 end = data + decoded_length;
Chris@0 443 }
Chris@0 444
Chris@0 445 /* check for obsolescence */
Chris@0 446
Chris@0 447 if (compat && !compat->equiv) {
Chris@0 448 frame = obsolete(id, data, end - data);
Chris@0 449 goto done;
Chris@0 450 }
Chris@0 451
Chris@0 452 /* generate the internal frame structure */
Chris@0 453
Chris@0 454 frame = id3_frame_new(id);
Chris@0 455 if (frame) {
Chris@0 456 frame->flags = flags;
Chris@0 457 frame->group_id = group_id;
Chris@0 458
Chris@0 459 if (compat && compat->translate) {
Chris@0 460 if (compat->translate(frame, compat->id, data, end - data) == -1)
Chris@0 461 goto fail;
Chris@0 462 }
Chris@0 463 else {
Chris@0 464 if (parse_data(frame, data, end - data) == -1)
Chris@0 465 goto fail;
Chris@0 466 }
Chris@0 467 }
Chris@0 468
Chris@0 469 if (0) {
Chris@0 470 fail:
Chris@0 471 if (frame) {
Chris@0 472 id3_frame_delete(frame);
Chris@0 473 frame = 0;
Chris@0 474 }
Chris@0 475 }
Chris@0 476
Chris@0 477 done:
Chris@0 478 if (mem)
Chris@0 479 free(mem);
Chris@0 480
Chris@0 481 return frame;
Chris@0 482 }
Chris@0 483
Chris@0 484 static
Chris@0 485 id3_length_t render_data(id3_byte_t **ptr,
Chris@0 486 union id3_field *fields, unsigned int length)
Chris@0 487 {
Chris@0 488 id3_length_t size = 0;
Chris@0 489 enum id3_field_textencoding encoding;
Chris@0 490 unsigned int i;
Chris@0 491
Chris@0 492 encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
Chris@0 493
Chris@0 494 for (i = 0; i < length; ++i)
Chris@0 495 size += id3_field_render(&fields[i], ptr, &encoding, i < length - 1);
Chris@0 496
Chris@0 497 return size;
Chris@0 498 }
Chris@0 499
Chris@0 500 /*
Chris@0 501 * NAME: frame->render()
Chris@0 502 * DESCRIPTION: render a single, complete frame
Chris@0 503 */
Chris@0 504 id3_length_t id3_frame_render(struct id3_frame const *frame,
Chris@0 505 id3_byte_t **ptr, int options)
Chris@0 506 {
Chris@0 507 id3_length_t size = 0, decoded_length, datalen;
Chris@0 508 id3_byte_t *size_ptr = 0, *flags_ptr = 0, *data = 0;
Chris@0 509 int flags;
Chris@0 510
Chris@0 511 assert(frame);
Chris@0 512
Chris@0 513 if ((frame->flags & ID3_FRAME_FLAG_TAGALTERPRESERVATION) ||
Chris@0 514 ((options & ID3_TAG_OPTION_FILEALTERED) &&
Chris@0 515 (frame->flags & ID3_FRAME_FLAG_FILEALTERPRESERVATION)))
Chris@0 516 return 0;
Chris@0 517
Chris@0 518 /* a frame must be at least 1 byte big, excluding the header */
Chris@0 519
Chris@0 520 decoded_length = render_data(0, frame->fields, frame->nfields);
Chris@0 521 if (decoded_length == 0 && frame->encoded == 0)
Chris@0 522 return 0;
Chris@0 523
Chris@0 524 /* header */
Chris@0 525
Chris@0 526 size += id3_render_immediate(ptr, frame->id, 4);
Chris@0 527
Chris@0 528 if (ptr)
Chris@0 529 size_ptr = *ptr;
Chris@0 530
Chris@0 531 size += id3_render_syncsafe(ptr, 0, 4);
Chris@0 532
Chris@0 533 if (ptr)
Chris@0 534 flags_ptr = *ptr;
Chris@0 535
Chris@0 536 flags = frame->flags;
Chris@0 537
Chris@0 538 size += id3_render_int(ptr, flags, 2);
Chris@0 539
Chris@0 540 if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) {
Chris@0 541 size += id3_render_binary(ptr, frame->encoded, frame->encoded_length);
Chris@0 542 if (size_ptr)
Chris@0 543 id3_render_syncsafe(&size_ptr, size - 10, 4);
Chris@0 544
Chris@0 545 return size;
Chris@0 546 }
Chris@0 547
Chris@0 548 flags &= ID3_FRAME_FLAG_KNOWNFLAGS;
Chris@0 549
Chris@0 550 flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;
Chris@0 551 if (options & ID3_TAG_OPTION_UNSYNCHRONISATION)
Chris@0 552 flags |= ID3_FRAME_FLAG_UNSYNCHRONISATION;
Chris@0 553
Chris@0 554 if (!(flags & ID3_FRAME_FLAG_ENCRYPTION)) {
Chris@0 555 flags &= ~ID3_FRAME_FLAG_COMPRESSION;
Chris@0 556 if (options & ID3_TAG_OPTION_COMPRESSION)
Chris@0 557 flags |= ID3_FRAME_FLAG_COMPRESSION | ID3_FRAME_FLAG_DATALENGTHINDICATOR;
Chris@0 558 }
Chris@0 559
Chris@0 560 if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY)
Chris@0 561 size += id3_render_int(ptr, frame->group_id, 1);
Chris@0 562 if (flags & ID3_FRAME_FLAG_ENCRYPTION)
Chris@0 563 size += id3_render_int(ptr, frame->encryption_method, 1);
Chris@0 564 if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {
Chris@0 565 if (flags & ID3_FRAME_FLAG_ENCRYPTION)
Chris@0 566 decoded_length = frame->decoded_length;
Chris@0 567 size += id3_render_syncsafe(ptr, decoded_length, 4);
Chris@0 568 }
Chris@0 569
Chris@0 570 if (ptr)
Chris@0 571 data = *ptr;
Chris@0 572
Chris@0 573 if (flags & ID3_FRAME_FLAG_ENCRYPTION)
Chris@0 574 datalen = id3_render_binary(ptr, frame->encoded, frame->encoded_length);
Chris@0 575 else {
Chris@0 576 if (ptr == 0)
Chris@0 577 datalen = decoded_length;
Chris@0 578 else {
Chris@0 579 datalen = render_data(ptr, frame->fields, frame->nfields);
Chris@0 580
Chris@0 581 if (flags & ID3_FRAME_FLAG_COMPRESSION) {
Chris@0 582 id3_byte_t *comp;
Chris@0 583 id3_length_t complen;
Chris@0 584
Chris@0 585 comp = id3_util_compress(data, datalen, &complen);
Chris@0 586 if (comp == 0)
Chris@0 587 flags &= ~ID3_FRAME_FLAG_COMPRESSION;
Chris@0 588 else {
Chris@0 589 *ptr = data;
Chris@0 590 datalen = id3_render_binary(ptr, comp, complen);
Chris@0 591
Chris@0 592 free(comp);
Chris@0 593 }
Chris@0 594 }
Chris@0 595 }
Chris@0 596 }
Chris@0 597
Chris@0 598 /* unsynchronisation */
Chris@0 599
Chris@0 600 if (flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) {
Chris@0 601 if (data == 0)
Chris@0 602 datalen *= 2;
Chris@0 603 else {
Chris@0 604 id3_length_t newlen;
Chris@0 605
Chris@0 606 newlen = id3_util_unsynchronise(data, datalen);
Chris@0 607 if (newlen == datalen)
Chris@0 608 flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;
Chris@0 609 else {
Chris@0 610 *ptr += newlen - datalen;
Chris@0 611 datalen = newlen;
Chris@0 612 }
Chris@0 613 }
Chris@0 614 }
Chris@0 615
Chris@0 616 size += datalen;
Chris@0 617
Chris@0 618 /* patch size and flags */
Chris@0 619
Chris@0 620 if (size_ptr)
Chris@0 621 id3_render_syncsafe(&size_ptr, size - 10, 4);
Chris@0 622 if (flags_ptr)
Chris@0 623 id3_render_int(&flags_ptr, flags, 2);
Chris@0 624
Chris@0 625 return size;
Chris@0 626 }