File: | build-analysis/../src/plugins/wavpack/wavpack.c |
Warning: | line 325, column 25 The left operand of '/' is a garbage value |
1 | /* XMMS2 - X Music Multiplexer System | |||
2 | * Copyright (C) 2006-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 | /** | |||
18 | * @file WavPack decoder | |||
19 | * @url http://wavpack.com | |||
20 | */ | |||
21 | ||||
22 | #include <xmms/xmms_xformplugin.h> | |||
23 | #include <xmms/xmms_log.h> | |||
24 | #include <xmms/xmms_medialib.h> | |||
25 | ||||
26 | #include <glib.h> | |||
27 | #include <math.h> | |||
28 | #include <stdio.h> | |||
29 | #include <stdlib.h> | |||
30 | #include <string.h> | |||
31 | #include <wavpack/wavpack.h> | |||
32 | ||||
33 | #include "../apev2_common/apev2.c" | |||
34 | ||||
35 | typedef struct xmms_wavpack_data_St { | |||
36 | WavpackContext *ctx; | |||
37 | WavpackStreamReader reader; | |||
38 | ||||
39 | gint channels; | |||
40 | gint bits_per_sample; | |||
41 | gint num_samples; | |||
42 | ||||
43 | guint8 pushback_byte; | |||
44 | gboolean pushback_set; | |||
45 | ||||
46 | xmms_samples32_t *buf; | |||
47 | gint buf_mono_samples; | |||
48 | } xmms_wavpack_data_t; | |||
49 | ||||
50 | /** These are the properties that we extract from the comments */ | |||
51 | static const xmms_xform_metadata_basic_mapping_t basic_mappings[] = { | |||
52 | { "Album", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM"album" }, | |||
53 | { "Title", XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE"title" }, | |||
54 | { "Artist", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST"artist" }, | |||
55 | { "Album Artist", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ARTIST"album_artist" }, | |||
56 | { "Track", XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR"tracknr" }, | |||
57 | { "Disc", XMMS_MEDIALIB_ENTRY_PROPERTY_PARTOFSET"partofset" }, | |||
58 | { "Year", XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR"date" }, | |||
59 | { "Composer", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPOSER"composer" }, | |||
60 | { "Lyricist", XMMS_MEDIALIB_ENTRY_PROPERTY_LYRICIST"lyricist" }, | |||
61 | { "Conductor", XMMS_MEDIALIB_ENTRY_PROPERTY_CONDUCTOR"conductor" }, | |||
62 | { "Performer", XMMS_MEDIALIB_ENTRY_PROPERTY_PERFORMER"performer" }, | |||
63 | { "MixArtist", XMMS_MEDIALIB_ENTRY_PROPERTY_REMIXER"remixer" }, | |||
64 | { "Arranger", XMMS_MEDIALIB_ENTRY_PROPERTY_ARRANGER"arranger" }, | |||
65 | { "Producer", XMMS_MEDIALIB_ENTRY_PROPERTY_PRODUCER"producer" }, | |||
66 | { "Mixer", XMMS_MEDIALIB_ENTRY_PROPERTY_MIXER"mixer" }, | |||
67 | { "Grouping", XMMS_MEDIALIB_ENTRY_PROPERTY_GROUPING"grouping" }, | |||
68 | { "Compilation", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION"compilation" }, | |||
69 | { "Comment", XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT"comment" }, | |||
70 | { "Genre", XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE"genre" }, | |||
71 | { "BPM", XMMS_MEDIALIB_ENTRY_PROPERTY_BPM"bpm" }, | |||
72 | { "ASIN", XMMS_MEDIALIB_ENTRY_PROPERTY_ASIN"asin" }, | |||
73 | { "ISRC", XMMS_MEDIALIB_ENTRY_PROPERTY_ISRC"isrc" }, | |||
74 | { "Label", XMMS_MEDIALIB_ENTRY_PROPERTY_PUBLISHER"publisher" }, | |||
75 | { "Copyright", XMMS_MEDIALIB_ENTRY_PROPERTY_COPYRIGHT"copyright" }, | |||
76 | { "CatalogNumber", XMMS_MEDIALIB_ENTRY_PROPERTY_CATALOGNUMBER"catalognumber" }, | |||
77 | { "Barcode", XMMS_MEDIALIB_ENTRY_PROPERTY_BARCODE"barcode" }, | |||
78 | { "ALBUMSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_SORT"album_sort" }, | |||
79 | { "ALBUMARTISTSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ARTIST_SORT"album_artist_sort" }, | |||
80 | { "ARTISTSORT", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST_SORT"artist_sort" }, | |||
81 | { "MUSICBRAINZ_TRACKID", XMMS_MEDIALIB_ENTRY_PROPERTY_TRACK_ID"track_id" }, | |||
82 | { "MUSICBRAINZ_ALBUMID", XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM_ID"album_id" }, | |||
83 | { "MUSICBRAINZ_ARTISTID", XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST_ID"artist_id" }, | |||
84 | { "MUSICBRAINZ_ALBUMARTISTID", XMMS_MEDIALIB_ENTRY_PROPERTY_COMPILATION"compilation" }, | |||
85 | ||||
86 | /* foobar2000 free-form strings (not in APEv2 spec) */ | |||
87 | { "tracknumber", XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR"tracknr", }, | |||
88 | { "discnumber", XMMS_MEDIALIB_ENTRY_PROPERTY_PARTOFSET"partofset", }, | |||
89 | ||||
90 | /* ReplayGain (including obsolete tag names - priority to new style tags) */ | |||
91 | { "rg_audiophile", XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_ALBUM"gain_album", }, | |||
92 | { "replaygain_album_gain", XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_ALBUM"gain_album", }, | |||
93 | { "replaygain_album_peak", XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_ALBUM"peak_album", }, | |||
94 | { "rg_radio", XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK"gain_track", }, | |||
95 | { "replaygain_track_gain", XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK"gain_track", }, | |||
96 | { "rg_peak", XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_TRACK"peak_track", }, | |||
97 | { "replaygain_track_peak", XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_TRACK"peak_track", } | |||
98 | }; | |||
99 | ||||
100 | static const xmms_xform_metadata_mapping_t mappings[] = { | |||
101 | { "Cover Art (Front)", xmms_apetag_handle_tag_coverart } | |||
102 | }; | |||
103 | ||||
104 | /* | |||
105 | * Function prototypes | |||
106 | */ | |||
107 | ||||
108 | static gboolean xmms_wavpack_plugin_setup (xmms_xform_plugin_t *xform_plugin); | |||
109 | static gboolean xmms_wavpack_init (xmms_xform_t *xform); | |||
110 | static gint64 xmms_wavpack_seek (xmms_xform_t *xform, gint64 samples, | |||
111 | xmms_xform_seek_mode_t whence, xmms_error_t *error); | |||
112 | static gint xmms_wavpack_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, | |||
113 | xmms_error_t *error); | |||
114 | static void xmms_wavpack_destroy (xmms_xform_t *xform); | |||
115 | ||||
116 | static void xmms_wavpack_free_data (xmms_wavpack_data_t *data); | |||
117 | static int32_t wavpack_read_bytes (void *id, void *data, int32_t bcount); | |||
118 | static uint32_t wavpack_get_pos (void *id); | |||
119 | static int wavpack_set_pos_abs (void *id, uint32_t pos); | |||
120 | static int wavpack_set_pos_rel (void *id, int32_t pos, int whence); | |||
121 | static int wavpack_push_back_byte (void *id, int c); | |||
122 | static uint32_t wavpack_get_length (void *id); | |||
123 | static int wavpack_can_seek (void *id); | |||
124 | ||||
125 | /* | |||
126 | * Plugin header | |||
127 | */ | |||
128 | ||||
129 | XMMS_XFORM_PLUGIN_DEFINE ("wavpack",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_XFORM, 7, "wavpack", "WavPack Decoder", "clang-analysis", "WavPack decoder", (gboolean (*)(gpointer) )xmms_wavpack_plugin_setup }; | |||
130 | "WavPack Decoder", XMMS_VERSION,xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_XFORM, 7, "wavpack", "WavPack Decoder", "clang-analysis", "WavPack decoder", (gboolean (*)(gpointer) )xmms_wavpack_plugin_setup }; | |||
131 | "WavPack decoder",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_XFORM, 7, "wavpack", "WavPack Decoder", "clang-analysis", "WavPack decoder", (gboolean (*)(gpointer) )xmms_wavpack_plugin_setup }; | |||
132 | xmms_wavpack_plugin_setup)xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_XFORM, 7, "wavpack", "WavPack Decoder", "clang-analysis", "WavPack decoder", (gboolean (*)(gpointer) )xmms_wavpack_plugin_setup };; | |||
133 | ||||
134 | static gboolean | |||
135 | xmms_wavpack_plugin_setup (xmms_xform_plugin_t *xform_plugin) | |||
136 | { | |||
137 | xmms_xform_methods_t methods; | |||
138 | ||||
139 | XMMS_XFORM_METHODS_INIT (methods)memset (&methods, 0, sizeof (xmms_xform_methods_t)); | |||
140 | ||||
141 | methods.init = xmms_wavpack_init; | |||
142 | methods.destroy = xmms_wavpack_destroy; | |||
143 | methods.read = xmms_wavpack_read; | |||
144 | methods.seek = xmms_wavpack_seek; | |||
145 | ||||
146 | xmms_xform_plugin_methods_set (xform_plugin, &methods); | |||
147 | ||||
148 | xmms_xform_plugin_metadata_mapper_init (xform_plugin, | |||
149 | basic_mappings, | |||
150 | G_N_ELEMENTS (basic_mappings)(sizeof (basic_mappings) / sizeof ((basic_mappings)[0])), | |||
151 | mappings, | |||
152 | G_N_ELEMENTS (mappings)(sizeof (mappings) / sizeof ((mappings)[0]))); | |||
153 | ||||
154 | xmms_xform_plugin_indata_add (xform_plugin, | |||
155 | XMMS_STREAM_TYPE_MIMETYPE, | |||
156 | "audio/x-wavpack", | |||
157 | XMMS_STREAM_TYPE_END); | |||
158 | ||||
159 | xmms_magic_add ("wavpack header v4", "audio/x-wavpack", | |||
160 | "0 string wvpk", NULL((void*)0)); | |||
161 | ||||
162 | xmms_magic_extension_add ("audio/x-wavpack", "*.wv"); | |||
163 | ||||
164 | return TRUE(!(0)); | |||
165 | } | |||
166 | ||||
167 | static gboolean | |||
168 | xmms_wavpack_init (xmms_xform_t *xform) | |||
169 | { | |||
170 | xmms_wavpack_data_t *data; | |||
171 | xmms_sample_format_t sample_format; | |||
172 | gint samplerate; | |||
173 | /* the maximum length of error really isn't defined... stupid */ | |||
174 | gchar error[1024]; | |||
175 | ||||
176 | 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); | |||
177 | ||||
178 | if (!xmms_apetag_read (xform)) { | |||
179 | XMMS_DBG ("Failed to read APEv2 tag")g_debug ("../src/plugins/wavpack/wavpack.c" ":" "179" ": " "Failed to read APEv2 tag" ); | |||
180 | } | |||
181 | ||||
182 | data = g_new0 (xmms_wavpack_data_t, 1)((xmms_wavpack_data_t *) g_malloc0_n ((1), sizeof (xmms_wavpack_data_t ))); | |||
183 | 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); | |||
184 | ||||
185 | xmms_xform_private_data_set (xform, data); | |||
186 | ||||
187 | data->reader.read_bytes = wavpack_read_bytes; | |||
188 | data->reader.get_pos = wavpack_get_pos; | |||
189 | data->reader.set_pos_abs = wavpack_set_pos_abs; | |||
190 | data->reader.set_pos_rel = wavpack_set_pos_rel; | |||
191 | data->reader.push_back_byte = wavpack_push_back_byte; | |||
192 | data->reader.get_length = wavpack_get_length; | |||
193 | data->reader.can_seek = wavpack_can_seek; | |||
194 | ||||
195 | data->ctx = WavpackOpenFileInputEx (&data->reader, | |||
196 | xform, xform, | |||
197 | error, OPEN_TAGS0x2, 0); | |||
198 | ||||
199 | if (!data->ctx) { | |||
200 | xmms_log_error ("Unable to open wavpack file: %s", error)g_warning ("../src/plugins/wavpack/wavpack.c" ":" "200" ": " "Unable to open wavpack file: %s" , error); | |||
201 | xmms_xform_private_data_set (xform, NULL((void*)0)); | |||
202 | xmms_wavpack_free_data (data); | |||
203 | return FALSE(0); | |||
204 | } | |||
205 | ||||
206 | data->channels = WavpackGetNumChannels (data->ctx); | |||
207 | data->bits_per_sample = WavpackGetBitsPerSample (data->ctx); | |||
208 | data->num_samples = WavpackGetNumSamples (data->ctx); | |||
209 | samplerate = WavpackGetSampleRate (data->ctx); | |||
210 | ||||
211 | xmms_xform_metadata_set_int (xform, | |||
212 | XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION"duration", | |||
213 | (int) (1000.0 * data->num_samples / samplerate)); | |||
214 | xmms_xform_metadata_set_int (xform, | |||
215 | XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE"samplerate", | |||
216 | samplerate); | |||
217 | xmms_xform_metadata_set_int (xform, | |||
218 | XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE"bitrate", | |||
219 | (int) WavpackGetAverageBitrate (data->ctx, FALSE(0))); | |||
220 | ||||
221 | switch (data->bits_per_sample) { | |||
222 | case 8: | |||
223 | sample_format = XMMS_SAMPLE_FORMAT_S8; | |||
224 | break; | |||
225 | case 12: | |||
226 | case 16: | |||
227 | sample_format = XMMS_SAMPLE_FORMAT_S16; | |||
228 | break; | |||
229 | case 24: | |||
230 | case 32: | |||
231 | sample_format = XMMS_SAMPLE_FORMAT_S32; | |||
232 | break; | |||
233 | default: | |||
234 | xmms_log_error ("Unsupported bits-per-sample in wavpack file: %d",g_warning ("../src/plugins/wavpack/wavpack.c" ":" "235" ": " "Unsupported bits-per-sample in wavpack file: %d" , data->bits_per_sample) | |||
235 | data->bits_per_sample)g_warning ("../src/plugins/wavpack/wavpack.c" ":" "235" ": " "Unsupported bits-per-sample in wavpack file: %d" , data->bits_per_sample); | |||
236 | xmms_xform_private_data_set (xform, NULL((void*)0)); | |||
237 | xmms_wavpack_free_data (data); | |||
238 | return FALSE(0); | |||
239 | } | |||
240 | ||||
241 | xmms_xform_outdata_type_add (xform, | |||
242 | XMMS_STREAM_TYPE_MIMETYPE, | |||
243 | "audio/pcm", | |||
244 | XMMS_STREAM_TYPE_FMT_FORMAT, | |||
245 | sample_format, | |||
246 | XMMS_STREAM_TYPE_FMT_CHANNELS, | |||
247 | data->channels, | |||
248 | XMMS_STREAM_TYPE_FMT_SAMPLERATE, | |||
249 | samplerate, | |||
250 | XMMS_STREAM_TYPE_END); | |||
251 | ||||
252 | return TRUE(!(0)); | |||
253 | } | |||
254 | ||||
255 | static gint64 | |||
256 | xmms_wavpack_seek (xmms_xform_t *xform, gint64 samples, | |||
257 | xmms_xform_seek_mode_t whence, xmms_error_t *error) | |||
258 | { | |||
259 | xmms_wavpack_data_t *data; | |||
260 | gint ret; | |||
261 | ||||
262 | 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); | |||
263 | g_return_val_if_fail (samples >= 0, -1)do{ if (samples >= 0) { } else { g_return_if_fail_warning ( ((gchar*) 0), ((const char*) (__func__)), "samples >= 0"); return (-1); }; }while (0); | |||
264 | 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); | |||
265 | ||||
266 | data = xmms_xform_private_data_get (xform); | |||
267 | 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); | |||
268 | ||||
269 | ret = WavpackSeekSample (data->ctx, (uint32_t)samples); | |||
270 | ||||
271 | if (ret) { | |||
272 | /* success */ | |||
273 | return samples; | |||
274 | } else { | |||
275 | return -1; | |||
276 | } | |||
277 | } | |||
278 | ||||
279 | static void | |||
280 | xmms_wavpack_ensure_buf (xmms_wavpack_data_t *data, gint mono_samples) | |||
281 | { | |||
282 | if (data->buf_mono_samples < mono_samples) { | |||
283 | data->buf = g_realloc (data->buf, | |||
284 | mono_samples * sizeof (xmms_samples32_t)); | |||
285 | data->buf_mono_samples = mono_samples; | |||
286 | } | |||
287 | } | |||
288 | ||||
289 | static gint | |||
290 | xmms_wavpack_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, | |||
291 | xmms_error_t *error) | |||
292 | { | |||
293 | xmms_wavpack_data_t *data; | |||
294 | gint mono_samples, samples; | |||
| ||||
295 | xmms_samples32_t *buf32; | |||
296 | gint i; | |||
297 | ||||
298 | 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); | |||
299 | ||||
300 | data = xmms_xform_private_data_get (xform); | |||
301 | 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); | |||
302 | ||||
303 | switch (data->bits_per_sample) { | |||
304 | case 8: | |||
305 | mono_samples = len; | |||
306 | xmms_wavpack_ensure_buf (data, mono_samples); | |||
307 | buf32 = data->buf; | |||
308 | break; | |||
309 | case 12: | |||
310 | case 16: | |||
311 | mono_samples = len / 2; | |||
312 | xmms_wavpack_ensure_buf (data, mono_samples); | |||
313 | buf32 = data->buf; | |||
314 | break; | |||
315 | case 24: | |||
316 | mono_samples = len / 4; | |||
317 | buf32 = buf; | |||
318 | break; | |||
319 | case 32: | |||
320 | mono_samples = len / 4; | |||
321 | buf32 = buf; | |||
322 | break; | |||
323 | } | |||
324 | ||||
325 | samples = mono_samples / data->channels; | |||
| ||||
326 | ||||
327 | samples = WavpackUnpackSamples (data->ctx, buf32, samples); | |||
328 | ||||
329 | mono_samples = samples * data->channels; | |||
330 | ||||
331 | switch (data->bits_per_sample) { | |||
332 | case 8: | |||
333 | len = mono_samples; | |||
334 | for (i=0; i<mono_samples; ++i) { | |||
335 | ((xmms_samples8_t *) buf)[i] = data->buf[i]; | |||
336 | } | |||
337 | break; | |||
338 | case 12: | |||
339 | len = mono_samples * 2; | |||
340 | for (i=0; i<mono_samples; ++i) { | |||
341 | ((xmms_samples16_t *) buf)[i] = data->buf[i] << 4; | |||
342 | } | |||
343 | break; | |||
344 | case 16: | |||
345 | len = mono_samples * 2; | |||
346 | for (i=0; i<mono_samples; ++i) { | |||
347 | ((xmms_samples16_t *) buf)[i] = data->buf[i]; | |||
348 | } | |||
349 | break; | |||
350 | case 24: | |||
351 | len = mono_samples * 4; | |||
352 | for (i=0; i<mono_samples; ++i) { | |||
353 | ((xmms_samples32_t *) buf)[i] <<= 8; | |||
354 | } | |||
355 | break; | |||
356 | case 32: | |||
357 | len = mono_samples * 4; | |||
358 | break; | |||
359 | } | |||
360 | ||||
361 | return len; | |||
362 | } | |||
363 | ||||
364 | static void | |||
365 | xmms_wavpack_destroy (xmms_xform_t *xform) | |||
366 | { | |||
367 | xmms_wavpack_data_t *data; | |||
368 | ||||
369 | g_return_if_fail (xform)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return; }; }while ( 0); | |||
370 | ||||
371 | data = xmms_xform_private_data_get (xform); | |||
372 | g_return_if_fail (data)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return; }; }while (0); | |||
373 | ||||
374 | xmms_wavpack_free_data (data); | |||
375 | } | |||
376 | ||||
377 | static int32_t | |||
378 | wavpack_read_bytes (void *id, void *buf, int32_t bcount) | |||
379 | { | |||
380 | xmms_xform_t *xform = id; | |||
381 | xmms_wavpack_data_t *data; | |||
382 | xmms_error_t error; | |||
383 | gint64 ret; | |||
384 | gboolean did_pushback = FALSE(0); | |||
385 | ||||
386 | 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); | |||
387 | ||||
388 | data = xmms_xform_private_data_get (xform); | |||
389 | 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); | |||
390 | ||||
391 | /* if we have pushback data, consume it */ | |||
392 | if (data->pushback_set && bcount > 0) { | |||
393 | ((guint8 *)buf)[0] = data->pushback_byte; | |||
394 | buf++; | |||
395 | bcount--; | |||
396 | ||||
397 | data->pushback_set = FALSE(0); | |||
398 | ||||
399 | did_pushback = TRUE(!(0)); | |||
400 | ||||
401 | if (bcount == 0) { | |||
402 | return 1; | |||
403 | } | |||
404 | } | |||
405 | ||||
406 | ret = xmms_xform_read (xform, buf, bcount, &error); | |||
407 | ||||
408 | if (ret != -1 && did_pushback) { | |||
409 | /* adjust return value if we consumed the pushback byte */ | |||
410 | ret++; | |||
411 | } | |||
412 | ||||
413 | return ret; | |||
414 | } | |||
415 | ||||
416 | static uint32_t | |||
417 | wavpack_get_pos (void *id) | |||
418 | { | |||
419 | xmms_xform_t *xform = id; | |||
420 | xmms_wavpack_data_t *data; | |||
421 | xmms_error_t error; | |||
422 | ||||
423 | g_return_val_if_fail (xform, (uint32_t)-1)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return ((uint32_t) -1); }; }while (0); | |||
424 | ||||
425 | data = xmms_xform_private_data_get (xform); | |||
426 | g_return_val_if_fail (data, (uint32_t)-1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((uint32_t)-1) ; }; }while (0); | |||
427 | ||||
428 | gint64 pos = xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_CUR, &error); | |||
429 | ||||
430 | if (data->pushback_set) { | |||
431 | /* we didn't actually perform the pushback on the | |||
432 | underlying stream so adjust offset accordingly */ | |||
433 | pos--; | |||
434 | } | |||
435 | ||||
436 | return (uint32_t)pos; | |||
437 | } | |||
438 | ||||
439 | /* return 0 on success, -1 on error */ | |||
440 | static int | |||
441 | wavpack_set_pos_abs (void *id, uint32_t pos) | |||
442 | { | |||
443 | xmms_xform_t *xform = id; | |||
444 | xmms_wavpack_data_t *data; | |||
445 | xmms_error_t error; | |||
446 | gint ret; | |||
447 | ||||
448 | 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); | |||
449 | ||||
450 | data = xmms_xform_private_data_get (xform); | |||
451 | 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); | |||
452 | ||||
453 | ret = xmms_xform_seek (xform, pos, XMMS_XFORM_SEEK_SET, &error); | |||
454 | ||||
455 | if (ret == -1) { | |||
456 | return -1; | |||
457 | } | |||
458 | ||||
459 | data->pushback_set = FALSE(0); | |||
460 | ||||
461 | return 0; | |||
462 | } | |||
463 | ||||
464 | /* return 0 on success, -1 on error */ | |||
465 | static int | |||
466 | wavpack_set_pos_rel (void *id, int32_t pos, int whence) | |||
467 | { | |||
468 | xmms_xform_t *xform = id; | |||
469 | xmms_wavpack_data_t *data; | |||
470 | xmms_error_t error; | |||
471 | gint ret; | |||
472 | ||||
473 | 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); | |||
474 | ||||
475 | data = xmms_xform_private_data_get (xform); | |||
476 | 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); | |||
477 | ||||
478 | if (whence == SEEK_CUR1) { | |||
479 | whence = XMMS_XFORM_SEEK_CUR; | |||
480 | ||||
481 | if (data->pushback_set) { | |||
482 | /* we didn't actually perform the pushback on the | |||
483 | underlying stream so adjust offset accordingly */ | |||
484 | pos--; | |||
485 | } | |||
486 | } else if (whence == SEEK_SET0) { | |||
487 | whence = XMMS_XFORM_SEEK_SET; | |||
488 | } else if (whence == SEEK_END2) { | |||
489 | whence = XMMS_XFORM_SEEK_END; | |||
490 | } | |||
491 | ||||
492 | ret = xmms_xform_seek (xform, pos, whence, &error); | |||
493 | ||||
494 | data->pushback_set = FALSE(0); | |||
495 | ||||
496 | return ((ret != -1) ? 0 : -1); | |||
497 | } | |||
498 | ||||
499 | static int | |||
500 | wavpack_push_back_byte (void *id, int c) | |||
501 | { | |||
502 | xmms_xform_t *xform = id; | |||
503 | xmms_wavpack_data_t *data; | |||
504 | ||||
505 | g_return_val_if_fail (xform, EOF)do{ if (xform) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "xform"); return ((-1)); }; } while (0); | |||
506 | ||||
507 | data = xmms_xform_private_data_get (xform); | |||
508 | g_return_val_if_fail (data, EOF)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((-1)); }; }while (0); | |||
509 | ||||
510 | if (data->pushback_set) { | |||
511 | /* current implementation only supports pushing back one byte, | |||
512 | and in wavpack-4.31 this is enough */ | |||
513 | /* => return failure */ | |||
514 | return EOF(-1); | |||
515 | } | |||
516 | ||||
517 | data->pushback_byte = c; | |||
518 | data->pushback_set = TRUE(!(0)); | |||
519 | ||||
520 | return c; | |||
521 | } | |||
522 | ||||
523 | static uint32_t | |||
524 | wavpack_get_length (void *id) | |||
525 | { | |||
526 | xmms_xform_t *xform = id; | |||
527 | gint filesize; | |||
528 | const gchar *metakey; | |||
529 | ||||
530 | metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE"size"; | |||
531 | if (!xmms_xform_metadata_get_int (xform, metakey, &filesize)) { | |||
532 | filesize = 0; | |||
533 | } | |||
534 | ||||
535 | return filesize; | |||
536 | } | |||
537 | ||||
538 | static int | |||
539 | wavpack_can_seek (void *id) | |||
540 | { | |||
541 | xmms_xform_t *xform = id; | |||
542 | xmms_error_t error; | |||
543 | int ret; | |||
544 | ||||
545 | ret = xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_CUR, &error); | |||
546 | ||||
547 | return (ret != -1); | |||
548 | } | |||
549 | ||||
550 | static void | |||
551 | xmms_wavpack_free_data (xmms_wavpack_data_t *data) | |||
552 | { | |||
553 | if (!data) { | |||
554 | return; | |||
555 | } | |||
556 | ||||
557 | if (data->buf) { | |||
558 | g_free (data->buf); | |||
559 | } | |||
560 | ||||
561 | if (data->ctx) { | |||
562 | WavpackCloseFile (data->ctx); | |||
563 | } | |||
564 | ||||
565 | g_free (data); | |||
566 | } |