summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/arm_support/support-arm.S51
-rw-r--r--lib/mipsunwinder/SOURCES2
-rw-r--r--lib/mipsunwinder/backtrace-mips32.c236
-rw-r--r--lib/mipsunwinder/backtrace-mipsunwinder.h65
-rw-r--r--lib/mipsunwinder/init_context_32.S12
-rw-r--r--lib/mipsunwinder/mipsunwinder.make23
-rw-r--r--lib/rbcodec/codecs/libm4a/demux.c31
-rw-r--r--lib/rbcodec/codecs/libm4a/m4a.c148
-rw-r--r--lib/rbcodec/codecs/libm4a/m4a.h1
-rw-r--r--lib/rbcodec/codecs/libopus/silk/NLSF2A.c2
-rw-r--r--lib/rbcodec/dsp/tdspeed.c9
-rw-r--r--lib/rbcodec/dsp/tdspeed.h1
-rw-r--r--lib/rbcodec/metadata/aac.c2
-rw-r--r--lib/rbcodec/metadata/asap.c19
-rw-r--r--lib/rbcodec/metadata/asf.c81
-rw-r--r--lib/rbcodec/metadata/id3tags.c15
-rw-r--r--lib/rbcodec/metadata/metadata.c38
-rw-r--r--lib/rbcodec/metadata/metadata.h1
-rw-r--r--lib/rbcodec/metadata/metadata_common.c90
-rw-r--r--lib/rbcodec/metadata/metadata_common.h4
-rw-r--r--lib/rbcodec/metadata/mp4.c21
-rw-r--r--lib/rbcodec/metadata/replaygain.c31
-rw-r--r--lib/skin_parser/skin_buffer.c4
-rw-r--r--lib/unwarminder/backtrace-unwarminder.c3
-rw-r--r--lib/x1000-installer/src/xf_nandio.c2
-rw-r--r--lib/x1000-installer/src/xf_package.c2
-rw-r--r--lib/x1000-installer/test_lib/core_alloc.c7
-rw-r--r--lib/x1000-installer/test_lib/core_alloc.h10
28 files changed, 692 insertions, 219 deletions
diff --git a/lib/arm_support/support-arm.S b/lib/arm_support/support-arm.S
index df49dc49e8..f99d086b0b 100644
--- a/lib/arm_support/support-arm.S
+++ b/lib/arm_support/support-arm.S
@@ -676,8 +676,8 @@ __udivsi3:
.size __udivsi3, . - __udivsi3
__divsi3:
- str lr, [sp, #-4]
- ARMV5_SDIV32_BODY r0, r1, r0, "", r2, lr, ip, r3, __div0_wrap_s, "ldr pc, [sp, #-4]"
+ push {lr}
+ ARMV5_SDIV32_BODY r0, r1, r0, "", r2, lr, ip, r3, __div0_wrap_s, "pop {pc}"
.size __divsi3, . - __divsi3
#else
@@ -686,8 +686,8 @@ __aeabi_uidivmod:
.size __aeabi_uidivmod, . - __aeabi_uidivmod
__aeabi_idivmod:
- str lr, [sp, #-4]
- ARMV5_SDIV32_BODY r0, r1, r0, r1, r2, lr, ip, r3, __div0_wrap_s, "ldr pc, [sp, #-4]"
+ push {lr}
+ ARMV5_SDIV32_BODY r0, r1, r0, r1, r2, lr, ip, r3, __div0_wrap_s, "pop {pc}"
.size __aeabi_idivmod, . - __aeabi_idivmod
#endif
@@ -705,6 +705,9 @@ __aeabi_idivmod:
/*
* int __popcountsi2(unsigned int x)
* int __popcountdi2(unsigned long x)
+ * x = x - ((x >> 1) & 0x55555555);
+ * x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+ * c = ((x + (x >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
*/
.section .text.__popcountsi2, "ax", %progbits
.global __popcountsi2
@@ -712,23 +715,25 @@ __aeabi_idivmod:
.global __popcountdi2
.type __popcountdi2, %function
.set __popcountdi2, __popcountsi2
+
__popcountsi2:
- mov r1, #0x33 @ r1 = 0x33333333
- orr r1, r1, r1, lsl #8 @ ...
- orr r1, r1, r1, lsl #16 @ ...
- eor r2, r1, r1, lsl #1 @ r2 = 0x55555555
- and r2, r2, r0, lsr #1 @ r2 = (x >> 1) & 0x55555555
- sub r0, r0, r2 @ x = x - ((x >> 1) & 0x55555555)
- and r2, r1, r0 @ r2 = x & 0x33333333
- and r1, r1, r0, lsr #2 @ r1 = (x >> 2) & 0x33333333
- add r0, r2, r1 @ x = (x & 0x33333333) + ((x >> 2) & 0x33333333)
- mov r1, #0x0f @ r1 = 0x0f0f0f0f
- orr r1, r1, r1, lsl #8 @ ...
- orr r1, r1, r1, lsl #16 @ ...
- add r0, r0, lsr #4 @ x = x + (x >> 4)
- and r0, r0, r1 @ x = (x + (x >> 4)) & 0x0f0f0f0f
- add r0, r0, lsr #16 @ x = x + (x >> 16)
- add r0, r0, lsr #8 @ x = x + (x >> 8)
- and r0, r0, #0x3f @ x &= 0x3f
- bx lr @ return x
- .size __popcountsi2, .-__popcountsi2
+ ldr r2, .L2 @ r2 = 0x55555555
+ ldr r3, .L2+4 @ r3 = 0x33333333
+ and r2, r2, r0, lsr #1 @ r2 = (x >> 1)
+ rsb r2, r2, r0 @ x = x - ((x >> 1) & 0x55555555)
+ and r0, r2, r3
+ and r3, r3, r2, lsr #2 @ r3 = (x >> 2)
+ add r0, r0, r3
+ ldr r3, .L2+8 @ r3 = 0xF0F0F0F
+ add r0, r0, r0, lsr #4 @ x = x + (x >> 4)
+ and r3, r0, r3
+ add r3, r3, r3, asl #8
+ add r3, r3, r3, asl #16
+ mov r0, r3, lsr #24 @ (r3 >> 24)
+ bx lr
+.L2:
+ .word 0x55555555
+ .word 0x33333333
+ .word 0xF0F0F0F
+ .size __popcountsi2, .-__popcountsi2
+
diff --git a/lib/mipsunwinder/SOURCES b/lib/mipsunwinder/SOURCES
new file mode 100644
index 0000000000..32fa57d157
--- /dev/null
+++ b/lib/mipsunwinder/SOURCES
@@ -0,0 +1,2 @@
+backtrace-mips32.c
+init_context_32.S
diff --git a/lib/mipsunwinder/backtrace-mips32.c b/lib/mipsunwinder/backtrace-mips32.c
new file mode 100644
index 0000000000..c5ab41e628
--- /dev/null
+++ b/lib/mipsunwinder/backtrace-mips32.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * MIPS32 backtrace implementation
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * References:
+ * https://yosefk.com/blog/getting-the-call-stack-without-a-frame-pointer.html
+ * https://elinux.org/images/6/68/ELC2008_-_Back-tracing_in_MIPS-based_Linux_Systems.pdf
+ * System V ABI MIPS Supplement, 3rd edition
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "backtrace.h"
+#include "lcd.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdalign.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#define MIN_ADDR 0x80000000ul
+#define MAX_ADDR (MIN_ADDR + (MEMORYSIZE * 1024 * 1024) - 1)
+
+static bool read_check(const void* addr, size_t alignment)
+{
+ if(addr < (const void*)MIN_ADDR ||
+ addr > (const void*)MAX_ADDR)
+ return false;
+
+ if((uintptr_t)addr & (alignment - 1))
+ return false;
+
+ return true;
+}
+
+static bool read32(const void* addr, uint32_t* val)
+{
+ if(!read_check(addr, alignof(uint32_t)))
+ return false;
+
+ *val = *(const uint32_t*)addr;
+ return true;
+}
+
+#if 0
+static bool read16(const void* addr, uint16_t* val)
+{
+ if(!read_check(addr, alignof(uint16_t)))
+ return false;
+
+ *val = *(const uint16_t*)addr;
+ return true;
+}
+
+static bool read8(const void* addr, uint8_t* val)
+{
+ if(!read_check(addr, alignof(uint8_t)))
+ return false;
+
+ *val = *(const uint8_t*)addr;
+ return true;
+}
+#endif
+
+static long extract_s16(uint32_t val)
+{
+#if 1
+ /* not ISO C, but gets GCC to emit 'seh' which is more compact */
+ return (int32_t)(val << 16) >> 16;
+#else
+ val &= 0xffff;
+
+ if(val > 0x7fff)
+ return (long)val - 0x10000l;
+ else
+ return val;
+#endif
+}
+
+/* TODO - cases not handled by the backtrace algorithm
+ *
+ * 1. functions that save the frame pointer will not be handled correctly
+ * (need to implement the algorithm specified by the System V ABI).
+ *
+ * 2. GCC can generate functions with a "false" stack pointer decrement,
+ * for some examples see read_bmp_fd and walk_path. those functions
+ * seem to be more difficult to deal with and the SysV algorithm will
+ * also get confused by them, but they are not common.
+ */
+int mips_bt_step(struct mips_bt_context* ctx)
+{
+ /* go backward and look for the stack pointer decrement */
+ uint32_t* pc = ctx->pc;
+ uint32_t insn;
+ long sp_off;
+
+ while(true) {
+ if(!read32(pc, &insn))
+ return 0;
+
+ /* addiu sp, sp, sp_off */
+ if((insn >> 16) == 0x27bd) {
+ sp_off = extract_s16(insn);
+ if(sp_off < 0)
+ break;
+ }
+
+ /* jr ra */
+ if(insn == 0x03e00008) {
+ /* end if this is not a leaf or we lack register info */
+ if(ctx->depth > 0 || !(ctx->valid & (1 << MIPSBT_RA))) {
+ mips_bt_debug(ctx, "unexpected leaf function");
+ return 0;
+ }
+
+ /* this is a leaf function - ra contains the return address
+ * and sp is unchanged */
+ ctx->pc = (void*)ctx->reg[MIPSBT_RA] - 8;
+ ctx->depth++;
+ return 1;
+ }
+
+ --pc;
+ }
+
+ mips_bt_debug(ctx, "found sp_off=%ld at %p", sp_off, pc);
+
+ /* now go forward and find the saved return address */
+ while((void*)pc < ctx->pc) {
+ if(!read32(pc, &insn))
+ return 0;
+
+ /* sw ra, ra_off(sp) */
+ if((insn >> 16) == 0xafbf) {
+ long ra_off = extract_s16(insn);
+ uint32_t save_ra;
+
+ /* load the saved return address */
+ mips_bt_debug(ctx, "load ra from %p+%ld", ctx->sp, ra_off);
+ if(!read32(ctx->sp + ra_off, &save_ra))
+ return 0;
+
+ if(save_ra == 0) {
+ mips_bt_debug("hit root");
+ return 0;
+ }
+
+ /* update bt context */
+ ctx->pc = (void*)save_ra - 8;
+ ctx->sp -= sp_off;
+
+ /* update saved register info */
+ ctx->reg[MIPSBT_RA] = save_ra;
+ ctx->valid |= (1 << MIPSBT_RA);
+
+ ctx->depth++;
+ return 1;
+ }
+
+ ++pc;
+ }
+
+ /* sometimes an exception occurs before ra is saved - in this case
+ * the ra register should contain the caller PC, but we still need
+ * to adjust the stack frame. */
+ if(ctx->depth == 0 && (ctx->valid & (1 << MIPSBT_RA))) {
+ ctx->pc = (void*)ctx->reg[MIPSBT_RA] - 8;
+ ctx->sp -= sp_off;
+
+ ctx->depth++;
+ return 1;
+ }
+
+ mips_bt_debug(ctx, "ra not found");
+ return 0;
+}
+
+#ifdef MIPSUNWINDER_DEBUG
+static void rb_backtrace_debugf(void* arg, const char* fmt, ...)
+{
+ static char buf[64];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ unsigned int* line = arg;
+ lcd_putsf(4, (*line)++, "%s", buf);
+ lcd_update();
+}
+#endif
+
+void rb_backtrace_ctx(void* arg, unsigned* line)
+{
+ struct mips_bt_context* ctx = arg;
+#ifdef MIPSUNWINDER_DEBUG
+ ctx->debugf = rb_backtrace_debugf;
+ ctx->debug_arg = line;
+#endif
+
+ do {
+ lcd_putsf(0, (*line)++, "%02d pc:%08lx sp:%08lx",
+ ctx->depth, (unsigned long)ctx->pc, (unsigned long)ctx->sp);
+ lcd_update();
+ } while(mips_bt_step(ctx));
+
+ lcd_puts(0, (*line)++, "bt end");
+ lcd_update();
+}
+
+void rb_backtrace(int pcAddr, int spAddr, unsigned* line)
+{
+ (void)pcAddr;
+ (void)spAddr;
+
+ struct mips_bt_context ctx;
+ mips_bt_start(&ctx);
+ mips_bt_step(&ctx); /* step over this function */
+
+ rb_backtrace_ctx(&ctx, line);
+}
diff --git a/lib/mipsunwinder/backtrace-mipsunwinder.h b/lib/mipsunwinder/backtrace-mipsunwinder.h
new file mode 100644
index 0000000000..4d6288b5fe
--- /dev/null
+++ b/lib/mipsunwinder/backtrace-mipsunwinder.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef BACKTRACE_MIPSUNWINDER_H
+#define BACKTRACE_MIPSUNWINDER_H
+
+/*#define MIPSUNWINDER_DEBUG*/
+
+#include <stdint.h>
+
+enum {
+ MIPSBT_RA,
+ MIPSBT_NREG,
+};
+
+struct mips_bt_context {
+ void* pc;
+ void* sp;
+ int depth;
+ uint32_t valid;
+ uint32_t reg[MIPSBT_NREG];
+#ifdef MIPSUNWINDER_DEBUG
+ void(*debugf)(void*, const char*, ...);
+ void* debug_arg;
+#endif
+};
+
+int mips_bt_step(struct mips_bt_context* ctx);
+void mips_bt_start(struct mips_bt_context* ctx);
+
+#ifdef MIPSUNWINDER_DEBUG
+# define mips_bt_debug(ctx, ...) \
+ do { struct mips_bt_context* __ctx = ctx; \
+ if(__ctx->debugf) \
+ __ctx->debugf(__ctx->debug_arg, __VA_ARGS__);\
+ } while(0)
+#else
+# define mips_bt_debug(...) do { } while(0)
+#endif
+
+/* NOTE: ignores pcAddr and spAddr, backtrace starts from caller */
+void rb_backtrace(int pcAddr, int spAddr, unsigned* line);
+
+/* given struct mips_bt_context argument, print stack traceback */
+void rb_backtrace_ctx(void* arg, unsigned* line);
+
+#endif /* BACKTRACE_MIPSUNWINDER_H */
diff --git a/lib/mipsunwinder/init_context_32.S b/lib/mipsunwinder/init_context_32.S
new file mode 100644
index 0000000000..a943d13dc3
--- /dev/null
+++ b/lib/mipsunwinder/init_context_32.S
@@ -0,0 +1,12 @@
+#include "mips.h"
+
+ .text
+ .global mips_bt_start
+
+mips_bt_start:
+ addiu v0, ra, -8
+ sw v0, 0(a0) /* ctx->pc = ra - 8 */
+ sw sp, 4(a0) /* ctx->sp = sp */
+ sw zero, 8(a0) /* ctx->depth = 0 */
+ sw zero, 12(a0) /* ctx->valid = 0 */
+ jr ra
diff --git a/lib/mipsunwinder/mipsunwinder.make b/lib/mipsunwinder/mipsunwinder.make
new file mode 100644
index 0000000000..ddd1ce078f
--- /dev/null
+++ b/lib/mipsunwinder/mipsunwinder.make
@@ -0,0 +1,23 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+#
+
+MIPSUNWINDERLIB_DIR = $(ROOTDIR)/lib/mipsunwinder
+MIPSUNWINDERLIB_SRC = $(call preprocess, $(MIPSUNWINDERLIB_DIR)/SOURCES)
+MIPSUNWINDERLIB_OBJ := $(call c2obj, $(MIPSUNWINDERLIB_SRC))
+
+OTHER_SRC += $(MIPSUNWINDERLIB_SRC)
+
+MIPSUNWINDERLIB = $(BUILDDIR)/lib/libmipsunwinder.a
+CORE_LIBS += $(MIPSUNWINDERLIB)
+
+INCLUDES += -I$(MIPSUNWINDERLIB_DIR)
+DEFINES += -DBACKTRACE_MIPSUNWINDER
+
+$(MIPSUNWINDERLIB): $(MIPSUNWINDERLIB_OBJ)
+ $(SILENT)$(shell rm -f $@)
+ $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
diff --git a/lib/rbcodec/codecs/libm4a/demux.c b/lib/rbcodec/codecs/libm4a/demux.c
index 3bf46efec6..e29ecb8339 100644
--- a/lib/rbcodec/codecs/libm4a/demux.c
+++ b/lib/rbcodec/codecs/libm4a/demux.c
@@ -349,6 +349,7 @@ static bool read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
{
size_t size_remaining = chunk_len - 8;
+ uint32_t numsizes, i;
/* version */
stream_read_uint8(qtmovie->stream);
@@ -369,9 +370,37 @@ static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
}
size_remaining -= 4;
- qtmovie->res->num_sample_byte_sizes = stream_read_uint32(qtmovie->stream);
+ numsizes = stream_read_uint32(qtmovie->stream);
size_remaining -= 4;
+ /* Because this table can be really large and is only used to improve seek
+ * accuracy, it's optional. In that case the seek code will fall back to a
+ * less accurate seek method. */
+ qtmovie->res->num_sample_byte_sizes = numsizes;
+ if (numsizes * sizeof(uint32_t) < CODEC_SIZE * 1 / 2)
+ qtmovie->res->sample_byte_sizes = malloc(numsizes * sizeof(uint32_t));
+ else
+ qtmovie->res->sample_byte_sizes = NULL;
+
+ if (qtmovie->res->sample_byte_sizes)
+ {
+ for (i = 0; i < numsizes; ++i)
+ {
+ qtmovie->res->sample_byte_sizes[i] =
+ stream_read_uint32(qtmovie->stream);
+ size_remaining -= 4;
+ }
+
+ if (size_remaining)
+ {
+ DEBUGF("extra bytes after stsz\n");
+ }
+ }
+ else
+ {
+ DEBUGF("stsz too large, ignoring it\n");
+ }
+
if (size_remaining)
{
stream_skip(qtmovie->stream, size_remaining);
diff --git a/lib/rbcodec/codecs/libm4a/m4a.c b/lib/rbcodec/codecs/libm4a/m4a.c
index 5fe778ac03..b967e15e7a 100644
--- a/lib/rbcodec/codecs/libm4a/m4a.c
+++ b/lib/rbcodec/codecs/libm4a/m4a.c
@@ -23,6 +23,13 @@
#include <inttypes.h>
#include "m4a.h"
+#undef DEBUGF
+#if defined(DEBUG)
+#define DEBUGF stream->ci->debugf
+#else
+#define DEBUGF(...)
+#endif
+
/* Implementation of the stream.h functions used by libalac */
#define _Swap32(v) do { \
@@ -127,76 +134,113 @@ int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame, uint32_t *st
return demux_res->lookup_table[i].offset;
}
-/* Find the exact or preceding frame in lookup_table[]. Return both frame
- * and byte position of this match. */
-static void gather_offset(demux_res_t *demux_res, uint32_t *frame, uint32_t *offset)
-{
- uint32_t i = 0;
- for (i=0; i<demux_res->num_lookup_table; ++i)
- {
- if (demux_res->lookup_table[i].offset == 0)
- break;
- if (demux_res->lookup_table[i].sample > *frame)
- break;
- }
- i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ *frame. */
- *frame = demux_res->lookup_table[i].sample;
- *offset = demux_res->lookup_table[i].offset;
-}
-
/* Seek to desired sound sample location. Return 1 on success (and modify
- * sound_samples_done and current_sample), 0 if failed.
- *
- * Find the sample (=frame) that contains the given sound sample, find a best
- * fit for this sample in the lookup_table[], seek to the byte position. */
+ * sound_samples_done and current_sample), 0 if failed. */
unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
uint32_t sound_sample_loc, uint32_t* sound_samples_done,
int* current_sample)
{
- uint32_t i = 0;
- uint32_t tmp_var, tmp_cnt, tmp_dur;
- uint32_t new_sample = 0; /* Holds the amount of chunks/frames. */
- uint32_t new_sound_sample = 0; /* Sums up total amount of samples. */
- uint32_t new_pos; /* Holds the desired chunk/frame index. */
-
- /* First check we have the appropriate metadata - we should always
- * have it.
- */
+ uint32_t i, sample_i, sound_sample_i;
+ uint32_t time, time_cnt, time_dur;
+ uint32_t chunk, chunk_first_sample;
+ uint32_t offset;
+ time_to_sample_t *tts_tab = demux_res->time_to_sample;
+ sample_offset_t *tco_tab = demux_res->lookup_table;
+ uint32_t *tsz_tab = demux_res->sample_byte_sizes;
+
+ /* First check we have the required metadata - we should always have it. */
if (!demux_res->num_time_to_samples || !demux_res->num_sample_byte_sizes)
- {
- return 0;
+ {
+ return 0;
}
- /* Find the destination block from time_to_sample array */
- time_to_sample_t *tab = demux_res->time_to_sample;
- while (i < demux_res->num_time_to_samples)
+ /* The 'sound_sample_loc' we have is PCM-based and not directly usable.
+ * We need to convert it to an MP4 sample number 'sample_i' first. */
+ sample_i = sound_sample_i = 0;
+ for (time = 0; time < demux_res->num_time_to_samples; ++time)
{
- tmp_cnt = tab[i].sample_count;
- tmp_dur = tab[i].sample_duration;
- tmp_var = tmp_cnt * tmp_dur;
- if (sound_sample_loc <= new_sound_sample + tmp_var)
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+ uint32_t time_var = time_cnt * time_dur;
+
+ if (sound_sample_loc < sound_sample_i + time_var)
{
- tmp_var = (sound_sample_loc - new_sound_sample);
- new_sample += tmp_var / tmp_dur;
- new_sound_sample += tmp_var;
+ time_var = sound_sample_loc - sound_sample_i;
+ sample_i += time_var / time_dur;
break;
}
- new_sample += tmp_cnt;
- new_sound_sample += tmp_var;
- ++i;
+
+ sample_i += time_cnt;
+ sound_sample_i += time_var;
+ }
+
+ /* Find the chunk after 'sample_i'. */
+ for (chunk = 1; chunk < demux_res->num_lookup_table; ++chunk)
+ {
+ if (tco_tab[chunk].offset == 0)
+ break;
+ if (tco_tab[chunk].sample > sample_i)
+ break;
}
- /* We know the new sample (=frame), now calculate the file position. */
- gather_offset(demux_res, &new_sample, &new_pos);
+ /* The preceding chunk is the one that contains 'sample_i'. */
+ chunk--;
+ chunk_first_sample = tco_tab[chunk].sample;
+ offset = tco_tab[chunk].offset;
- /* We know the new file position, so let's try to seek to it */
- if (stream->ci->seek_buffer(new_pos))
+ /* Compute the PCM sample number of the chunk's first sample
+ * to get an accurate base for sound_sample_i. */
+ i = sound_sample_i = 0;
+ for (time = 0; time < demux_res->num_time_to_samples; ++time)
{
- *sound_samples_done = new_sound_sample;
- *current_sample = new_sample;
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+
+ if (chunk_first_sample < i + time_cnt)
+ {
+ sound_sample_i += (chunk_first_sample - i) * time_dur;
+ break;
+ }
+
+ i += time_cnt;
+ sound_sample_i += time_cnt * time_dur;
+ }
+
+ DEBUGF("seek chunk=%lu, sample=%lu, soundsample=%lu, offset=%lu\n",
+ (unsigned long)chunk, (unsigned long)chunk_first_sample,
+ (unsigned long)sound_sample_i, (unsigned long)offset);
+
+ if (tsz_tab) {
+ /* We have a sample-to-bytes table available so we can do accurate
+ * seeking. Move one sample at a time and update the file offset and
+ * PCM sample offset as we go. */
+ for (i = chunk_first_sample;
+ i < sample_i && i < demux_res->num_sample_byte_sizes; ++i)
+ {
+ /* this could be unnecessary */
+ if (time_cnt == 0 && ++time < demux_res->num_time_to_samples)
+ {
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+ }
+
+ offset += tsz_tab[i];
+ sound_sample_i += time_dur;
+ time_cnt--;
+ }
+ } else {
+ /* No sample-to-bytes table available so we can only seek to the
+ * start of a chunk, which is often much lower resolution. */
+ sample_i = chunk_first_sample;
+ }
+
+ if (stream->ci->seek_buffer(offset))
+ {
+ *sound_samples_done = sound_sample_i;
+ *current_sample = sample_i;
return 1;
}
-
+
return 0;
}
diff --git a/lib/rbcodec/codecs/libm4a/m4a.h b/lib/rbcodec/codecs/libm4a/m4a.h
index aa8e768045..81b10c3a27 100644
--- a/lib/rbcodec/codecs/libm4a/m4a.h
+++ b/lib/rbcodec/codecs/libm4a/m4a.h
@@ -80,6 +80,7 @@ typedef struct
time_to_sample_t *time_to_sample;
uint32_t num_time_to_samples;
+ uint32_t *sample_byte_sizes;
uint32_t num_sample_byte_sizes;
uint32_t codecdata_len;
diff --git a/lib/rbcodec/codecs/libopus/silk/NLSF2A.c b/lib/rbcodec/codecs/libopus/silk/NLSF2A.c
index d5b7730638..8f472f25f7 100644
--- a/lib/rbcodec/codecs/libopus/silk/NLSF2A.c
+++ b/lib/rbcodec/codecs/libopus/silk/NLSF2A.c
@@ -80,7 +80,7 @@ void silk_NLSF2A(
};
const unsigned char *ordering;
opus_int k, i, dd;
- opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ];
+ opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ] = {0};
opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
diff --git a/lib/rbcodec/dsp/tdspeed.c b/lib/rbcodec/dsp/tdspeed.c
index 21585eb78e..64cbaf5e12 100644
--- a/lib/rbcodec/dsp/tdspeed.c
+++ b/lib/rbcodec/dsp/tdspeed.c
@@ -41,7 +41,6 @@
#define MAX_INPUTCOUNT 512 /* Max input count so dst doesn't overflow */
#define FIXED_BUFCOUNT 3072 /* 48KHz factor 3.0 */
#define FIXED_OUTBUFCOUNT 4096
-#define NBUFFERS 4
enum tdspeed_ops
{
@@ -65,9 +64,9 @@ static struct tdspeed_state_s
int32_t *ovl_buff[2]; /* overlap buffer (L+R) */
} tdspeed_state;
-static int32_t *buffers[NBUFFERS] = { NULL, NULL, NULL, NULL };
+static int32_t *buffers[TDSPEED_NBUFFERS] = { NULL, NULL, NULL, NULL };
-static const int buffer_sizes[NBUFFERS] =
+static const int buffer_sizes[TDSPEED_NBUFFERS] =
{
FIXED_BUFCOUNT * sizeof(int32_t),
FIXED_BUFCOUNT * sizeof(int32_t),
@@ -552,7 +551,7 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
break;
case DSP_PROC_INIT:
- if (!tdspeed_alloc_buffers(buffers, buffer_sizes, NBUFFERS))
+ if (!tdspeed_alloc_buffers(buffers, buffer_sizes, TDSPEED_NBUFFERS))
return -1; /* fail the init */
st->this = this;
@@ -564,7 +563,7 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
st->this = NULL;
st->factor = PITCH_SPEED_100;
dsp_outbuf.remcount = 0;
- tdspeed_free_buffers(buffers, NBUFFERS);
+ tdspeed_free_buffers(buffers, TDSPEED_NBUFFERS);
break;
case DSP_PROC_NEW_FORMAT:
diff --git a/lib/rbcodec/dsp/tdspeed.h b/lib/rbcodec/dsp/tdspeed.h
index 2949c1bee9..84920ac7c2 100644
--- a/lib/rbcodec/dsp/tdspeed.h
+++ b/lib/rbcodec/dsp/tdspeed.h
@@ -34,6 +34,7 @@
#define STRETCH_MAX (250L * PITCH_SPEED_PRECISION) /* 250% */
#define STRETCH_MIN (35L * PITCH_SPEED_PRECISION) /* 35% */
+#define TDSPEED_NBUFFERS 4
void dsp_timestretch_enable(bool enable);
void dsp_set_timestretch(int32_t percent);
diff --git a/lib/rbcodec/metadata/aac.c b/lib/rbcodec/metadata/aac.c
index 82adeacbde..358b2de079 100644
--- a/lib/rbcodec/metadata/aac.c
+++ b/lib/rbcodec/metadata/aac.c
@@ -41,7 +41,7 @@ static const int sample_rates[] =
static bool check_adts_syncword(int fd)
{
- uint16_t syncword;
+ uint16_t syncword = 0;
read_uint16be(fd, &syncword);
return (syncword & 0xFFF6) == 0xFFF0;
diff --git a/lib/rbcodec/metadata/asap.c b/lib/rbcodec/metadata/asap.c
index 47eb2a3d50..db23dd69fa 100644
--- a/lib/rbcodec/metadata/asap.c
+++ b/lib/rbcodec/metadata/asap.c
@@ -185,38 +185,41 @@ static bool parse_sap_header(int fd, struct mp3entry* id3, int file_len)
break;
}
}
-
+ static const char *tg_options[] = {"SAP", "AUTHOR", "NAME", "DATE",
+ "SONGS", "DEFSONG", "TIME", NULL};
/* parse tags */
- if(strcmp(line, "SAP") == 0)
+ int tg_op = string_option(line, tg_options, false);
+ if (tg_op == 0) /*SAP*/
sap_signature = 1;
if (sap_signature == -1)
return false;
- if (strcmp(line, "AUTHOR") == 0)
+
+ if (tg_op == 1) /*AUTHOR*/
{
if(read_asap_string(p, &buffer, &buffer_end, &id3->artist) == false)
return false;
}
- else if(strcmp(line, "NAME") == 0)
+ else if(tg_op == 2) /*NAME*/
{
if(read_asap_string(p, &buffer, &buffer_end, &id3->title) == false)
return false;
}
- else if(strcmp(line, "DATE") == 0)
+ else if(tg_op == 3) /*DATE*/
{
if(read_asap_string(p, &buffer, &buffer_end, &id3->year_string) == false)
return false;
}
- else if (strcmp(line, "SONGS") == 0)
+ else if (tg_op == 4) /*SONGS*/
{
if (parse_dec(&numSongs, p, 1, MAX_SONGS) == false )
return false;
}
- else if (strcmp(line, "DEFSONG") == 0)
+ else if (tg_op == 5) /*DEFSONG*/
{
if (parse_dec(&defSong, p, 0, MAX_SONGS) == false)
return false;
}
- else if (strcmp(line, "TIME") == 0)
+ else if (tg_op == 6) /*TIME*/
{
int durationTemp = ASAP_ParseDuration(p);
if (durationTemp < 0 || duration_index >= MAX_SONGS)
diff --git a/lib/rbcodec/metadata/asf.c b/lib/rbcodec/metadata/asf.c
index d90487b36b..82c418cc73 100644
--- a/lib/rbcodec/metadata/asf.c
+++ b/lib/rbcodec/metadata/asf.c
@@ -129,19 +129,21 @@ static int asf_intdecode(int fd, int type, int length)
{
int bytes = 0;
int ret;
- uint16_t tmp16;
- uint32_t tmp32;
- uint64_t tmp64;
+ union {
+ uint16_t tmp16;
+ uint32_t tmp32;
+ uint64_t tmp64;
+ } uu = {0};
if (type == 3) {
- bytes = read_uint32le(fd, &tmp32);
- ret = (int)tmp32;
+ bytes = read_uint32le(fd, &uu.tmp32);
+ ret = (int)uu.tmp32;
} else if (type == 4) {
- bytes = read_uint64le(fd, &tmp64);
- ret = (int)tmp64;
+ bytes = read_uint64le(fd, &uu.tmp64);
+ ret = (int)uu.tmp64;
} else if (type == 5) {
- bytes = read_uint16le(fd, &tmp16);
- ret = (int)tmp16;
+ bytes = read_uint16le(fd, &uu.tmp16);
+ ret = (int)uu.tmp16;
}
if (bytes > 0)
@@ -437,6 +439,25 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
read_uint16le(fd, &count);
bytesleft -= 2;
//DEBUGF("extended metadata count = %u\n",count);
+ enum
+ {
+ eWM_TrackNumber, eWM_Genre, eWM_AlbumTitle,
+ eWM_AlbumArtist, eWM_Composer, eWM_Year,
+ eWM_MusicBrainz_Track_Id, eWM_Picture,
+ eWM_COUNT_TAG_COUNT
+ };
+
+ static const char *tagops[eWM_COUNT_TAG_COUNT + 1] =
+ { [eWM_TrackNumber] = "WM/TrackNumber",
+ [eWM_Genre] = "WM/Genre",
+ [eWM_AlbumTitle] = "WM/AlbumTitle",
+ [eWM_AlbumArtist] = "WM/AlbumArtist",
+ [eWM_Composer] = "WM/Composer",
+ [eWM_Year] = "WM/Year",
+ [eWM_MusicBrainz_Track_Id]"MusicBrainz/Track Id",
+ [eWM_Picture]"WM/Picture",
+ [eWM_COUNT_TAG_COUNT] = NULL
+ };
for (i=0; i < count; i++) {
uint16_t length, type;
@@ -450,7 +471,9 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
read_uint16le(fd, &type);
read_uint16le(fd, &length);
- if (!strcmp("WM/TrackNumber",utf8buf)) {
+ int itag = string_option(utf8buf, tagops, false);
+
+ if (itag == eWM_TrackNumber) {
if (type == 0) {
id3->track_string = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
@@ -460,19 +483,19 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
} else {
lseek(fd, length, SEEK_CUR);
}
- } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) {
+ } else if ((itag == eWM_Genre) && (type == 0)) {
id3->genre_string = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) {
+ } else if ((itag == eWM_AlbumTitle) && (type == 0)) {
id3->album = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) {
+ } else if ((itag == eWM_AlbumArtist) && (type == 0)) {
id3->albumartist = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) {
+ } else if ((itag == eWM_Composer) && (type == 0)) {
id3->composer = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- } else if (!strcmp("WM/Year", utf8buf)) {
+ } else if (itag == eWM_Year) {
if (type == 0) {
id3->year_string = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
@@ -482,15 +505,11 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
} else {
lseek(fd, length, SEEK_CUR);
}
- } else if (!strncmp("replaygain_", utf8buf, 11)) {
- char *value = id3buf;
- asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- parse_replaygain(utf8buf, value, id3);
- } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
+ } else if (itag == eWM_MusicBrainz_Track_Id) {
id3->mb_track_id = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
#ifdef HAVE_ALBUMART
- } else if (!strcmp("WM/Picture", utf8buf)) {
+ } else if (itag == eWM_Picture) {
uint32_t datalength = 0;
uint32_t strlength;
/* Expected is either "01 00 xx xx 03 yy yy yy yy" or
@@ -521,13 +540,23 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
asf_utf16LEdecode(fd, 32, &utf8, &utf8length);
strlength = (strlen(utf8buf) + 2) * 2;
lseek(fd, strlength-32, SEEK_CUR);
- if (!strcmp("image/jpeg", utf8buf)) {
+
+ static const char *aa_options[] = {"image/jpeg",
+ "image/jpg","image/png", NULL};
+ int aa_op = string_option(utf8buf, aa_options, false);
+
+ if (aa_op == 0) /*image/jpeg*/
+ {
id3->albumart.type = AA_TYPE_JPG;
- } else if (!strcmp("image/jpg", utf8buf)) {
+ }
+ else if (aa_op == 1) /*image/jpg*/
+ {
/* image/jpg is technically invalid,
* but it does occur in the wild */
id3->albumart.type = AA_TYPE_JPG;
- } else if (!strcmp("image/png", utf8buf)) {
+ }
+ else if (aa_op == 2) /*image/png*/
+ {
id3->albumart.type = AA_TYPE_PNG;
} else {
id3->albumart.type = AA_TYPE_UNKNOWN;
@@ -543,6 +572,10 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
lseek(fd, datalength, SEEK_CUR);
#endif
+ } else if (!strncmp("replaygain_", utf8buf, 11)) {
+ char *value = id3buf;
+ asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+ parse_replaygain(utf8buf, value, id3);
} else {
lseek(fd, length, SEEK_CUR);
}
diff --git a/lib/rbcodec/metadata/id3tags.c b/lib/rbcodec/metadata/id3tags.c
index 458e24cf61..ba7695d569 100644
--- a/lib/rbcodec/metadata/id3tags.c
+++ b/lib/rbcodec/metadata/id3tags.c
@@ -308,24 +308,27 @@ static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos )
char *start = tag;
/* skip text encoding */
tag += 1;
+ static const char *img_options[] = {"jpeg", "jpg", "png", NULL};
if (memcmp(tag, "image/", 6) == 0)
{
/* ID3 v2.3+ */
tag += 6;
- if (strcmp(tag, "jpeg") == 0)
+ int tg_op = string_option(tag, img_options, false);
+
+ if (tg_op == 0) /*jpeg*/
{
entry->albumart.type = AA_TYPE_JPG;
tag += 5;
}
- else if (strcmp(tag, "jpg") == 0)
+ else if (tg_op == 1) /*jpg*/
{
/* image/jpg is technically invalid, but it does occur in
* the wild */
entry->albumart.type = AA_TYPE_JPG;
tag += 4;
}
- else if (strcmp(tag, "png") == 0)
+ else if (tg_op == 2) /*png*/
{
entry->albumart.type = AA_TYPE_PNG;
tag += 4;
@@ -434,9 +437,11 @@ static int parserva2( struct mp3entry* entry, char* tag, int bufferpos)
}
}
- if (strcasecmp(tag, "album") == 0) {
+ static const char *tg_options[] = {"album", "track", NULL};
+ int tg_op = string_option(tag, tg_options, true);
+ if (tg_op == 0) { /*album*/
album = true;
- } else if (strcasecmp(tag, "track") != 0) {
+ } else if (tg_op != 1) { /*!track*/
/* Only accept non-track values if we don't have any previous
* value.
*/
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c
index aec72db97f..19147ccdb3 100644
--- a/lib/rbcodec/metadata/metadata.c
+++ b/lib/rbcodec/metadata/metadata.c
@@ -458,44 +458,6 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
return true;
}
-#ifndef __PCTOOL__
-void strip_tags(int handle_id)
-{
- static const unsigned char tag[] = "TAG";
- static const unsigned char apetag[] = "APETAGEX";
- size_t len, version;
- void *tail;
-
- if (bufgettail(handle_id, 128, &tail) != 128)
- return;
-
- if (memcmp(tail, tag, 3) == 0)
- {
- /* Skip id3v1 tag */
- logf("Cutting off ID3v1 tag");
- bufcuttail(handle_id, 128);
- }
-
- /* Get a new tail, as the old one may have been cut */
- if (bufgettail(handle_id, 32, &tail) != 32)
- return;
-
- /* Check for APE tag (look for the APE tag footer) */
- if (memcmp(tail, apetag, 8) != 0)
- return;
-
- /* Read the version and length from the footer */
- version = get_long_le(&((unsigned char *)tail)[8]);
- len = get_long_le(&((unsigned char *)tail)[12]);
- if (version == 2000)
- len += 32; /* APEv2 has a 32 byte header */
-
- /* Skip APE tag */
- logf("Cutting off APE tag (%ldB)", len);
- bufcuttail(handle_id, len);
-}
-#endif /* ! __PCTOOL__ */
-
#define MOVE_ENTRY(x) if (x) x += offset;
void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig)
diff --git a/lib/rbcodec/metadata/metadata.h b/lib/rbcodec/metadata/metadata.h
index 50fd5bac86..1a205a08eb 100644
--- a/lib/rbcodec/metadata/metadata.h
+++ b/lib/rbcodec/metadata/metadata.h
@@ -333,7 +333,6 @@ void wipe_mp3entry(struct mp3entry *id3);
void fill_metadata_from_path(struct mp3entry *id3, const char *trackname);
int get_audio_base_codec_type(int type);
-void strip_tags(int handle_id);
bool rbcodec_format_is_atomic(int afmt);
bool format_buffers_with_offset(int afmt);
diff --git a/lib/rbcodec/metadata/metadata_common.c b/lib/rbcodec/metadata/metadata_common.c
index 6fc50e9a9d..8eec16a877 100644
--- a/lib/rbcodec/metadata/metadata_common.c
+++ b/lib/rbcodec/metadata/metadata_common.c
@@ -252,6 +252,26 @@ bool skip_id3v2(int fd, struct mp3entry *id3)
return success;
}
+#if !defined(ROCKBOX) || defined(WARBLE) /*codecs can be built without rockbox */
+/* returns match index from option list
+ * returns -1 if option was not found
+ * option list is array of char pointers with the final item set to null
+ * ex - const char *option[] = { "op_a", "op_b", "op_c", NULL}
+ */
+int string_option(const char *option, const char *const oplist[], bool ignore_case)
+{
+ const char *op;
+ int (*cmp_fn)(const char*, const char*) = &strcasecmp;
+ if (!ignore_case)
+ cmp_fn = strcmp;
+ for (int i=0; (op=oplist[i]) != NULL; i++)
+ {
+ if (cmp_fn(op, option) == 0)
+ return i;
+ }
+ return -1;
+}
+#endif
/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
* String values to keep are written to buf. Returns number of bytes written
* to buf (including end nil).
@@ -262,19 +282,44 @@ long parse_tag(const char* name, char* value, struct mp3entry* id3,
long len = 0;
char** p;
- if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE)))
- || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS)))
+ enum
+ {
+ eTRACK = 0, eTRACKNUMBER, eDISCNUMBER, eDISC,
+ eYEAR, eDATE, eTITLE, eARTIST, eALBUM, eGENRE,
+ eCOMPOSER, eCOMMENT, eALBUMARTIST, eALBUM_ARTIST,
+ eENSEMBLE, eGROUPING, eCONTENTGROUP, eCONTENT_GROUP,
+ eMUSICBRAINZ1, eMUSICBRAINZ2, e_COUNT_TAG_COUNT
+ };
+
+ static const char *tagops[e_COUNT_TAG_COUNT + 1] =
+ { [eTRACK] = "track", [eTRACKNUMBER] = "tracknumber",
+ [eDISCNUMBER] = "discnumber", [eDISC] = "disc",
+ [eYEAR] = "year", [eDATE] = "date", [eTITLE] = "title",
+ [eARTIST] = "artist", [eALBUM] = "album", [eGENRE] = "genre",
+ [eCOMPOSER] = "composer", [eCOMMENT] = "comment",
+ [eALBUMARTIST] = "albumartist", [eALBUM_ARTIST] ="album artist",
+ [eENSEMBLE] = "ensemble", [eGROUPING] = "grouping",
+ [eCONTENTGROUP] = "contentgroup", [eCONTENT_GROUP] = "content group",
+ [eMUSICBRAINZ1] = "musicbrainz_trackid",
+ [eMUSICBRAINZ2] = "http://musicbrainz.org",
+ [e_COUNT_TAG_COUNT] = NULL
+ };
+
+ int item = string_option(name, tagops, true);
+
+ if (((item == eTRACK && (type == TAGTYPE_APE)))
+ || (item == eTRACKNUMBER && (type == TAGTYPE_VORBIS)))
{
id3->tracknum = atoi(value);
p = &(id3->track_string);
}
- else if (strcasecmp(name, "discnumber") == 0 || strcasecmp(name, "disc") == 0)
+ else if (item == eDISCNUMBER || item == eDISC)
{
id3->discnum = atoi(value);
p = &(id3->disc_string);
}
- else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE))
- || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS)))
+ else if ((item == eYEAR && (type == TAGTYPE_APE))
+ || (item == eDATE && (type == TAGTYPE_VORBIS)))
{
/* Date's can be in any format in Vorbis. However most of them
* are in ISO8601 format so if we try and parse the first part
@@ -288,56 +333,39 @@ long parse_tag(const char* name, char* value, struct mp3entry* id3,
}
p = &(id3->year_string);
}
- else if (strcasecmp(name, "title") == 0)
+ else if (item == eTITLE)
{
p = &(id3->title);
}
- else if (strcasecmp(name, "artist") == 0)
+ else if (item == eARTIST)
{
p = &(id3->artist);
}
- else if (strcasecmp(name, "album") == 0)
+ else if (item == eALBUM)
{
p = &(id3->album);
}
- else if (strcasecmp(name, "genre") == 0)
+ else if (item == eGENRE)
{
p = &(id3->genre_string);
}
- else if (strcasecmp(name, "composer") == 0)
+ else if (item == eCOMPOSER)
{
p = &(id3->composer);
}
- else if (strcasecmp(name, "comment") == 0)
+ else if (item == eCOMMENT)
{
p = &(id3->comment);
}
- else if (strcasecmp(name, "albumartist") == 0)
- {
- p = &(id3->albumartist);
- }
- else if (strcasecmp(name, "album artist") == 0)
+ else if (item == eALBUMARTIST || item == eALBUM_ARTIST || item == eENSEMBLE)
{
p = &(id3->albumartist);
}
- else if (strcasecmp(name, "ensemble") == 0)
- {
- p = &(id3->albumartist);
- }
- else if (strcasecmp(name, "grouping") == 0)
- {
- p = &(id3->grouping);
- }
- else if (strcasecmp(name, "content group") == 0)
- {
- p = &(id3->grouping);
- }
- else if (strcasecmp(name, "contentgroup") == 0)
+ else if (item == eGROUPING || item == eCONTENTGROUP || item == eCONTENT_GROUP)
{
p = &(id3->grouping);
}
- else if (strcasecmp(name, "musicbrainz_trackid") == 0
- || strcasecmp(name, "http://musicbrainz.org") == 0 )
+ else if (item == eMUSICBRAINZ1 || item == eMUSICBRAINZ2)
{
p = &(id3->mb_track_id);
}
diff --git a/lib/rbcodec/metadata/metadata_common.h b/lib/rbcodec/metadata/metadata_common.h
index db91729de4..0f6fcb279c 100644
--- a/lib/rbcodec/metadata/metadata_common.h
+++ b/lib/rbcodec/metadata/metadata_common.h
@@ -30,7 +30,8 @@
#define TAG_NAME_LENGTH 32
#define TAG_VALUE_LENGTH 128
-#define FOURCC(a,b,c,d) (((a)<<24) | ((b) << 16) | ((c) << 8) | (d))
+#define FOURCC(a,b,c,d) ((((unsigned long)(a)) << 24) | (((unsigned long)(b)) << 16) | \
+ (((unsigned long)(c)) << 8) | ((unsigned long)(d)))
enum tagtype { TAGTYPE_APE = 1, TAGTYPE_VORBIS };
@@ -38,6 +39,7 @@ bool read_ape_tags(int fd, struct mp3entry* id3);
long read_vorbis_tags(int fd, struct mp3entry *id3,
long tag_remaining);
+int string_option(const char *option, const char *const oplist[], bool ignore_case);
bool skip_id3v2(int fd, struct mp3entry *id3);
long read_string(int fd, char* buf, long buf_size, int eos, long size);
diff --git a/lib/rbcodec/metadata/mp4.c b/lib/rbcodec/metadata/mp4.c
index 41f38480b1..19e6b515c7 100644
--- a/lib/rbcodec/metadata/mp4.c
+++ b/lib/rbcodec/metadata/mp4.c
@@ -195,7 +195,7 @@ static unsigned int read_mp4_length(int fd, uint32_t* size)
{
unsigned int length = 0;
int bytes = 0;
- unsigned char c;
+ unsigned char c = '\0';
do
{
@@ -211,7 +211,7 @@ static unsigned int read_mp4_length(int fd, uint32_t* size)
static bool read_mp4_esds(int fd, struct mp3entry* id3, uint32_t* size)
{
- unsigned char buf[8];
+ unsigned char buf[8] = {0};
bool sbr = false;
lseek(fd, 4, SEEK_CUR); /* Version and flags. */
@@ -533,13 +533,18 @@ static bool read_mp4_tags(int fd, struct mp3entry* id3,
rd_ret = 0;
tag_name[rd_ret] = 0;
+ static const char *tn_options[] = {"composer", "iTunSMPB",
+ "musicbrainz track id", "album artist", NULL};
- if ((strcasecmp(tag_name, "composer") == 0) && !cwrt)
+ int tn_op = string_option(tag_name, tn_options, true);
+
+
+ if (tn_op == 0 && !cwrt) /*composer*/
{
read_mp4_tag_string(fd, size, &buffer, &buffer_left,
&id3->composer);
}
- else if (strcasecmp(tag_name, "iTunSMPB") == 0)
+ else if (tn_op == 1) /*iTunSMPB*/
{
char value[TAG_VALUE_LENGTH];
char* value_p = value;
@@ -552,12 +557,12 @@ static bool read_mp4_tags(int fd, struct mp3entry* id3,
DEBUGF("AAC: lead_trim %d, tail_trim %d\n",
id3->lead_trim, id3->tail_trim);
}
- else if (strcasecmp(tag_name, "musicbrainz track id") == 0)
+ else if (tn_op == 2) /*musicbrainz track id*/
{
read_mp4_tag_string(fd, size, &buffer, &buffer_left,
&id3->mb_track_id);
}
- else if ((strcasecmp(tag_name, "album artist") == 0))
+ else if (tn_op == 3) /*album artist*/
{
read_mp4_tag_string(fd, size, &buffer, &buffer_left,
&id3->albumartist);
@@ -784,8 +789,8 @@ static bool read_mp4_container(int fd, struct mp3entry* id3,
{
/* ADDME: add support for real chapters. Right now it's only
* used for Nero's gapless hack */
- uint8_t chapters;
- uint64_t timestamp;
+ uint8_t chapters = 0;
+ uint64_t timestamp = 0;
lseek(fd, 8, SEEK_CUR);
read_uint8(fd, &chapters);
diff --git a/lib/rbcodec/metadata/replaygain.c b/lib/rbcodec/metadata/replaygain.c
index 7aa77cfedd..eb98bbc342 100644
--- a/lib/rbcodec/metadata/replaygain.c
+++ b/lib/rbcodec/metadata/replaygain.c
@@ -32,6 +32,7 @@
#include "debug.h"
#include "replaygain.h"
#include "fixedpoint.h"
+#include "metadata_common.h"
#define FP_BITS (12)
#define FP_ONE (1 << FP_BITS)
@@ -167,29 +168,29 @@ long get_replaygain_int(long int_gain)
void parse_replaygain(const char* key, const char* value,
struct mp3entry* entry)
{
- if (((strcasecmp(key, "replaygain_track_gain") == 0) ||
- (strcasecmp(key, "rg_radio") == 0)) &&
- !entry->track_gain)
- {
+ static const char *rg_options[] = {"replaygain_track_gain", "rg_radio",
+ "replaygain_album_gain", "rg_audiophile",
+ "replaygain_track_peak", "rg_peak",
+ "replaygain_album_peak", NULL};
+
+ int rg_op = string_option(key, rg_options, true);
+
+ if ((rg_op == 0 || rg_op == 1) && !entry->track_gain)
+ { /*replaygain_track_gain||rg_radio*/
entry->track_level = get_replaygain(value);
entry->track_gain = convert_gain(entry->track_level);
}
- else if (((strcasecmp(key, "replaygain_album_gain") == 0) ||
- (strcasecmp(key, "rg_audiophile") == 0)) &&
- !entry->album_gain)
- {
+ else if ((rg_op == 2 || rg_op == 3) && !entry->album_gain)
+ { /*replaygain_album_gain||rg_audiophile*/
entry->album_level = get_replaygain(value);
entry->album_gain = convert_gain(entry->album_level);
}
- else if (((strcasecmp(key, "replaygain_track_peak") == 0) ||
- (strcasecmp(key, "rg_peak") == 0)) &&
- !entry->track_peak)
- {
+ else if ((rg_op == 4 || rg_op == 5) && !entry->track_peak)
+ { /*replaygain_track_peak||rg_peak*/
entry->track_peak = get_replaypeak(value);
}
- else if ((strcasecmp(key, "replaygain_album_peak") == 0) &&
- !entry->album_peak)
- {
+ else if ((rg_op == 6) && !entry->album_peak)
+ { /*replaygain_album_peak*/
entry->album_peak = get_replaypeak(value);
}
}
diff --git a/lib/skin_parser/skin_buffer.c b/lib/skin_parser/skin_buffer.c
index d18122ef20..021746ba82 100644
--- a/lib/skin_parser/skin_buffer.c
+++ b/lib/skin_parser/skin_buffer.c
@@ -80,8 +80,8 @@ void* skin_buffer_alloc(size_t size)
{
void *retval = NULL;
#endif
- /* 32-bit aligned */
- size = (size + 3) & ~3;
+ /* align to long which is enough for most types */
+ size = (size + sizeof(long) - 1) & ~(sizeof(long) - 1);
if (size > skin_buffer_freespace())
{
skin_error(MEMORY_LIMIT_EXCEEDED, NULL);
diff --git a/lib/unwarminder/backtrace-unwarminder.c b/lib/unwarminder/backtrace-unwarminder.c
index 7808a1f2d7..e36557a07c 100644
--- a/lib/unwarminder/backtrace-unwarminder.c
+++ b/lib/unwarminder/backtrace-unwarminder.c
@@ -108,7 +108,8 @@ Boolean CliInvalidateW(const Int32 a)
void rb_backtrace(int pcAddr, int spAddr, unsigned *line)
{
- lcd_putsf(0, (*line)++, "pc:%08x sp:%08x", pcAddr, spAddr);
+ lcd_putsf(0, (*line)++, "pc:%08x", pcAddr);
+ lcd_putsf(0, (*line)++, "sp:%08x", spAddr);
lcd_update();
UnwindStart(pcAddr, spAddr, &cliCallbacks, (void *)line);
diff --git a/lib/x1000-installer/src/xf_nandio.c b/lib/x1000-installer/src/xf_nandio.c
index ba79cbbcbf..29ff9d9120 100644
--- a/lib/x1000-installer/src/xf_nandio.c
+++ b/lib/x1000-installer/src/xf_nandio.c
@@ -51,7 +51,7 @@ int xf_nandio_init(struct xf_nandio* nio)
alloc_size += CACHEALIGN_SIZE - 1;
alloc_size += nio->block_size * 2;
- nio->alloc_handle = core_alloc("xf_nandio", alloc_size);
+ nio->alloc_handle = core_alloc_ex("xf_nandio", alloc_size, &buflib_ops_locked);
if(nio->alloc_handle < 0) {
rc = XF_E_OUT_OF_MEMORY;
goto out_nclose;
diff --git a/lib/x1000-installer/src/xf_package.c b/lib/x1000-installer/src/xf_package.c
index 78bddded68..04b32cdcb0 100644
--- a/lib/x1000-installer/src/xf_package.c
+++ b/lib/x1000-installer/src/xf_package.c
@@ -49,7 +49,7 @@ static int pkg_alloc(struct xf_package* pkg)
alloc_size += ALIGN_UP_P2(METADATA_SIZE, 3);
alloc_size += 7; /* for alignment */
- pkg->alloc_handle = core_alloc("xf_package", alloc_size);
+ pkg->alloc_handle = core_alloc_ex("xf_package", alloc_size, &buflib_ops_locked);
if(pkg->alloc_handle < 0)
return XF_E_OUT_OF_MEMORY;
diff --git a/lib/x1000-installer/test_lib/core_alloc.c b/lib/x1000-installer/test_lib/core_alloc.c
index 5d4edb03f7..719670f8f2 100644
--- a/lib/x1000-installer/test_lib/core_alloc.c
+++ b/lib/x1000-installer/test_lib/core_alloc.c
@@ -25,6 +25,7 @@
#define N_POINTERS 100
static void* pointers[N_POINTERS];
+struct buflib_callbacks buflib_ops_locked = {NULL, NULL, NULL};
int core_alloc(const char* name, size_t size)
{
@@ -46,6 +47,12 @@ int core_alloc(const char* name, size_t size)
return -1;
}
+int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks* cb)
+{
+ (void)cb;
+ return core_alloc(name, size);
+}
+
int core_free(int handle)
{
if(handle > 0) {
diff --git a/lib/x1000-installer/test_lib/core_alloc.h b/lib/x1000-installer/test_lib/core_alloc.h
index 6fb06649fb..2c77e3c274 100644
--- a/lib/x1000-installer/test_lib/core_alloc.h
+++ b/lib/x1000-installer/test_lib/core_alloc.h
@@ -25,8 +25,18 @@
#define CORE_ALLOC_H
#include <stddef.h>
+#include <stdbool.h>
+
+struct buflib_callbacks {
+ int (*move_callback)(int handle, void* current, void* new);
+ int (*shrink_callback)(int handle, unsigned hints, void* start, size_t old_size);
+ void (*sync_callback)(int handle, bool sync_on);
+};
+
+extern struct buflib_callbacks buflib_ops_locked;
int core_alloc(const char* name, size_t size);
+int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks* cb);
int core_free(int handle);
void* core_get_data(int handle);