changed n_link to 1, so 'find' will work (we have no enless subdirs by default anymore)
[k8muffin.git] / src / tagload.c
bloba328cd76d0e4325910da77ffd0752a80553e2825
1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 ////////////////////////////////////////////////////////////////////////////////
18 // augment UTHASH with two more macrodefs
19 #define HASH_FIND_PTR_EX(hh,head,findptr,out) HASH_FIND(hh,head,findptr,sizeof(void *),out)
20 #define HASH_ADD_PTR_EX(hh,head,ptrfield,add) HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
22 #define HASH_FIND_STR_EX(hh,head,findstr,out) HASH_FIND(hh,head,findstr,strlen(findstr),out)
23 #define HASH_ADD_STR_EX(hh,head,strfield,add) HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
25 #define HASH_FIND_UINT32(head,findint,out) HASH_FIND(hh,head,findint,sizeof(uint32_t),out)
26 #define HASH_ADD_UINT32(head,intfield,add) HASH_ADD(hh,head,intfield,sizeof(uint32_t),add)
27 #define HASH_REPLACE_UINT32(head,intfield,add,replaced) HASH_REPLACE(hh,head,intfield,sizeof(uint32_t),add,replaced)
30 ////////////////////////////////////////////////////////////////////////////////
31 enum {
32 TFL_YEAR,
33 TFL_ARTIST_O,
34 TFL_ARTIST_T,
35 TFL_ALBUM_O,
36 TFL_ALBUM_T,
37 TFL_TITLE_O,
38 TFL_TITLE_T,
39 TFL_GENRE_O,
40 TFL_GENRE_T,
41 TFL_YRAL_O,
42 TFL_YRAL_T,
43 TFL_MAX
47 typedef struct __attribute__((packed,gcc_struct)) {
48 uint32_t count;
49 uint32_t idx;
50 } fl_tfl_t;
52 typedef struct __attribute__((packed,gcc_struct)) {
53 uint32_t value;
54 fl_tfl_t tfl[TFL_MAX];
55 } fl_tagvalue_t;
58 typedef struct __attribute__((packed,gcc_struct)) {
59 uint32_t realname;
60 uint32_t shortname;
61 #ifdef USE_DEVID_INODE
62 uint64_t devid;
63 uint64_t inode;
64 #endif
65 uint64_t size;
66 uint64_t mtime;
67 uint8_t tracknum;
68 uint16_t year;
69 union {
70 struct {
71 uint32_t year_tag;
72 uint32_t artist_o, artist_t;
73 uint32_t album_o, album_t;
74 uint32_t title_o, title_t;
75 uint32_t genre_o, genre_t;
76 uint32_t yral_o, yral_t;
78 uint32_t tags[TFL_MAX];
80 } fl_fileinfo_t;
83 ////////////////////////////////////////////////////////////////////////////////
84 static uint32_t file_count = 0, tag_count = 0, string_bytes = 0, o_tag_count = 0, t_tag_count = 0, tfl_bytes = 0;
85 static uint8_t *string_data = NULL;
86 static fl_fileinfo_t *fileinfo_data = NULL;
87 static fl_tagvalue_t *tagvalue_data = NULL;
88 static uint32_t *taglisto_data = NULL;
89 static uint32_t *taglistt_data = NULL;
90 static uint32_t *tfl_data = NULL;
92 static inline fl_tagvalue_t *get_tv (uint32_t idx) { return (idx < tag_count ? &tagvalue_data[idx] : NULL); }
93 static inline fl_fileinfo_t *get_fi (uint32_t idx) { return (idx < file_count ? &fileinfo_data[idx] : NULL); }
95 static inline uint32_t tv2idx (const fl_tagvalue_t *tv) { return (tv != NULL ? (uintptr_t)((const uint8_t *)tv-(const uint8_t *)tagvalue_data)/sizeof(*tv) : 0); }
96 static inline uint32_t fi2idx (const fl_fileinfo_t *fi) { return (fi != NULL ? (uintptr_t)((const uint8_t *)fi-(const uint8_t *)fileinfo_data)/sizeof(*fi) : 0); }
98 static inline char *get_str (uint32_t ofs) { return (ofs >= 2 && ofs < string_bytes ? (char *)(string_data+ofs) : NULL); }
99 static inline int get_strlen (uint32_t ofs) { return (ofs < string_bytes ? *((const uint16_t *)(string_data+ofs-2)) : 0); }
102 ////////////////////////////////////////////////////////////////////////////////
103 static void tagdb_unload (void) {
104 file_count = tag_count = string_bytes = o_tag_count = t_tag_count = tfl_bytes = 0;
105 if (string_data != NULL) free(string_data);
106 if (fileinfo_data != NULL) free(fileinfo_data);
107 if (tagvalue_data != NULL) free(tagvalue_data);
108 if (taglisto_data != NULL) free(taglisto_data);
109 if (taglistt_data != NULL) free(taglistt_data);
110 if (tfl_data != NULL) free(tfl_data);
112 string_data = NULL;
113 fileinfo_data = NULL;
114 tagvalue_data = NULL;
115 taglisto_data = NULL;
116 taglistt_data = NULL;
117 tfl_data = NULL;
121 ////////////////////////////////////////////////////////////////////////////////
122 static int tagdb_load (const char *fname) {
123 FILE *fl;
124 char sign[4];
126 #if defined(NDEBUG) && NDEBUG
127 # define showofs() ((void)0)
128 #else
129 void showofs (void) {
130 dlogf("OFS: 0x%08x\n", (unsigned)ftell(fl));
132 #endif
134 tagdb_unload();
135 fl = fopen(fname, "r");
136 if (fl == NULL) return -1; // no tags
137 // header
138 if (fread(sign, 4, 1, fl) != 1) goto error;
139 #ifdef USE_DEVID_INODE
140 if (memcmp(sign, "MTD0", 4) != 0) goto error;
141 #else
142 if (memcmp(sign, "MTD2", 4) != 0) goto error;
143 #endif
144 if (fread(&file_count, 4, 1, fl) != 1) goto error;
145 if (fread(&tag_count, 4, 1, fl) != 1) goto error;
146 if (fread(&string_bytes, 4, 1, fl) != 1) goto error;
147 if (fread(&tfl_bytes, 4, 1, fl) != 1) goto error;
148 if (fread(&o_tag_count, 4, 1, fl) != 1) goto error;
149 if (fread(&t_tag_count, 4, 1, fl) != 1) goto error;
151 //dlogf("%u\n", sizeof(fl_tagvalue_t));
152 dlogf("file_count=%u\n", file_count);
153 dlogf("tag_count=%u\n", tag_count);
154 dlogf("string_bytes=%u\n", string_bytes);
155 dlogf("tfl_bytes=%u\n", tfl_bytes);
156 dlogf("o_tag_count=%u\n", o_tag_count);
157 dlogf("t_tag_count=%u\n", t_tag_count);
159 if (file_count < 1 || tag_count < 1 || string_bytes < 3 || tfl_bytes < 1 || o_tag_count < 1 || t_tag_count < 1) goto error; // invalid or empty file
161 printf("loading %u files...\n", (unsigned int)file_count);
162 dlogf("loading strings...\n");
163 showofs();
164 if ((string_data = malloc(string_bytes)) == NULL) goto error;
165 if (fread(string_data, string_bytes, 1, fl) != 1) goto error;
167 dlogf("loading taglisto...\n");
168 showofs();
169 if ((taglisto_data = malloc(o_tag_count*sizeof(uint32_t))) == NULL) goto error;
170 if (fread(taglisto_data, o_tag_count*sizeof(uint32_t), 1, fl) != 1) goto error;
172 dlogf("loading taglistt...\n");
173 showofs();
174 if ((taglistt_data = malloc(t_tag_count*sizeof(uint32_t))) == NULL) goto error;
175 if (fread(taglistt_data, t_tag_count*sizeof(uint32_t), 1, fl) != 1) goto error;
177 dlogf("loading fileinfo...\n");
178 showofs();
179 if ((fileinfo_data = malloc(file_count*sizeof(fl_fileinfo_t))) == NULL) goto error;
180 if (fread(fileinfo_data, file_count*sizeof(fl_fileinfo_t), 1, fl) != 1) goto error;
182 dlogf("loading taginfo...\n");
183 showofs();
184 if ((tagvalue_data = malloc(tag_count*sizeof(fl_tagvalue_t))) == NULL) goto error;
185 if (fread(tagvalue_data, tag_count*sizeof(fl_tagvalue_t), 1, fl) != 1) goto error;
187 dlogf("loading tfl...\n");
188 showofs();
189 if ((tfl_data = malloc(tfl_bytes)) == NULL) goto error;
190 if (fread(tfl_data, tfl_bytes, 1, fl) != 1) goto error;
192 dlogf("done\n");
193 fclose(fl);
195 return 0;
196 error:
197 // invalid tag file
198 fclose(fl);
199 tagdb_unload();
200 return -1;