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