Bug Summary

File:build-analysis/../src/plugins/apefile/apefile.c
Warning:line 440, column 3
Value stored to 'buflen' is never read

Annotated Source Code

1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2005-2017 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17#include <xmms/xmms_xformplugin.h>
18#include <xmms/xmms_sample.h>
19#include <xmms/xmms_log.h>
20#include <xmms/xmms_medialib.h>
21
22#include <string.h>
23#include <math.h>
24
25#include <glib.h>
26
27#include "../apev2_common/apev2.c"
28
29#define APE_MIN_VERSION3950 3950
30#define APE_MAX_VERSION3990 3990
31
32#define MAC_FORMAT_FLAG_8_BIT1 1 /* is 8-bit */
33#define MAC_FORMAT_FLAG_CRC2 2 /* uses the new CRC32 error detection */
34#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL4 4 /* uint32 nPeakLevel after the header */
35#define MAC_FORMAT_FLAG_24_BIT8 8 /* is 24-bit */
36#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS16 16 /* has the number of seek elements after the peak level */
37#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER32 32 /* create the wave header on decompression (not stored) */
38
39/** These are the properties that we extract from the comments */
40static const xmms_xform_metadata_basic_mapping_t basic_mappings[] = {
41 { "Album", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM"album" },
42 { "Title", XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE"title" },
43 { "Artist", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST"artist" },
44 { "Album Artist", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ARTIST"album_artist" },
45 { "Track", XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR"tracknr" },
46 { "Disc", XMMS_MEDIALIB_ENTRY_PROPERTY_PARTOFSET"partofset" },
47 { "Year", XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR"date" },
48 { "Composer", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPOSER"composer" },
49 { "Lyricist", XMMS_MEDIALIB_ENTRY_PROPERTY_LYRICIST"lyricist" },
50 { "Conductor", XMMS_MEDIALIB_ENTRY_PROPERTY_CONDUCTOR"conductor" },
51 { "Performer", XMMS_MEDIALIB_ENTRY_PROPERTY_PERFORMER"performer" },
52 { "MixArtist", XMMS_MEDIALIB_ENTRY_PROPERTY_REMIXER"remixer" },
53 { "Arranger", XMMS_MEDIALIB_ENTRY_PROPERTY_ARRANGER"arranger" },
54 { "Producer", XMMS_MEDIALIB_ENTRY_PROPERTY_PRODUCER"producer" },
55 { "Mixer", XMMS_MEDIALIB_ENTRY_PROPERTY_MIXER"mixer" },
56 { "Grouping", XMMS_MEDIALIB_ENTRY_PROPERTY_GROUPING"grouping" },
57 { "Compilation", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION"compilation" },
58 { "Comment", XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT"comment" },
59 { "Genre", XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE"genre" },
60 { "BPM", XMMS_MEDIALIB_ENTRY_PROPERTY_BPM"bpm" },
61 { "ASIN", XMMS_MEDIALIB_ENTRY_PROPERTY_ASIN"asin" },
62 { "ISRC", XMMS_MEDIALIB_ENTRY_PROPERTY_ISRC"isrc" },
63 { "Label", XMMS_MEDIALIB_ENTRY_PROPERTY_PUBLISHER"publisher" },
64 { "Copyright", XMMS_MEDIALIB_ENTRY_PROPERTY_COPYRIGHT"copyright" },
65 { "CatalogNumber", XMMS_MEDIALIB_ENTRY_PROPERTY_CATALOGNUMBER"catalognumber" },
66 { "Barcode", XMMS_MEDIALIB_ENTRY_PROPERTY_BARCODE"barcode" },
67 { "ALBUMSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_SORT"album_sort" },
68 { "ALBUMARTISTSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ARTIST_SORT"album_artist_sort" },
69 { "ARTISTSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST_SORT"artist_sort" },
70 { "MUSICBRAINZ_TRACKID", XMMS_MEDIALIB_ENTRY_PROPERTY_TRACK_ID"track_id" },
71 { "MUSICBRAINZ_ALBUMID", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ID"album_id" },
72 { "MUSICBRAINZ_ARTISTID", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST_ID"artist_id" },
73 { "MUSICBRAINZ_ALBUMARTISTID", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION"compilation" }
74};
75
76static const xmms_xform_metadata_mapping_t mappings[] = {
77 { "Cover Art (Front)", xmms_apetag_handle_tag_coverart }
78};
79
80typedef struct {
81 guchar magic[4];
82 guint16 fileversion;
83
84 /* descriptor block, only in new file format */
85 guint16 padding;
86 guint32 descriptorlength;
87 guint32 headerlength;
88 guint32 seektablelength;
89 guint32 wavheaderlength;
90 guint32 audiodatalength;
91 guint32 audiodatalength_high;
92 guint32 wavtaillength;
93 guint8 md5[16];
94
95 /* header block, in all versions */
96 guint16 compressiontype;
97 guint16 formatflags;
98 guint32 blocksperframe;
99 guint32 finalframeblocks;
100 guint32 totalframes;
101 guint32 samplebits;
102 guint32 channels;
103 guint32 samplerate;
104
105 guint32 *seektable;
106
107 /* other useful data */
108 gint32 filesize;
109 guint32 firstframe;
110 guint32 totalsamples;
111 guint32 nextframe;
112
113 /* input buffer for reading */
114 guchar *buffer;
115 gint buffer_size;
116 gint buffer_length;
117} xmms_apefile_data_t;
118
119/*
120 * Function prototypes
121 */
122static gboolean xmms_apefile_plugin_setup (xmms_xform_plugin_t *xform_plugin);
123static gboolean xmms_apefile_init (xmms_xform_t *decoder);
124static void xmms_apefile_destroy (xmms_xform_t *decoder);
125
126static gboolean xmms_apefile_init_demuxer (xmms_xform_t *xform);
127
128static gint xmms_apefile_read (xmms_xform_t *xform, xmms_sample_t *buffer,
129 gint len, xmms_error_t *err);
130static gint64 xmms_apefile_seek (xmms_xform_t *xform, gint64 samples,
131 xmms_xform_seek_mode_t whence,
132 xmms_error_t *err);
133
134XMMS_XFORM_PLUGIN_DEFINE ("apefile", "Monkey's Audio demuxer", XMMS_VERSION,xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC
= { XMMS_PLUGIN_TYPE_XFORM, 7, "apefile", "Monkey's Audio demuxer"
, "clang-analysis", "Monkey's Audio file format demuxer", (gboolean
(*)(gpointer))xmms_apefile_plugin_setup };
135 "Monkey's Audio file format demuxer",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC
= { XMMS_PLUGIN_TYPE_XFORM, 7, "apefile", "Monkey's Audio demuxer"
, "clang-analysis", "Monkey's Audio file format demuxer", (gboolean
(*)(gpointer))xmms_apefile_plugin_setup };
136 xmms_apefile_plugin_setup)xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC
= { XMMS_PLUGIN_TYPE_XFORM, 7, "apefile", "Monkey's Audio demuxer"
, "clang-analysis", "Monkey's Audio file format demuxer", (gboolean
(*)(gpointer))xmms_apefile_plugin_setup };
;
137
138static guint16
139get_le16 (guchar *data)
140{
141 return (data[1] << 8) | data[0];
142}
143
144static void
145set_le16 (guchar *data, guint16 value)
146{
147 data[0] = value & 0xff;
148 data[1] = (value >> 8) & 0xff;
149}
150
151static guint32
152get_le32 (guchar *data)
153{
154 return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0];
155}
156
157static void
158set_le32 (guchar *data, guint32 value)
159{
160 data[0] = value & 0xff;
161 data[1] = (value >> 8) & 0xff;
162 data[2] = (value >> 16) & 0xff;
163 data[3] = (value >> 24) & 0xff;
164}
165
166/*
167 * Plugin header
168 */
169static gboolean
170xmms_apefile_plugin_setup (xmms_xform_plugin_t *xform_plugin)
171{
172 xmms_xform_methods_t methods;
173
174 XMMS_XFORM_METHODS_INIT (methods)memset (&methods, 0, sizeof (xmms_xform_methods_t));
175 methods.init = xmms_apefile_init;
176 methods.destroy = xmms_apefile_destroy;
177 methods.read = xmms_apefile_read;
178 methods.seek = xmms_apefile_seek;
179
180 xmms_xform_plugin_methods_set (xform_plugin, &methods);
181
182 xmms_xform_plugin_metadata_mapper_init (xform_plugin,
183 basic_mappings,
184 G_N_ELEMENTS (basic_mappings)(sizeof (basic_mappings) / sizeof ((basic_mappings)[0])),
185 mappings,
186 G_N_ELEMENTS (mappings)(sizeof (mappings) / sizeof ((mappings)[0])));
187
188 xmms_xform_plugin_indata_add (xform_plugin,
189 XMMS_STREAM_TYPE_MIMETYPE,
190 "audio/x-ape",
191 XMMS_STREAM_TYPE_END);
192
193 xmms_magic_add ("mpc header", "audio/x-ape", "0 string MAC ", NULL((void*)0));
194
195 return TRUE(!(0));
196}
197
198static gboolean
199xmms_apefile_init (xmms_xform_t *xform)
200{
201 xmms_apefile_data_t *data;
202 guchar decoder_config[6];
203
204 data = g_new0 (xmms_apefile_data_t, 1)((xmms_apefile_data_t *) g_malloc0_n ((1), sizeof (xmms_apefile_data_t
)))
;
205 data->seektable = NULL((void*)0);
206 data->buffer = NULL((void*)0);
207
208 xmms_xform_private_data_set (xform, data);
209
210 if (!xmms_apefile_init_demuxer (xform)) {
211 xmms_log_error ("Couldn't initialize the demuxer, please check log")g_warning ("../src/plugins/apefile/apefile.c" ":" "211" ": " "Couldn't initialize the demuxer, please check log"
)
;
212 return FALSE(0);
213 }
214
215 /* Note that this function will seek around the file to another position */
216 if (!xmms_apetag_read (xform)) {
217 XMMS_DBG ("Couldn't read tags from the file")g_debug ("../src/plugins/apefile/apefile.c" ":" "217" ": " "Couldn't read tags from the file"
)
;
218 }
219
220 xmms_xform_metadata_set_int (xform,
221 XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION"duration",
222 data->totalsamples / data->samplerate * 1000);
223
224 xmms_xform_auxdata_set_int (xform,
225 "samplebits",
226 data->samplebits);
227
228 set_le16 (decoder_config + 0, data->fileversion);
229 set_le16 (decoder_config + 2, data->compressiontype);
230 set_le16 (decoder_config + 4, data->formatflags);
231 xmms_xform_auxdata_set_bin (xform,
232 "decoder_config",
233 decoder_config,
234 sizeof (decoder_config));
235
236 xmms_xform_outdata_type_add (xform,
237 XMMS_STREAM_TYPE_MIMETYPE,
238 "audio/x-ffmpeg-ape",
239 XMMS_STREAM_TYPE_FMT_CHANNELS,
240 data->channels,
241 XMMS_STREAM_TYPE_FMT_SAMPLERATE,
242 data->samplerate,
243 XMMS_STREAM_TYPE_END);
244
245 return TRUE(!(0));
246}
247
248static gboolean
249xmms_apefile_init_demuxer (xmms_xform_t *xform)
250{
251 xmms_apefile_data_t *data;
252 guchar buffer[512];
253 xmms_error_t error;
254 guint32 seektablepos;
255 gint buflen, ret;
256
257 g_return_val_if_fail (xform, FALSE)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*)
0), ((const char*) (__func__)), "xform"); return ((0)); }; }
while (0)
;
258 data = xmms_xform_private_data_get (xform);
259 g_return_val_if_fail (data, FALSE)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "data"); return ((0)); }; }while
(0)
;
260
261 xmms_xform_metadata_get_int (xform,
262 XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE"size",
263 &data->filesize);
264
265 ret = xmms_xform_read (xform, buffer, 16, &error);
266 if (ret != 16) {
267 xmms_log_error ("Reading the file descriptor failed")g_warning ("../src/plugins/apefile/apefile.c" ":" "267" ": " "Reading the file descriptor failed"
)
;
268 return FALSE(0);
269 }
270 buflen = ret;
271
272 memcpy (data->magic, buffer, 4);
273 if (memcmp (data->magic, "MAC ", 4)) {
274 xmms_log_error ("File magic doesn't match, this is weird")g_warning ("../src/plugins/apefile/apefile.c" ":" "274" ": " "File magic doesn't match, this is weird"
)
;
275 return FALSE(0);
276 }
277
278 data->fileversion = get_le16 (buffer+4);
279 if (data->fileversion < APE_MIN_VERSION3950 || data->fileversion > APE_MAX_VERSION3990) {
280 xmms_log_error ("The APE file is of unknown version, not supported!")g_warning ("../src/plugins/apefile/apefile.c" ":" "280" ": " "The APE file is of unknown version, not supported!"
)
;
281 return FALSE(0);
282 }
283
284 XMMS_DBG ("File version number %d", data->fileversion)g_debug ("../src/plugins/apefile/apefile.c" ":" "284" ": " "File version number %d"
, data->fileversion)
;
285
286 if (data->fileversion >= 3980) {
287 gint totallength;
288 guchar *header;
289
290 /* Descriptor length includes magic bytes and file version */
291 data->padding = get_le16 (buffer + 6);
292 data->descriptorlength = get_le32 (buffer + 8);
293 data->headerlength = get_le32 (buffer + 12);
294
295 totallength = data->descriptorlength + data->headerlength;
296 if (totallength > 512) {
297 /* This doesn't fit in the buffer, maybe should make it bigger? */
298 xmms_log_error ("Internal header buffer too short, please file a bug!")g_warning ("../src/plugins/apefile/apefile.c" ":" "298" ": " "Internal header buffer too short, please file a bug!"
)
;
299 return FALSE(0);
300 }
301
302 /* read the rest of the header into buffer */
303 ret = xmms_xform_read (xform,
304 buffer + buflen,
305 totallength - buflen,
306 &error);
307 if (ret != totallength - buflen) {
308 xmms_log_error ("Reading the header data failed")g_warning ("../src/plugins/apefile/apefile.c" ":" "308" ": " "Reading the header data failed"
)
;
309 return FALSE(0);
310 }
311 buflen += ret;
312
313 /* Read rest of the descriptor data */
314 data->seektablelength = get_le32 (buffer + 16) / 4;
315 data->wavheaderlength = get_le32 (buffer + 20);
316 data->audiodatalength = get_le32 (buffer + 24);
317 data->audiodatalength_high = get_le32 (buffer + 28);
318 data->wavtaillength = get_le32 (buffer + 32);
319 memcpy (data->md5, buffer + 36, 16);
320
321 header = buffer + data->descriptorlength;
322
323 /* Read header data */
324 data->compressiontype = get_le16 (header + 0);
325 data->formatflags = get_le16 (header + 2);
326 data->blocksperframe = get_le32 (header + 4);
327 data->finalframeblocks = get_le32 (header + 8);
328 data->totalframes = get_le32 (header + 12);
329 data->samplebits = get_le16 (header + 16);
330 data->channels = get_le16 (header + 18);
331 data->samplerate = get_le32 (header + 20);
332
333 seektablepos = data->descriptorlength + data->headerlength;
334 data->firstframe = seektablepos + data->seektablelength * 4 +
335 data->wavheaderlength;
336 } else {
337 /* Header includes magic bytes and file version */
338 data->headerlength = 32;
339
340 data->compressiontype = get_le16 (buffer+6);
341 data->formatflags = get_le16 (buffer+8);
342 data->channels = get_le16 (buffer+10);
343 data->samplerate = get_le32 (buffer+12);
344
345 if (data->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL4)
346 data->headerlength += 4;
347 if (data->formatflags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS16)
348 data->headerlength += 4;
349
350 /* read the rest of the header into buffer */
351 ret = xmms_xform_read (xform,
352 buffer + buflen,
353 data->headerlength - buflen,
354 &error);
355 if (ret != data->headerlength - buflen) {
356 xmms_log_error ("Reading the header data failed")g_warning ("../src/plugins/apefile/apefile.c" ":" "356" ": " "Reading the header data failed"
)
;
357 return FALSE(0);
358 }
359 buflen += ret;
360
361 data->wavheaderlength = get_le32 (buffer+16);
362 data->wavtaillength = get_le32 (buffer+20);
363 data->totalframes = get_le32 (buffer+24);
364 data->finalframeblocks = get_le32 (buffer+28);
365
366 if (data->formatflags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS16) {
367 gint seeklenidx = data->headerlength - 4;
368
369 data->seektablelength = get_le32 (buffer + seeklenidx);
370 } else {
371 data->seektablelength = data->totalframes;
372 }
373
374 if (data->formatflags & MAC_FORMAT_FLAG_8_BIT1) {
375 data->samplebits = 8;
376 } else if (data->formatflags & MAC_FORMAT_FLAG_24_BIT8) {
377 data->samplebits = 24;
378 } else {
379 data->samplebits = 16;
380 }
381
382 if (data->fileversion >= 3950) {
383 data->blocksperframe = 73728 * 4;
384 } else if (data->fileversion >= 3900 || (data->fileversion >= 3800 &&
385 data->compressiontype == 4000)) {
386 data->blocksperframe = 73728;
387 } else {
388 data->blocksperframe = 9216;
389 }
390
391 seektablepos = data->headerlength + data->wavheaderlength;
392 data->firstframe = seektablepos + data->seektablelength * 4;
393 }
394
395 data->totalsamples = data->finalframeblocks;
396 if (data->totalframes > 1) {
397 data->totalsamples += data->blocksperframe * (data->totalframes - 1);
398 }
399
400 if (data->seektablelength > 0) {
401 guchar *tmpbuf;
402 gint seektablebytes, i;
403
404 if (data->seektablelength < data->totalframes) {
405 xmms_log_error ("Seektable length %d too small, frame count %d",g_warning ("../src/plugins/apefile/apefile.c" ":" "407" ": " "Seektable length %d too small, frame count %d"
, data->seektablelength, data->totalframes)
406 data->seektablelength,g_warning ("../src/plugins/apefile/apefile.c" ":" "407" ": " "Seektable length %d too small, frame count %d"
, data->seektablelength, data->totalframes)
407 data->totalframes)g_warning ("../src/plugins/apefile/apefile.c" ":" "407" ": " "Seektable length %d too small, frame count %d"
, data->seektablelength, data->totalframes)
;
408 /* FIXME: this is not really fatal */
409 return FALSE(0);
410 }
411
412 XMMS_DBG ("Seeking to position %d", seektablepos)g_debug ("../src/plugins/apefile/apefile.c" ":" "412" ": " "Seeking to position %d"
, seektablepos)
;
413
414 ret = xmms_xform_seek (xform,
415 seektablepos,
416 XMMS_XFORM_SEEK_SET,
417 &error);
418 if (ret != seektablepos) {
419 xmms_log_error ("Seeking to the beginning of seektable failed")g_warning ("../src/plugins/apefile/apefile.c" ":" "419" ": " "Seeking to the beginning of seektable failed"
)
;
420 /* FIXME: this is not really fatal */
421 return FALSE(0);
422 }
423
424 seektablebytes = data->seektablelength * 4;
425 tmpbuf = g_malloc (seektablebytes);
426 data->seektable = g_malloc (seektablebytes);
427
428 XMMS_DBG ("Reading %d bytes to the seek table", seektablebytes)g_debug ("../src/plugins/apefile/apefile.c" ":" "428" ": " "Reading %d bytes to the seek table"
, seektablebytes)
;
429
430 /* read the seektable into buffer */
431 ret = xmms_xform_read (xform,
432 tmpbuf,
433 seektablebytes,
434 &error);
435 if (ret != seektablebytes) {
436 xmms_log_error ("Reading the seektable failed")g_warning ("../src/plugins/apefile/apefile.c" ":" "436" ": " "Reading the seektable failed"
)
;
437 /* FIXME: this is not really fatal */
438 return FALSE(0);
439 }
440 buflen += ret;
Value stored to 'buflen' is never read
441
442 for (i = 0; i < data->seektablelength; i++) {
443 data->seektable[i] = get_le32 (tmpbuf + i * 4);
444 }
445
446 g_free (tmpbuf);
447 }
448
449 return TRUE(!(0));
450}
451
452static gint
453xmms_apefile_read (xmms_xform_t *xform, xmms_sample_t *buffer,
454 gint len, xmms_error_t *err)
455{
456 xmms_apefile_data_t *data;
457 guint size;
458
459 g_return_val_if_fail (xform, -1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*)
0), ((const char*) (__func__)), "xform"); return (-1); }; }while
(0)
;
460 data = xmms_xform_private_data_get (xform);
461 g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "data"); return (-1); }; }while
(0)
;
462
463 size = MIN (data->buffer_length, len)(((data->buffer_length) < (len)) ? (data->buffer_length
) : (len))
;
464
465 /* There is some unhandled data in the buffer */
466 if (data->buffer_length > 0) {
467 memcpy (buffer, data->buffer, size);
468 data->buffer_length -= size;
469 g_memmove (data->buffer, data->buffer + size, data->buffer_length)do { memmove ((data->buffer), (data->buffer + size), (data
->buffer_length)); } while (0)
;
470
471 /* the buffer is only needed in special cases, free when not used
472 * (it can be over half megabytes big so we don't want to keep it
473 * uselessly here) */
474 if (data->buffer_length == 0) {
475 g_free (data->buffer);
476 data->buffer = NULL((void*)0);
477 data->buffer_size = 0;
478 }
479
480 return size;
481 }
482
483 while (size == 0) {
484 gint framepos, framelength, framealign, nblocks, ret;
485
486 /* this is the beginning of a new frame */
487 xmms_xform_auxdata_barrier (xform);
488
489 if (data->nextframe >= data->totalframes) {
490 /* EOF reached, no more frames */
491 return 0;
492 }
493
494 /* look up the position of next frame */
495 framepos = data->seektable[data->nextframe];
496
497 /* last frame needs a special handling since it differs */
498 if (data->nextframe < (data->totalframes - 1)) {
499 framelength = data->seektable[data->nextframe+1] -
500 data->seektable[data->nextframe];
501 nblocks = data->blocksperframe;
502 } else {
503 if (data->filesize > data->seektable[data->nextframe]) {
504 framelength = data->filesize - data->seektable[data->nextframe];
505 } else {
506 /* unknown or invalid file size, just read a lot */
507 framelength = data->finalframeblocks * 4;
508 }
509 nblocks = data->finalframeblocks;
510 }
511
512 /* the data is aligned in 32-bit words, so need to fix alignment */
513 framealign = (data->seektable[data->nextframe] -
514 data->seektable[0]) & 3;
515 framepos -= framealign;
516 framelength += framealign;
517
518 ret = xmms_xform_seek (xform,
519 framepos,
520 XMMS_XFORM_SEEK_SET,
521 err);
522 if (ret != framepos) {
523 xmms_log_error ("Seeking to the beginning of next frame failed")g_warning ("../src/plugins/apefile/apefile.c" ":" "523" ": " "Seeking to the beginning of next frame failed"
)
;
524 /* FIXME: this is not really fatal */
525 return -1;
526 }
527
528 /* the required data doesn't fit into the buffer, allocate new input buffer
529 * 8 bytes are required for the libavcodec metadata passing */
530 if ((framelength + 8) > len) {
531 data->buffer = g_realloc (data->buffer, framelength + 8 - len);
532 data->buffer_size = framelength + 8 - len;
533 }
534
535 /* calculate how much data will go directly into the buffer */
536 size = MIN (framelength, len - 8)(((framelength) < (len - 8)) ? (framelength) : (len - 8));
537
538 /* read the actual data */
539 ret = xmms_xform_read (xform, buffer + 8, size, err);
540 if (ret < 0) {
541 xmms_log_error ("Reading the frame data failed")g_warning ("../src/plugins/apefile/apefile.c" ":" "541" ": " "Reading the frame data failed"
)
;
542 return ret;
543 }
544
545 /* set frame metadata required by avcodec decoder */
546 set_le32 (buffer + 0, nblocks);
547 set_le32 (buffer + 4, framealign);
548 size = size + 8;
549
550 if ((framelength + 8) > len) {
551 /* read the data that didn't fit the original buffer */
552 ret = xmms_xform_read (xform,
553 data->buffer,
554 framelength + 8 - len,
555 err);
556 if (ret < 0) {
557 xmms_log_error ("Reading the frame data failed")g_warning ("../src/plugins/apefile/apefile.c" ":" "557" ": " "Reading the frame data failed"
)
;
558 return ret;
559 }
560
561 data->buffer_length = ret;
562 }
563
564 data->nextframe++;
565 }
566
567 return size;
568}
569
570static gint64
571xmms_apefile_seek (xmms_xform_t *xform, gint64 samples,
572 xmms_xform_seek_mode_t whence, xmms_error_t *err)
573{
574 xmms_apefile_data_t *data;
575
576 g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1)do{ if (whence == XMMS_XFORM_SEEK_SET) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "whence == XMMS_XFORM_SEEK_SET"
); return (-1); }; }while (0)
;
577 g_return_val_if_fail (xform, -1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*)
0), ((const char*) (__func__)), "xform"); return (-1); }; }while
(0)
;
578
579 data = xmms_xform_private_data_get (xform);
580 g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "data"); return (-1); }; }while
(0)
;
581 g_return_val_if_fail (data->seektable, -1)do{ if (data->seektable) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "data->seektable"
); return (-1); }; }while (0)
;
582
583 if (samples < 0 || samples > data->totalsamples) {
584 /* trying to seek outside file bounds */
585 xmms_error_set (err, XMMS_ERROR_GENERIC,
586 "Seek index out of bounds, only seek within the file");
587 return -1;
588 }
589
590 /* update the position of the next frame */
591 data->nextframe = samples / data->blocksperframe;
592
593 /* free possibly temporary buffer, it is useless now */
594 g_free (data->buffer);
595 data->buffer = NULL((void*)0);
596 data->buffer_length = 0;
597
598 return (data->nextframe * data->blocksperframe);
599}
600
601void
602xmms_apefile_destroy (xmms_xform_t *xform)
603{
604 xmms_apefile_data_t *data;
605
606 g_return_if_fail (xform)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*)
0), ((const char*) (__func__)), "xform"); return; }; }while (
0)
;
607 data = xmms_xform_private_data_get (xform);
608 g_return_if_fail (data)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0
), ((const char*) (__func__)), "data"); return; }; }while (0)
;
609
610 g_free (data->seektable);
611 g_free (data->buffer);
612 g_free (data);
613}