diff --git a/apps/tagcache.c b/apps/tagcache.c index 57bde77cf9..6ef0755809 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -69,6 +69,7 @@ #include "misc.h" #include "settings.h" #include "dircache.h" +#include "structec.h" #ifndef __PCTOOL__ #include "atoi.h" #include "splash.h" @@ -159,6 +160,12 @@ struct master_header { long serial; /* Increasing counting number */ }; +/* For the endianess correction */ +static const char *tagfile_entry_ec = "ss"; +static const char *index_entry_ec = "llllllllllllllll"; /* (1 + TAG_COUNT) * l */ +static const char *tagcache_header_ec = "lll"; +static const char *master_header_ec = "llll"; + static long current_serial; #ifdef HAVE_TC_RAMCACHE @@ -296,7 +303,7 @@ static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write) } /* Check the header. */ - rc = read(fd, hdr, sizeof(struct tagcache_header)); + rc = ecread(fd, hdr, 1, tagcache_header_ec, tc_stat.econ); if (hdr->magic != TAGCACHE_MAGIC || rc != sizeof(struct tagcache_header)) { logf("header error"); @@ -399,8 +406,8 @@ static long find_entry_disk(const char *filename) pos_history[i+1] = pos_history[i]; pos_history[0] = pos; - if (read(fd, &tfe, sizeof(struct tagfile_entry)) != - sizeof(struct tagfile_entry)) + if (ecread(fd, &tfe, 1, tagfile_entry_ec, tc_stat.econ) + != sizeof(struct tagfile_entry)) { break ; } @@ -512,8 +519,8 @@ static bool get_index(int masterfd, int idxid, lseek(masterfd, idxid * sizeof(struct index_entry) + sizeof(struct master_header), SEEK_SET); - if (read(masterfd, idx, sizeof(struct index_entry)) != - sizeof(struct index_entry)) + if (ecread(masterfd, idx, 1, index_entry_ec, tc_stat.econ) + != sizeof(struct index_entry)) { logf("read error #3"); return false; @@ -543,8 +550,8 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx) lseek(masterfd, idxid * sizeof(struct index_entry) + sizeof(struct master_header), SEEK_SET); - if (write(masterfd, idx, sizeof(struct index_entry)) != - sizeof(struct index_entry)) + if (ecwrite(masterfd, idx, 1, index_entry_ec, tc_stat.econ) + != sizeof(struct index_entry)) { logf("write error #3"); logf("idxid: %d", idxid); @@ -619,8 +626,8 @@ static bool retrieve(struct tagcache_search *tcs, struct index_entry *idx, return false; lseek(tcs->idxfd[tag], seek, SEEK_SET); - if (read(tcs->idxfd[tag], &tfe, sizeof(struct tagfile_entry)) != - sizeof(struct tagfile_entry)) + if (ecread(tcs->idxfd[tag], &tfe, 1, tagfile_entry_ec, tc_stat.econ) + != sizeof(struct tagfile_entry)) { logf("read error #5"); return false; @@ -831,7 +838,7 @@ static bool check_clauses(struct tagcache_search *tcs, { int fd = tcs->idxfd[clause[i]->tag]; lseek(fd, seek, SEEK_SET); - read(fd, &tfe, sizeof(struct tagfile_entry)); + ecread(fd, &tfe, 1, tagfile_entry_ec, tc_stat.econ); if (tfe.tag_length >= (int)sizeof(str)) { logf("Too long tag read!"); @@ -952,8 +959,8 @@ static bool build_lookup_list(struct tagcache_search *tcs) lseek(tcs->masterfd, tcs->seek_pos * sizeof(struct index_entry) + sizeof(struct master_header), SEEK_SET); - while (read(tcs->masterfd, &entry, sizeof(struct index_entry)) == - sizeof(struct index_entry)) + while (ecread(tcs->masterfd, &entry, 1, index_entry_ec, tc_stat.econ) + == sizeof(struct index_entry)) { /* Check if entry has been deleted. */ if (entry.flag & FLAG_DELETED) @@ -1001,6 +1008,7 @@ static void remove_files(void) tc_stat.ready = false; tc_stat.ramcache = false; + tc_stat.econ = false; remove(TAGCACHE_FILE_MASTER); for (i = 0; i < TAG_COUNT; i++) { @@ -1026,8 +1034,20 @@ static int open_master_fd(struct master_header *hdr, bool write) return fd; } + tc_stat.econ = false; + /* Check the header. */ rc = read(fd, hdr, sizeof(struct master_header)); + if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header)) + { + /* Success. */ + return fd; + } + + /* Trying to read again, this time with endianess correction enabled. */ + lseek(fd, 0, SEEK_SET); + + rc = ecread(fd, hdr, 1, master_header_ec, true); if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header)) { logf("header error"); @@ -1035,6 +1055,8 @@ static int open_master_fd(struct master_header *hdr, bool write) close(fd); return -2; } + + tc_stat.econ = true; return fd; } @@ -1260,8 +1282,8 @@ static bool get_next(struct tagcache_search *tcs) return false; tcs->result_seek = lseek(tcs->idxfd[tcs->type], 0, SEEK_CUR); - if (read(tcs->idxfd[tcs->type], &entry, sizeof(struct tagfile_entry)) != - sizeof(struct tagfile_entry)) + if (ecread(tcs->idxfd[tcs->type], &entry, 1, + tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry)) { /* End of data. */ tcs->valid = false; @@ -1739,7 +1761,7 @@ static int tempbuf_sort(int fd) } #endif - if (write(fd, &fe, sizeof(struct tagfile_entry)) != + if (ecwrite(fd, &fe, 1, tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry)) { logf("tempbuf_sort: write error #1"); @@ -1833,8 +1855,8 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) { int loc = lseek(masterfd, 0, SEEK_CUR); - if (read(masterfd, &idx, sizeof(struct index_entry)) != - sizeof(struct index_entry)) + if (ecread(masterfd, &idx, 1, index_entry_ec, tc_stat.econ) + != sizeof(struct index_entry)) { logf("read fail #2"); close(masterfd); @@ -1852,8 +1874,8 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) /* Write back the updated index. */ lseek(masterfd, loc, SEEK_SET); - if (write(masterfd, &idx, sizeof(struct index_entry)) != - sizeof(struct index_entry)) + if (ecwrite(masterfd, &idx, 1, index_entry_ec, tc_stat.econ) + != sizeof(struct index_entry)) { logf("write fail"); close(masterfd); @@ -1977,7 +1999,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) int loc = lseek(fd, 0, SEEK_CUR); bool ret; - if (read(fd, &entry, sizeof(struct tagfile_entry)) + if (ecread(fd, &entry, 1, tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry)) { logf("read error #7"); @@ -2041,8 +2063,8 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) tch.entry_count = 0; tch.datasize = 0; - if (write(fd, &tch, sizeof(struct tagcache_header)) != - sizeof(struct tagcache_header)) + if (ecwrite(fd, &tch, 1, tagcache_header_ec, tc_stat.econ) + != sizeof(struct tagcache_header)) { logf("header write failed"); close(fd); @@ -2071,7 +2093,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) tcmh.tch = *h; tcmh.tch.entry_count = 0; tcmh.tch.datasize = 0; - write(masterfd, &tcmh, sizeof(struct master_header)); + ecwrite(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ); init = true; masterfd_pos = lseek(masterfd, 0, SEEK_CUR); current_serial = 0; @@ -2084,7 +2106,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) */ init = false; - if (read(masterfd, &tcmh, sizeof(struct master_header)) != + if (ecread(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ) != sizeof(struct master_header) || tcmh.tch.magic != TAGCACHE_MAGIC) { logf("header error"); @@ -2125,7 +2147,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) != sizeof(struct temp_file_entry)) { - logf("read fail #1"); + logf("read fail #3"); error = true; goto error_exit; } @@ -2142,7 +2164,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) if (read(tmpfd, buf, entry.tag_length[index_type]) != entry.tag_length[index_type]) { - logf("read fail #3"); + logf("read fail #4"); error = true; goto error_exit; } @@ -2184,10 +2206,10 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) idxbuf_pos = MIN(tcmh.tch.entry_count - i, IDX_BUF_DEPTH); - if (read(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) != - (int)sizeof(struct index_entry)*idxbuf_pos) + if (ecread(masterfd, idxbuf, idxbuf_pos, index_entry_ec, tc_stat.econ) + != (int)sizeof(struct index_entry)*idxbuf_pos) { - logf("read fail #2"); + logf("read fail #5"); error = true; goto error_exit ; } @@ -2217,7 +2239,8 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) } /* Write back the updated index. */ - if (write(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) != + if (ecwrite(masterfd, idxbuf, idxbuf_pos, + index_entry_ec, tc_stat.econ) != (int)sizeof(struct index_entry)*idxbuf_pos) { logf("write fail"); @@ -2249,10 +2272,10 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) { int loc = lseek(masterfd, 0, SEEK_CUR); - if (read(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) != - (int)sizeof(struct index_entry)*idxbuf_pos) + if (ecread(masterfd, idxbuf, idxbuf_pos, index_entry_ec, tc_stat.econ) + != (int)sizeof(struct index_entry)*idxbuf_pos) { - logf("read fail #2"); + logf("read fail #6"); error = true; break ; } @@ -2270,7 +2293,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) != sizeof(struct temp_file_entry)) { - logf("read fail #1"); + logf("read fail #7"); error = true; break ; } @@ -2289,7 +2312,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) if (read(tmpfd, buf, entry.tag_length[index_type]) != entry.tag_length[index_type]) { - logf("read fail #3"); + logf("read fail #8"); logf("offset=0x%02x", entry.tag_offset[index_type]); logf("length=0x%02x", entry.tag_length[index_type]); error = true; @@ -2300,7 +2323,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) idxbuf[j].tag_seek[index_type] = lseek(fd, 0, SEEK_CUR); fe.tag_length = entry.tag_length[index_type]; fe.idx_id = tcmh.tch.entry_count + i + j; - write(fd, &fe, sizeof(struct tagfile_entry)); + ecwrite(fd, &fe, 1, tagfile_entry_ec, tc_stat.econ); write(fd, buf, fe.tag_length); tempbufidx++; @@ -2322,7 +2345,8 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) } /* Write index. */ - if (write(masterfd, idxbuf, sizeof(struct index_entry)*idxbuf_pos) != + if (ecwrite(masterfd, idxbuf, idxbuf_pos, + index_entry_ec, tc_stat.econ) != (int)sizeof(struct index_entry)*idxbuf_pos) { logf("tagcache: write fail #4"); @@ -2339,7 +2363,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) tch.entry_count = tempbufidx; tch.datasize = lseek(fd, 0, SEEK_END) - sizeof(struct tagcache_header); lseek(fd, 0, SEEK_SET); - write(fd, &tch, sizeof(struct tagcache_header)); + ecwrite(fd, &tch, 1, tagcache_header_ec, tc_stat.econ); if (index_type != tag_filename) h->datasize += tch.datasize; @@ -2495,7 +2519,7 @@ static bool commit(void) + tch.datasize; lseek(masterfd, 0, SEEK_SET); - write(masterfd, &tcmh, sizeof(struct master_header)); + ecwrite(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ); close(masterfd); logf("tagcache committed"); @@ -2570,7 +2594,7 @@ static bool update_current_serial(long serial) /* Write it back */ lseek(fd, 0, SEEK_SET); - write(fd, &myhdr, sizeof(struct master_header)); + ecwrite(fd, &myhdr, 1, master_header_ec, tc_stat.econ); close(fd); return true; @@ -2872,14 +2896,14 @@ bool tagcache_create_changelog(struct tagcache_search *tcs) else { lseek(tcs->masterfd, 0, SEEK_SET); - read(tcs->masterfd, &myhdr, sizeof(struct master_header)); + ecread(tcs->masterfd, &myhdr, 1, master_header_ec, tc_stat.econ); } write(clfd, "## Changelog version 1\n", 23); for (i = 0; i < myhdr.tch.entry_count; i++) { - if (read(tcs->masterfd, &idx, sizeof(struct index_entry)) + if (ecread(tcs->masterfd, &idx, 1, index_entry_ec, tc_stat.econ) != sizeof(struct index_entry)) { logf("read error #9"); @@ -2943,7 +2967,7 @@ static bool delete_entry(long idx_id) return false; lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR); - if (read(fd, &myidx, sizeof(struct index_entry)) + if (ecread(fd, &myidx, 1, index_entry_ec, tc_stat.econ) != sizeof(struct index_entry)) { logf("delete_entry(): read error"); @@ -2953,7 +2977,7 @@ static bool delete_entry(long idx_id) myidx.flag |= FLAG_DELETED; lseek(fd, -sizeof(struct index_entry), SEEK_CUR); - if (write(fd, &myidx, sizeof(struct index_entry)) + if (ecwrite(fd, &myidx, 1, index_entry_ec, tc_stat.econ) != sizeof(struct index_entry)) { logf("delete_entry(): write_error"); @@ -2968,7 +2992,7 @@ static bool delete_entry(long idx_id) lseek(fd, sizeof(struct master_header), SEEK_SET); for (i = 0; i < myhdr.tch.entry_count; i++) { - if (read(fd, &idx, sizeof(struct index_entry)) + if (ecread(fd, &idx, 1, index_entry_ec, tc_stat.econ) != sizeof(struct index_entry)) { logf("delete_entry(): read error #2"); @@ -3190,7 +3214,7 @@ static bool load_tagcache(void) return false; } - if (read(fd, &hdr->h, sizeof(struct master_header)) + if (ecread(fd, &hdr->h, 1, master_header_ec, tc_stat.econ) != sizeof(struct master_header) || hdr->h.tch.magic != TAGCACHE_MAGIC) { @@ -3203,7 +3227,7 @@ static bool load_tagcache(void) /* Load the master index table. */ for (i = 0; i < hdr->h.tch.entry_count; i++) { - rc = read(fd, idx, sizeof(struct index_entry)); + rc = ecread(fd, idx, 1, index_entry_ec, tc_stat.econ); if (rc != sizeof(struct index_entry)) { logf("read error #10"); @@ -3262,7 +3286,7 @@ static bool load_tagcache(void) fe = (struct tagfile_entry *)p; pos = lseek(fd, 0, SEEK_CUR); - rc = read(fd, fe, sizeof(struct tagfile_entry)); + rc = ecread(fd, fe, 1, tagfile_entry_ec, tc_stat.econ); if (rc != sizeof(struct tagfile_entry)) { /* End of lookup table. */ @@ -3413,7 +3437,7 @@ static bool check_deleted_files(void) } lseek(fd, sizeof(struct tagcache_header), SEEK_SET); - while (read(fd, &tfe, sizeof(struct tagfile_entry)) + while (ecread(fd, &tfe, 1, tagfile_entry_ec, tc_stat.econ) == sizeof(struct tagfile_entry) #ifndef __PCTOOL__ && !check_event_queue() @@ -3443,7 +3467,7 @@ static bool check_deleted_files(void) if (testfd < 0) { logf("Entry no longer valid."); - logf("-> %s", buf); + logf("-> %s / %d", buf, tfe.tag_length); delete_entry(tfe.idx_id); } close(testfd); diff --git a/apps/tagcache.h b/apps/tagcache.h index 503da8c1eb..5140aa1989 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -88,6 +88,7 @@ struct tagcache_stat { bool ready; /* Is tagcache ready to be used? */ bool ramcache; /* Is tagcache loaded in ram? */ bool commit_delayed; /* Has commit been delayed until next reboot? */ + bool econ; /* Is endianess correction enabled? */ int commit_step; /* Commit progress */ int ramcache_allocated; /* Has ram been allocated for ramcache? */ int ramcache_used; /* How much ram has been really used */ diff --git a/firmware/SOURCES b/firmware/SOURCES index 15e8cf0603..d4447c22cc 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -53,6 +53,7 @@ common/strncmp.c common/strncpy.c common/strrchr.c common/strtok.c +common/structec.c common/timefuncs.c common/unicode.c diff --git a/firmware/common/structec.c b/firmware/common/structec.c new file mode 100644 index 0000000000..ec7e1409fd --- /dev/null +++ b/firmware/common/structec.c @@ -0,0 +1,179 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 by Miika Pekkarinen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include "structec.h" +#include "system.h" +#include "file.h" + +#define MAX_STRUCT_SIZE 128 + +/** + * Convert the struct endianess with the instructions provided. + * + * For example: + * struct test { + * long par1; + * short par2; + * short par3; + * }; + * + * structec_convert(instance_of_test, "lss", sizeof(struct test), true); + * + * Structures to be converted must be properly padded. + * + * @param structure Pointer to the struct being converted. + * @param ecinst Instructions how to do the endianess conversion. + * @param count Number of structures to write + * @param enable Conversion is not made unless this is true. + */ +void structec_convert(void *structure, const char *ecinst, + long count, bool enable) +{ + const char *ecinst_ring = ecinst; + char *buf = (char *)structure; + + if (!enable) + return; + + while (count > 0) + { + switch (*ecinst_ring) + { + /* Swap nothing. */ + case 'c': + { + buf++; + break; + } + + /* Swap 2 bytes. */ + case 's': + { + unsigned short *data = (unsigned short *)buf; + *data = SWAP_16(*data); + buf += 2; + break; + } + + /* Swap 4 bytes. */ + case 'l': + { + unsigned long *data = (unsigned long *)buf; + *data = SWAP_32(*data); + buf += 4; + break; + } + + /* This should be never reached. */ + default: + break; + } + + ecinst_ring++; + if (*ecinst_ring == '\0') + { + ecinst_ring = ecinst; + count--; + } + } +} + +/** + * Determines the size of a struct in bytes by using endianess correction + * string format. + * + * @param ecinst endianess correction string. + * @return length of the struct in bytes. + */ +size_t structec_size(const char *ecinst) +{ + size_t size = 0; + + do + { + switch (*ecinst) + { + case 'c': size += 1; break; + case 's': size += 2; break; + case 'l': size += 4; break; + default: break; + } + } while (*(++ecinst) != '\0'); + + return size; +} + +/** + * Reads endianess corrected structure members from the given file. + * + * @param fd file descriptor of the file being read. + * @param buf endianess corrected data is placed here. + * @param scount the number of struct members to read. + * @param ecinst endianess correction string. + * @param ec if true, endianess correction is enabled. + */ +ssize_t ecread(int fd, void *buf, size_t scount, const char *ecinst, bool ec) +{ + ssize_t ret; + size_t member_size = structec_size(ecinst); + + ret = read(fd, buf, scount * member_size); + structec_convert(buf, ecinst, scount, ec); + + return ret; +} + +/** + * Writes endianess corrected structure members to the given file. + * + * @param fd file descriptor of the file being written to. + * @param buf endianess corrected data is read here. + * @param scount the number of struct members to write. + * @param ecinst endianess correction string. + * @param ec if true, endianess correction is enabled. + */ +ssize_t ecwrite(int fd, const void *buf, size_t scount, + const char *ecinst, bool ec) +{ + char tmp[MAX_STRUCT_SIZE]; + size_t member_size = structec_size(ecinst); + + if (ec) + { + const char *p = (const char *)buf; + int maxamount = (int)(MAX_STRUCT_SIZE / member_size); + int i; + + for (i = 0; i < (long)scount; i += maxamount) + { + long amount = MIN((int)scount-i, maxamount); + + memcpy(tmp, p, member_size * amount); + structec_convert(tmp, ecinst, amount, true); + write(fd, tmp, amount * member_size); + p += member_size * amount; + } + + return scount * member_size; + } + + return write(fd, buf, scount * member_size); +} + diff --git a/firmware/export/structec.h b/firmware/export/structec.h new file mode 100644 index 0000000000..de406f9f99 --- /dev/null +++ b/firmware/export/structec.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 by Miika Pekkarinen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _STRUCTEC_H +#define _STRUCTEC_H + +#include +#include + +void structec_convert(void *structure, const char *ecinst, + long count, bool enable); +ssize_t ecread(int fd, void *buf, size_t scount, const char *ecinst, bool ec); +ssize_t ecwrite(int fd, const void *buf, size_t scount, const char *ecinst, bool ec); +#endif + diff --git a/tools/Makefile b/tools/Makefile index e477f7fc43..d957f75327 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -41,7 +41,8 @@ ipod_fw: ipod_fw.c database: database.c ../apps/tagcache.c ../apps/metadata.c \ ../firmware/id3.c ../firmware/common/unicode.c \ ../firmware/common/crc32.c ../uisimulator/common/io.c \ -../firmware/mp3data.c ../firmware/logf.c ../firmware/replaygain.c +../firmware/mp3data.c ../firmware/logf.c ../firmware/replaygain.c \ +../firmware/common/structec.c $(SILENT)$(CC) -g -I../firmware/export -iquote ../firmware/include \ -D__PCTOOL__ -DHAVE_TAGCACHE -DROCKBOX_HAS_LOGF -DSIMULATOR \ -DCONFIG_CODEC=1 -ldl -I../apps $+ -o $@