annotate src/libid3tag-0.15.1b/frame.c @ 127:7867fa7e1b6b

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