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 }
|