summaryrefslogtreecommitdiff
path: root/apps/tagcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/tagcache.c')
-rw-r--r--apps/tagcache.c246
1 files changed, 231 insertions, 15 deletions
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 5214e508e8..bc463ab142 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -32,6 +32,7 @@
32#include "lang.h" 32#include "lang.h"
33#include "tagcache.h" 33#include "tagcache.h"
34#include "buffer.h" 34#include "buffer.h"
35#include "atoi.h"
35 36
36/* Tag Cache thread. */ 37/* Tag Cache thread. */
37static struct event_queue tagcache_queue; 38static struct event_queue tagcache_queue;
@@ -50,8 +51,9 @@ static long tempbuf_left; /* Buffer space left. */
50static long tempbuf_pos; 51static long tempbuf_pos;
51 52
52/* Tags we want to get sorted (loaded to the tempbuf). */ 53/* Tags we want to get sorted (loaded to the tempbuf). */
53static const int sorted_tags[] = { tag_artist, tag_album, tag_genre, tag_title }; 54static const int sorted_tags[] = { tag_artist, tag_album, tag_genre, tag_composer, tag_title };
54static const int unique_tags[] = { tag_artist, tag_album, tag_genre }; 55static const int unique_tags[] = { tag_artist, tag_album, tag_genre, tag_composer };
56static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, tag_bitrate };
55 57
56/* Queue commands. */ 58/* Queue commands. */
57#define Q_STOP_SCAN 0 59#define Q_STOP_SCAN 0
@@ -63,15 +65,15 @@ static const int unique_tags[] = { tag_artist, tag_album, tag_genre };
63#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/tagcache_idx.tcd" 65#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/tagcache_idx.tcd"
64#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd" 66#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd"
65 67
68/* Tag Cache Header version 'TCHxx' */
69#define TAGCACHE_MAGIC 0x54434801
70
66/* Tag database structures. */ 71/* Tag database structures. */
67#define TAGCACHE_MAGIC 0x01020317
68 72
69/* Variable-length tag entry in tag files. */ 73/* Variable-length tag entry in tag files. */
70struct tagfile_entry { 74struct tagfile_entry {
71 short tag_length; 75 short tag_length;
72#ifdef ROCKBOX_STRICT_ALIGN 76 short idx_id;
73 short padding;
74#endif
75 char tag_data[0]; 77 char tag_data[0];
76}; 78};
77 79
@@ -118,6 +120,7 @@ struct tempbuf_id {
118 120
119struct tempbuf_searchidx { 121struct tempbuf_searchidx {
120 struct tempbuf_id *id; 122 struct tempbuf_id *id;
123 long idx_id;
121 char *str; 124 char *str;
122 int seek; 125 int seek;
123}; 126};
@@ -129,6 +132,19 @@ static int total_entry_count = 0;
129static int data_size = 0; 132static int data_size = 0;
130static int processed_dir_count; 133static int processed_dir_count;
131 134
135static bool is_numeric_tag(int type)
136{
137 int i;
138
139 for (i = 0; i < (int)(sizeof(numeric_tags)/sizeof(numeric_tags[0])); i++)
140 {
141 if (type == numeric_tags[i])
142 return true;
143 }
144
145 return false;
146}
147
132#ifdef HAVE_TC_RAMCACHE 148#ifdef HAVE_TC_RAMCACHE
133static struct index_entry *find_entry_ram(const char *filename, 149static struct index_entry *find_entry_ram(const char *filename,
134 const struct dircache_entry *dc) 150 const struct dircache_entry *dc)
@@ -308,6 +324,50 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
308 return &idx; 324 return &idx;
309} 325}
310 326
327long tagcache_get_numeric(const struct tagcache_search *tcs, int tag)
328{
329 struct tagcache_header tch;
330 struct index_entry idx;
331 int masterfd;
332
333 if (!is_numeric_tag(tag))
334 return -1;
335
336#ifdef HAVE_TC_RAMCACHE
337 if (tcs->ramsearch)
338 {
339 return hdr->indices[tcs->idx_id].tag_seek[tag];
340 }
341#endif
342
343 masterfd = open(TAGCACHE_FILE_MASTER, O_RDONLY);
344
345 if (masterfd < 0)
346 {
347 logf("open fail");
348 return -2;
349 }
350
351 if (read(masterfd, &tch, sizeof(struct tagcache_header)) !=
352 sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC)
353 {
354 logf("header error");
355 return -3;
356 }
357
358 lseek(masterfd, tcs->idx_id * sizeof(struct index_entry), SEEK_CUR);
359 if (read(masterfd, &idx, sizeof(struct index_entry)) !=
360 sizeof(struct index_entry))
361 {
362 logf("read error #3");
363 close(masterfd);
364 return -4;
365 }
366 close(masterfd);
367
368 return idx.tag_seek[tag];
369}
370
311static bool build_lookup_list(struct tagcache_search *tcs) 371static bool build_lookup_list(struct tagcache_search *tcs)
312{ 372{
313 struct tagcache_header header; 373 struct tagcache_header header;
@@ -443,6 +503,9 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
443 else 503 else
444#endif 504#endif
445 { 505 {
506 if (is_numeric_tag(tcs->type))
507 return true;
508
446 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tcs->type); 509 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tcs->type);
447 tcs->fd = open(buf, O_RDONLY); 510 tcs->fd = open(buf, O_RDONLY);
448 if (tcs->fd < 0) 511 if (tcs->fd < 0)
@@ -484,13 +547,17 @@ bool tagcache_get_next(struct tagcache_search *tcs)
484 if (!tcs->valid) 547 if (!tcs->valid)
485 return false; 548 return false;
486 549
487 if (tcs->fd < 0 550 if (tcs->fd < 0 && !is_numeric_tag(tcs->type)
488#ifdef HAVE_TC_RAMCACHE 551#ifdef HAVE_TC_RAMCACHE
489 && !tcs->ramsearch 552 && !tcs->ramsearch
490#endif 553#endif
491 ) 554 )
492 return false; 555 return false;
493 556
557 /* Searching not supported for numeric tags yet. */
558 if (is_numeric_tag(tcs->type))
559 return false;
560
494 /* Relative fetch. */ 561 /* Relative fetch. */
495 if (tcs->filter_count > 0) 562 if (tcs->filter_count > 0)
496 { 563 {
@@ -539,6 +606,7 @@ bool tagcache_get_next(struct tagcache_search *tcs)
539 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length; 606 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
540 tcs->result = ep->tag_data; 607 tcs->result = ep->tag_data;
541 tcs->result_len = ep->tag_length; 608 tcs->result_len = ep->tag_length;
609 tcs->idx_id = ep->idx_id;
542 610
543 return true; 611 return true;
544 } 612 }
@@ -571,6 +639,7 @@ bool tagcache_get_next(struct tagcache_search *tcs)
571 639
572 tcs->result = buf; 640 tcs->result = buf;
573 tcs->result_len = entry.tag_length; 641 tcs->result_len = entry.tag_length;
642 tcs->idx_id = entry.idx_id;
574 643
575 return true; 644 return true;
576} 645}
@@ -609,7 +678,7 @@ void tagcache_search_finish(struct tagcache_search *tcs)
609} 678}
610 679
611#ifdef HAVE_TC_RAMCACHE 680#ifdef HAVE_TC_RAMCACHE
612struct tagfile_entry *get_tag(struct index_entry *entry, int tag) 681static struct tagfile_entry *get_tag(struct index_entry *entry, int tag)
613{ 682{
614 return (struct tagfile_entry *)&hdr->tags[tag][entry->tag_seek[tag]]; 683 return (struct tagfile_entry *)&hdr->tags[tag][entry->tag_seek[tag]];
615} 684}
@@ -627,6 +696,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
627 id3->artist = get_tag(entry, tag_artist)->tag_data; 696 id3->artist = get_tag(entry, tag_artist)->tag_data;
628 id3->album = get_tag(entry, tag_album)->tag_data; 697 id3->album = get_tag(entry, tag_album)->tag_data;
629 id3->genre_string = get_tag(entry, tag_genre)->tag_data; 698 id3->genre_string = get_tag(entry, tag_genre)->tag_data;
699 id3->composer = get_tag(entry, tag_composer)->tag_data;
630 700
631 return true; 701 return true;
632} 702}
@@ -658,6 +728,7 @@ static void add_tagcache(const char *path)
658 struct temp_file_entry entry; 728 struct temp_file_entry entry;
659 bool ret; 729 bool ret;
660 int fd; 730 int fd;
731 char tracknumfix[3];
661 //uint32_t crcbuf[CRC_BUF_LEN]; 732 //uint32_t crcbuf[CRC_BUF_LEN];
662 733
663 if (cachefd < 0) 734 if (cachefd < 0)
@@ -689,6 +760,8 @@ static void add_tagcache(const char *path)
689 } 760 }
690 761
691 memset(&track, 0, sizeof(struct track_info)); 762 memset(&track, 0, sizeof(struct track_info));
763 memset(&entry, 0, sizeof(struct temp_file_entry));
764 memset(&tracknumfix, 0, sizeof(tracknumfix));
692 ret = get_metadata(&track, fd, path, false); 765 ret = get_metadata(&track, fd, path, false);
693 close(fd); 766 close(fd);
694 767
@@ -699,19 +772,51 @@ static void add_tagcache(const char *path)
699 check_if_empty(&track.id3.artist); 772 check_if_empty(&track.id3.artist);
700 check_if_empty(&track.id3.album); 773 check_if_empty(&track.id3.album);
701 check_if_empty(&track.id3.genre_string); 774 check_if_empty(&track.id3.genre_string);
775 check_if_empty(&track.id3.composer);
702 776
703 entry.tag_length[tag_filename] = strlen(path) + 1; 777 entry.tag_length[tag_filename] = strlen(path) + 1;
704 entry.tag_length[tag_title] = strlen(track.id3.title) + 1; 778 entry.tag_length[tag_title] = strlen(track.id3.title) + 1;
705 entry.tag_length[tag_artist] = strlen(track.id3.artist) + 1; 779 entry.tag_length[tag_artist] = strlen(track.id3.artist) + 1;
706 entry.tag_length[tag_album] = strlen(track.id3.album) + 1; 780 entry.tag_length[tag_album] = strlen(track.id3.album) + 1;
707 entry.tag_length[tag_genre] = strlen(track.id3.genre_string) + 1; 781 entry.tag_length[tag_genre] = strlen(track.id3.genre_string) + 1;
782 entry.tag_length[tag_composer] = strlen(track.id3.composer) + 1;
708 783
709 entry.tag_offset[tag_filename] = 0; 784 entry.tag_offset[tag_filename] = 0;
710 entry.tag_offset[tag_title] = entry.tag_offset[tag_filename] + entry.tag_length[tag_filename]; 785 entry.tag_offset[tag_title] = entry.tag_offset[tag_filename] + entry.tag_length[tag_filename];
711 entry.tag_offset[tag_artist] = entry.tag_offset[tag_title] + entry.tag_length[tag_title]; 786 entry.tag_offset[tag_artist] = entry.tag_offset[tag_title] + entry.tag_length[tag_title];
712 entry.tag_offset[tag_album] = entry.tag_offset[tag_artist] + entry.tag_length[tag_artist]; 787 entry.tag_offset[tag_album] = entry.tag_offset[tag_artist] + entry.tag_length[tag_artist];
713 entry.tag_offset[tag_genre] = entry.tag_offset[tag_album] + entry.tag_length[tag_album]; 788 entry.tag_offset[tag_genre] = entry.tag_offset[tag_album] + entry.tag_length[tag_album];
714 entry.data_length = entry.tag_offset[tag_genre] + entry.tag_length[tag_genre]; 789 entry.tag_offset[tag_composer] = entry.tag_offset[tag_genre] + entry.tag_length[tag_genre];
790 entry.data_length = entry.tag_offset[tag_composer] + entry.tag_length[tag_composer];
791
792 /* Numeric tags */
793 entry.tag_offset[tag_year] = track.id3.year;
794 entry.tag_offset[tag_tracknumber] = track.id3.tracknum;
795 entry.tag_offset[tag_length] = track.id3.length;
796 entry.tag_offset[tag_bitrate] = track.id3.bitrate;
797
798 if (entry.tag_offset[tag_tracknumber] <= 0)
799 {
800 int start, i;
801
802 for (start = 0; path[start] != '\0'; start++)
803 if (isdigit(path[start]))
804 break ;
805
806 for (i = 0; i < (int)sizeof(tracknumfix)-1
807 && path[start+i] != '\0'; i++)
808 {
809 if (isdigit(path[start+i]))
810 tracknumfix[i] = path[start+i];
811 else
812 break ;
813 }
814
815 if (tracknumfix[0] != '\0')
816 entry.tag_offset[tag_tracknumber] = atoi(tracknumfix);
817 else
818 entry.tag_offset[tag_tracknumber] = -1;
819 }
715 820
716 write(cachefd, &entry, sizeof(struct temp_file_entry)); 821 write(cachefd, &entry, sizeof(struct temp_file_entry));
717 write_item(path); 822 write_item(path);
@@ -719,6 +824,7 @@ static void add_tagcache(const char *path)
719 write_item(track.id3.artist); 824 write_item(track.id3.artist);
720 write_item(track.id3.album); 825 write_item(track.id3.album);
721 write_item(track.id3.genre_string); 826 write_item(track.id3.genre_string);
827 write_item(track.id3.composer);
722 total_entry_count++; 828 total_entry_count++;
723} 829}
724 830
@@ -730,12 +836,15 @@ static void remove_files(void)
730 remove(TAGCACHE_FILE_MASTER); 836 remove(TAGCACHE_FILE_MASTER);
731 for (i = 0; i < TAG_COUNT; i++) 837 for (i = 0; i < TAG_COUNT; i++)
732 { 838 {
839 if (is_numeric_tag(i))
840 continue;
841
733 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i); 842 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i);
734 remove(buf); 843 remove(buf);
735 } 844 }
736} 845}
737 846
738static bool tempbuf_insert(char *str, int id) 847static bool tempbuf_insert(char *str, int id, int idx_id)
739{ 848{
740 struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf; 849 struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf;
741 int len = strlen(str)+1; 850 int len = strlen(str)+1;
@@ -759,6 +868,7 @@ static bool tempbuf_insert(char *str, int id)
759#endif 868#endif
760 index[tempbufidx].id->id = id; 869 index[tempbufidx].id->id = id;
761 index[tempbufidx].id->next = NULL; 870 index[tempbufidx].id->next = NULL;
871 index[tempbufidx].idx_id = idx_id;
762 tempbuf_pos += sizeof(struct tempbuf_id); 872 tempbuf_pos += sizeof(struct tempbuf_id);
763 873
764 index[tempbufidx].seek = -1; 874 index[tempbufidx].seek = -1;
@@ -810,7 +920,7 @@ static bool tempbuf_unique_insert(char *str, int id)
810 } 920 }
811 } 921 }
812 922
813 return tempbuf_insert(str, id); 923 return tempbuf_insert(str, id, -1);
814} 924}
815 925
816static int compare(const void *p1, const void *p2) 926static int compare(const void *p1, const void *p2)
@@ -845,6 +955,7 @@ static int tempbuf_sort(int fd)
845 index[i].seek = lseek(fd, 0, SEEK_CUR); 955 index[i].seek = lseek(fd, 0, SEEK_CUR);
846 length = strlen(index[i].str) + 1; 956 length = strlen(index[i].str) + 1;
847 fe.tag_length = length; 957 fe.tag_length = length;
958 fe.idx_id = index[i].idx_id;
848 959
849#ifdef ROCKBOX_STRICT_ALIGN 960#ifdef ROCKBOX_STRICT_ALIGN
850 /* Make sure the entry is long aligned. */ 961 /* Make sure the entry is long aligned. */
@@ -944,6 +1055,102 @@ static bool is_sorted_tag(int type)
944 return false; 1055 return false;
945} 1056}
946 1057
1058static bool build_numeric_index(int index_type, struct tagcache_header *h, int tmpfd)
1059{
1060 struct tagcache_header tch;
1061 struct index_entry idx;
1062 int masterfd;
1063 int masterfd_pos;
1064 long *databuf = (long *)tempbuf;
1065 int max_entries;
1066 int i;
1067
1068 max_entries = tempbuf_size / sizeof(long);
1069
1070 if (h->entry_count >= max_entries)
1071 {
1072 logf("not enough space!");
1073 return false;
1074 }
1075
1076 logf("Building numeric index: %d", index_type);
1077
1078 /* Walk through the temporary file. */
1079 lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET);
1080 for (i = 0; i < h->entry_count; i++)
1081 {
1082 struct temp_file_entry entry;
1083
1084 if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) !=
1085 sizeof(struct temp_file_entry))
1086 {
1087 logf("read fail #1");
1088 return false;
1089 }
1090
1091 /* Insert data in buffer. */
1092 databuf[i] = (long)entry.tag_offset[index_type];
1093
1094 /* Skip to next. */
1095 lseek(tmpfd, entry.data_length, SEEK_CUR);
1096 }
1097
1098 /* Update the entries in index. */
1099 masterfd = open(TAGCACHE_FILE_MASTER, O_RDWR);
1100
1101 if (masterfd < 0)
1102 {
1103 logf("No master file found!");
1104 return false;
1105 }
1106
1107 if (read(masterfd, &tch, sizeof(struct tagcache_header)) !=
1108 sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC)
1109 {
1110 logf("header error");
1111 close(masterfd);
1112 return false;
1113 }
1114
1115 masterfd_pos = lseek(masterfd, tch.entry_count * sizeof(struct index_entry),
1116 SEEK_CUR);
1117 if (masterfd_pos == filesize(masterfd))
1118 {
1119 logf("we can't append!");
1120 close(masterfd);
1121 return false;
1122 }
1123
1124 for (i = 0; i < h->entry_count; i++)
1125 {
1126 int loc = lseek(masterfd, 0, SEEK_CUR);
1127
1128 if (read(masterfd, &idx, sizeof(struct index_entry)) !=
1129 sizeof(struct index_entry))
1130 {
1131 logf("read fail #2");
1132 close(masterfd);
1133 return false;
1134 }
1135
1136 idx.tag_seek[index_type] = databuf[i];
1137
1138 /* Write back the updated index. */
1139 lseek(masterfd, loc, SEEK_SET);
1140 if (write(masterfd, &idx, sizeof(struct index_entry)) !=
1141 sizeof(struct index_entry))
1142 {
1143 logf("write fail");
1144 close(masterfd);
1145 return false;
1146 }
1147 }
1148
1149 close(masterfd);
1150
1151 return true;
1152}
1153
947static bool build_index(int index_type, struct tagcache_header *h, int tmpfd) 1154static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
948{ 1155{
949 int i; 1156 int i;
@@ -1020,7 +1227,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
1020 * is saved so we can later reindex the master lookup 1227 * is saved so we can later reindex the master lookup
1021 * table when the index gets resorted. 1228 * table when the index gets resorted.
1022 */ 1229 */
1023 tempbuf_insert(buf, loc + TAGFILE_MAX_ENTRIES); 1230 tempbuf_insert(buf, loc + TAGFILE_MAX_ENTRIES, entry.idx_id);
1024 } 1231 }
1025 } 1232 }
1026 else 1233 else
@@ -1149,7 +1356,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
1149 if (is_unique_tag(index_type)) 1356 if (is_unique_tag(index_type))
1150 error = !tempbuf_unique_insert(buf, i); 1357 error = !tempbuf_unique_insert(buf, i);
1151 else 1358 else
1152 error = !tempbuf_insert(buf, i); 1359 error = !tempbuf_insert(buf, i, tch.entry_count + i);
1153 1360
1154 if (error) 1361 if (error)
1155 { 1362 {
@@ -1268,6 +1475,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
1268 /* Write to index file. */ 1475 /* Write to index file. */
1269 idx.tag_seek[index_type] = lseek(fd, 0, SEEK_CUR); 1476 idx.tag_seek[index_type] = lseek(fd, 0, SEEK_CUR);
1270 fe.tag_length = entry.tag_length[index_type]; 1477 fe.tag_length = entry.tag_length[index_type];
1478 fe.idx_id = tch.entry_count + i;
1271 write(fd, &fe, sizeof(struct tagfile_entry)); 1479 write(fd, &fe, sizeof(struct tagfile_entry));
1272 write(fd, buf, fe.tag_length); 1480 write(fd, buf, fe.tag_length);
1273 tempbufidx++; 1481 tempbufidx++;
@@ -1375,7 +1583,12 @@ static bool commit(void)
1375 /* Now create the index files. */ 1583 /* Now create the index files. */
1376 for (i = 0; i < TAG_COUNT; i++) 1584 for (i = 0; i < TAG_COUNT; i++)
1377 { 1585 {
1378 if (!build_index(i, &header, tmpfd)) 1586 if (is_numeric_tag(i))
1587 {
1588 build_numeric_index(i, &header, tmpfd);
1589 }
1590
1591 else if (!build_index(i, &header, tmpfd))
1379 { 1592 {
1380 logf("tagcache failed init"); 1593 logf("tagcache failed init");
1381 remove_files(); 1594 remove_files();
@@ -1537,6 +1750,9 @@ static bool load_tagcache(void)
1537 struct tagfile_entry *fe; 1750 struct tagfile_entry *fe;
1538 char buf[MAX_PATH]; 1751 char buf[MAX_PATH];
1539 1752
1753 if (is_numeric_tag(i))
1754 continue ;
1755
1540 //p = ((void *)p+1); 1756 //p = ((void *)p+1);
1541 p = (char *)((long)p & ~0x03) + 0x04; 1757 p = (char *)((long)p & ~0x03) + 0x04;
1542 hdr->tags[i] = p; 1758 hdr->tags[i] = p;
@@ -1854,7 +2070,7 @@ static void tagcache_thread(void)
1854 2070
1855int tagcache_get_progress(void) 2071int tagcache_get_progress(void)
1856{ 2072{
1857 int total_count = -1; 2073 int total_count = processed_dir_count;
1858 2074
1859#ifdef HAVE_DIRCACHE 2075#ifdef HAVE_DIRCACHE
1860 if (dircache_is_enabled()) 2076 if (dircache_is_enabled())