diff options
Diffstat (limited to 'lib')
27 files changed, 691 insertions, 218 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/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); |