annotate src/libid3tag-0.15.1b/frame.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
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 }