diff options
author | Alexey Yakovenko <waker@users.sourceforge.net> | 2014-05-28 20:52:30 +0200 |
---|---|---|
committer | Alexey Yakovenko <waker@users.sourceforge.net> | 2014-05-28 21:01:08 +0200 |
commit | e1363a40577d0027d0fd858aa85b5dafdf5eac0c (patch) | |
tree | 37981fc583962fe1302883ccb49473cb3625e64c /plugins | |
parent | ce0afc80553144a45e1e1c6ac1d4cb2a32d54ea8 (diff) |
ape: allow playing ape format >=4.11 (bug #1019), improved error handling
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/ffap/ffap.c | 92 |
1 files changed, 69 insertions, 23 deletions
diff --git a/plugins/ffap/ffap.c b/plugins/ffap/ffap.c index 1a7641fb..c1de88ff 100644 --- a/plugins/ffap/ffap.c +++ b/plugins/ffap/ffap.c @@ -274,6 +274,7 @@ typedef struct APEContext { int error; int skip_header; + int filterbuf_size[APE_FILTER_LEVELS]; } APEContext; typedef struct { @@ -398,7 +399,7 @@ ape_read_header(DB_FILE *fp, APEContext *ape) return -1; } - if (ape->fileversion < APE_MIN_VERSION || ape->fileversion > APE_MAX_VERSION) { + if (ape->fileversion < APE_MIN_VERSION) { fprintf (stderr, "ape: Unsupported file version - %d.%02d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10); return -1; } @@ -435,7 +436,9 @@ ape_read_header(DB_FILE *fp, APEContext *ape) /* Skip any unknown bytes at the end of the descriptor. This is for future compatibility */ if (ape->descriptorlength > 52) { - deadbeef->fseek (fp, ape->descriptorlength - 52, SEEK_CUR); + if (deadbeef->fseek (fp, ape->descriptorlength - 52, SEEK_CUR)) { + return -1; + } } /* Read header data */ @@ -493,7 +496,9 @@ ape_read_header(DB_FILE *fp, APEContext *ape) } if (ape->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL) { - deadbeef->fseek(fp, 4, SEEK_CUR); /* Skip the peak level */ + if (deadbeef->fseek(fp, 4, SEEK_CUR)) { /* Skip the peak level */ + return -1; + } ape->headerlength += 4; } @@ -522,7 +527,9 @@ ape_read_header(DB_FILE *fp, APEContext *ape) /* Skip any stored wav header */ if (!(ape->formatflags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)) { - deadbeef->fseek (fp, ape->wavheaderlength, SEEK_CUR); + if (deadbeef->fseek (fp, ape->wavheaderlength, SEEK_CUR)) { + return -1; + } } } @@ -607,7 +614,7 @@ static int ape_read_packet(DB_FILE *fp, APEContext *ape_ctx) if (ape->currentframe > ape->totalframes) return -1; - trace ("seeking to packet %d (%d + %d)\n", ape->currentframe, ape->frames[ape->currentframe].pos, ape_ctx->skip_header); + trace ("seeking to packet %d (%lld + %d)\n", ape->currentframe, ape->frames[ape->currentframe].pos, ape_ctx->skip_header); if (deadbeef->fseek (fp, ape->frames[ape->currentframe].pos + ape_ctx->skip_header, SEEK_SET) != 0) { return -1; } @@ -665,6 +672,7 @@ ape_free_ctx (APEContext *ape_ctx) { ape_ctx->filterbuf[i] = NULL; } } + memset (ape_ctx, 0, sizeof (APEContext)); } static void @@ -699,7 +707,9 @@ ffap_init (DB_fileinfo_t *_info, DB_playItem_t *it) memset (&info->ape_ctx, 0, sizeof (info->ape_ctx)); int skip = deadbeef->junk_get_leading_size (info->fp); if (skip > 0) { - deadbeef->fseek (info->fp, skip, SEEK_SET); + if (deadbeef->fseek (info->fp, skip, SEEK_SET)) { + return -1; + } info->ape_ctx.skip_header = skip; } ape_read_header (info->fp, &info->ape_ctx); @@ -721,7 +731,8 @@ ffap_init (DB_fileinfo_t *_info, DB_playItem_t *it) for (i = 0; i < APE_FILTER_LEVELS; i++) { if (!ape_filter_orders[info->ape_ctx.fset][i]) break; - int err = posix_memalign ((void **)&info->ape_ctx.filterbuf[i], 16, (ape_filter_orders[info->ape_ctx.fset][i] * 3 + HISTORY_SIZE) * 4); + info->ape_ctx.filterbuf_size[i] = (ape_filter_orders[info->ape_ctx.fset][i] * 3 + HISTORY_SIZE) * 4; + int err = posix_memalign ((void **)&info->ape_ctx.filterbuf[i], 16, info->ape_ctx.filterbuf_size[i]); if (err) { trace ("ffap: out of memory (posix_memalign)\n"); return -1; @@ -965,6 +976,7 @@ static inline int ape_decode_value(APEContext * ctx, APERice *rice) range_dec_normalize(ctx); ctx->rc.help = ctx->rc.range / ((pivot >> lo_bits) + 1); if (unlikely (ctx->rc.help == 0)) { + trace ("rc.help=0\n"); ctx->error = 1; return 0; } @@ -1475,7 +1487,7 @@ ape_decode_frame(DB_fileinfo_t *_info, void *data, int *data_size) /* should not happen but who knows */ if (BLOCKS_PER_LOOP * samplesize > *data_size) { - fprintf (stderr, "ape: Packet size is too big! (max is %d where you have %d)\n", *data_size, BLOCKS_PER_LOOP * samplesize); + fprintf (stderr, "ape: Packet size is too big! (max is %d while you have %d)\n", *data_size, BLOCKS_PER_LOOP * samplesize); return -1; } @@ -1485,7 +1497,7 @@ ape_decode_frame(DB_fileinfo_t *_info, void *data, int *data_size) return -1; } assert (!s->samples); -// fprintf (stderr, "start reading packet %d\n", ape_ctx.currentframe); + trace ("start reading packet %d\n", s->currentframe); assert (s->samples == 0); // all samples from prev packet must have been read // start new packet if (ape_read_packet (info->fp, s) < 0) { @@ -1494,15 +1506,14 @@ ape_decode_frame(DB_fileinfo_t *_info, void *data, int *data_size) } bswap_buf((uint32_t*)(s->packet_data), (const uint32_t*)(s->packet_data), s->packet_remaining >> 2); -// fprintf (stderr, "packet_sizeleft=%d packet_remaining=%d\n", packet_sizeleft, packet_remaining); s->ptr = s->last_ptr = s->packet_data; nblocks = s->samples = bytestream_get_be32(&s->ptr); - //fprintf (stderr, "s->samples=%d (1)\n", s->samples); + trace ("s->samples=%d (1)\n", s->samples); n = bytestream_get_be32(&s->ptr); if(n < 0 || n > 3){ - fprintf (stderr, "ape: Incorrect offset passed\n"); + trace ("ape: Incorrect offset passed\n"); return -1; } s->ptr += n; @@ -1520,6 +1531,7 @@ ape_decode_frame(DB_fileinfo_t *_info, void *data, int *data_size) memset(s->decoded1, 0, sizeof(s->decoded1)); /* Initialize the frame decoder */ + trace ("init_frame_decoder\n"); init_frame_decoder(s); } else { @@ -1563,7 +1575,7 @@ ape_decode_frame(DB_fileinfo_t *_info, void *data, int *data_size) fprintf (stderr, "ape: Error decoding frame, error=%d\n", s->error); } else { - fprintf (stderr, "ape: Error decoding frame, ptr > data_end\n"); + fprintf (stderr, "ape: Error decoding frame, ptr >= data_end\n"); } return -1; } @@ -1651,19 +1663,17 @@ ffap_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { int skip = deadbeef->junk_get_leading_size (fp); if (skip > 0) { - deadbeef->fseek (fp, skip, SEEK_SET); + if (deadbeef->fseek (fp, skip, SEEK_SET)) { + goto error; + } } if (ape_read_header (fp, &ape_ctx) < 0) { fprintf (stderr, "ape: failed to read ape header\n"); - deadbeef->fclose (fp); - ape_free_ctx (&ape_ctx); - return NULL; + goto error; } - if ((ape_ctx.fileversion < APE_MIN_VERSION) || (ape_ctx.fileversion > APE_MAX_VERSION)) { + if (ape_ctx.fileversion < APE_MIN_VERSION) { fprintf(stderr, "ape: unsupported file version - %.2f\n", ape_ctx.fileversion/1000.0); - deadbeef->fclose (fp); - ape_free_ctx (&ape_ctx); - return NULL; + goto error; } float duration = ape_ctx.totalsamples / (float)ape_ctx.samplerate; @@ -1675,10 +1685,14 @@ ffap_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { /*int v2err = */deadbeef->junk_id3v2_read (it, fp); int v1err = deadbeef->junk_id3v1_read (it, fp); if (v1err >= 0) { - deadbeef->fseek (fp, -128, SEEK_END); + if (deadbeef->fseek (fp, -128, SEEK_END)) { + goto error; + } } else { - deadbeef->fseek (fp, 0, SEEK_END); + if (deadbeef->fseek (fp, 0, SEEK_END)) { + goto error; + } } /*int apeerr = */deadbeef->junk_apev2_read (it, fp); @@ -1726,6 +1740,16 @@ ffap_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { deadbeef->pl_item_unref (it); return after; + +error: + if (fp) { + deadbeef->fclose (fp); + } + if (ape_ctx.packet_data) { + ape_free_ctx (&ape_ctx); + } + return NULL; + } static int @@ -1799,6 +1823,28 @@ ffap_seek_sample (DB_fileinfo_t *_info, int sample) { trace ("samples to skip: %d\n", info->ape_ctx.samplestoskip); // reset decoder + info->ape_ctx.CRC = 0; + info->ape_ctx.frameflags = 0; + info->ape_ctx.currentframeblocks = 0; + info->ape_ctx.blocksdecoded = 0; + memset (&info->ape_ctx.predictor, 0, sizeof (info->ape_ctx.predictor)); + memset (info->ape_ctx.decoded0, 0, sizeof (info->ape_ctx.decoded0)); + memset (info->ape_ctx.decoded1, 0, sizeof (info->ape_ctx.decoded1)); + for (int i = 0; i < APE_FILTER_LEVELS; i++) { + memset (info->ape_ctx.filterbuf[i], 0, info->ape_ctx.filterbuf_size[i]); + } + memset (&info->ape_ctx.rc, 0, sizeof (info->ape_ctx.rc)); + memset (&info->ape_ctx.riceX, 0, sizeof (info->ape_ctx.riceX)); + memset (&info->ape_ctx.riceY, 0, sizeof (info->ape_ctx.riceY)); + memset (info->ape_ctx.filters, 0, sizeof (info->ape_ctx.filters)); + memset (info->ape_ctx.packet_data, 0, PACKET_BUFFER_SIZE); + info->ape_ctx.packet_sizeleft = 0; + info->ape_ctx.data_end = NULL; + info->ape_ctx.ptr = NULL; + info->ape_ctx.last_ptr = NULL; + info->ape_ctx.error = 0; + memset (info->ape_ctx.buffer, 0, sizeof (info->ape_ctx.buffer)); + info->ape_ctx.remaining = 0; info->ape_ctx.packet_remaining = 0; info->ape_ctx.samples = 0; |