Fix build warning
[platform/core/appfw/xdgmime.git] / xdgmime / src / xdgmimeglobs2.c
1 /*
2  * xdgmimeglobs2.c
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee                          <airjany@samsung.com>
7  * Contact: Seokkyu Jang                        <seokkyu.jang@samsung.com>
8  * Contact: Sangil Yoon                         <si83.yoon@samsung.com>
9  *
10  * This library is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU Lesser General Public License as published by the
12  * Free Software Foundation; either version 2.1 of the License, or (at your option)
13  * any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this library; if not, write to the Free Software Foundation, Inc., 51
22  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #include "xdgmime.h"
34
35 #ifndef API
36 #define API __attribute__ ((visibility("default")))
37 #endif
38
39
40 #define GLOBS2_PATH "/usr/share/mime/globs2"
41 #define MEM_INC_RATE 20
42
43
44 /*************
45  * Data types
46  *************/
47 typedef struct mime_type_info
48 {
49         char *mime_type;
50         char **file_names;
51         size_t file_names_size;
52 } mime_type_info;
53
54 typedef struct mime_type_info_list
55 {
56         mime_type_info **mti_list;
57         size_t mti_list_size;
58         time_t globs2_mtime;
59 } mime_type_info_list;
60
61 static mime_type_info_list *mti_list = NULL;
62
63
64 /***************************
65  * mime_type_info functions
66  ***************************/
67 static mime_type_info *
68 mime_type_info_new(void)
69 {
70         mime_type_info *mti = NULL;
71
72         mti = calloc(1, sizeof(mime_type_info));
73         mti->file_names = calloc(MEM_INC_RATE, sizeof(char *));
74         mti->file_names_size = MEM_INC_RATE;
75
76         return mti;
77 }
78
79 static void
80 mime_type_info_free(mime_type_info *mti)
81 {
82         if(!mti) return;
83
84         if(mti->mime_type) free(mti->mime_type);
85         if(mti->file_names) {
86                 char **tmpstr;
87                 for(tmpstr = mti->file_names; *tmpstr; tmpstr++) {
88                         free(*tmpstr);
89                 }
90                 free(mti->file_names);
91         }
92         free(mti);
93 }
94
95 static int
96 mime_type_info_add_file_name(mime_type_info *mti,
97                 const char *mime_type,
98                 const char *file_name)
99 {
100         if(!mti) return -1;
101
102         if(!mti->mime_type) {
103                 mti->mime_type = strdup(mime_type);
104         }
105         else {
106                 /* mime_type already exist, but mime_type is different! */
107                 if(strcmp(mti->mime_type, mime_type)) return -1;
108         }
109
110         /* Find position */
111         char **pname;
112         for(pname = mti->file_names; pname < (mti->file_names + mti->file_names_size - 1) && *pname; pname++) {
113                 if(!strcmp(file_name, *pname)) return 0;        /* already exist! */
114         }
115
116         int old_file_names_size = mti->file_names_size;
117
118         if(pname == mti->file_names + old_file_names_size -1) {
119
120                 /* memory full. realloc needed */
121                 mti->file_names = realloc(mti->file_names, sizeof(char *)*(old_file_names_size+MEM_INC_RATE));
122                 if(!mti->file_names) return -1;
123
124                 memset(mti->file_names + old_file_names_size, 0x00, sizeof(char *)*MEM_INC_RATE);
125                 pname = mti->file_names + old_file_names_size - 1;
126                 mti->file_names_size += MEM_INC_RATE;
127         }
128
129         *pname = strdup(file_name);
130
131         return 0;
132 }
133
134
135
136 /********************************
137  * mime_type_info_list functions
138  ********************************/
139
140 /* definitions */
141
142 static mime_type_info_list *
143 mime_type_info_list_new(void)
144 {
145         mime_type_info_list *mtil;
146
147         mtil = calloc(1, sizeof(mime_type_info_list));
148
149         mtil->mti_list = calloc(MEM_INC_RATE, sizeof(mime_type_info *));
150         mtil->mti_list_size = MEM_INC_RATE;
151
152         return mtil;
153 }
154
155
156
157 /* free and init mtlist */
158 static void
159 mime_type_info_list_free(mime_type_info_list *mtil)
160 {
161         mime_type_info **mti;
162         char *tmp;
163
164         for(mti = mtil->mti_list;
165                         *mti;
166                         mti++) {
167                 mime_type_info_free(*mti);
168         }
169
170         free(mtil->mti_list);
171         free(mtil);
172 }
173
174 static int
175 mime_type_info_list_add_file_name(mime_type_info_list *mtil,
176                 const char *mime_type,
177                 const char *file_name)
178 {
179         if(!mtil || !mime_type || !file_name) return -1;
180
181         mime_type_info **mti;
182         int found = 0;
183
184         for(mti = mtil->mti_list; mti < (mtil->mti_list + mtil->mti_list_size - 1) && *mti; mti++) {
185                 if((*mti)->mime_type && mime_type &&  /* NULL check */
186                         0 == strncmp((*mti)->mime_type,
187                                 mime_type,
188                                 strlen(mime_type))) {
189                         /* found! */
190                         found = 1;
191                         break;
192                 }
193         }
194         if(!found) {
195                 /* New mime_type_info must be needed */
196
197                 /* check memory full */
198                 int old_mti_list_size = mtil->mti_list_size;
199                 //printf("sizeof(mti_list)=%d, sizeof(mime_type_info *)=%d, old info_list_size=%d\n", sizeof(mtil->mti_list), sizeof(mime_type_info *), old_mti_list_size);
200
201                 /* last chance */
202                 if(mti == mtil->mti_list + old_mti_list_size - 1) {
203                         /* memory full. realloc needed */
204                         mtil->mti_list = realloc(mtil->mti_list, sizeof(mime_type_info *) * (old_mti_list_size + MEM_INC_RATE));
205                         if(!mtil->mti_list) return -1;
206                         memset(mtil->mti_list + old_mti_list_size, 0x0, sizeof(mime_type_info *) * MEM_INC_RATE);
207                         mti = mtil->mti_list + old_mti_list_size - 1;
208
209                         mtil->mti_list_size += MEM_INC_RATE;
210                 }
211         }
212
213         /* assign new data */
214         if(NULL == *mti) *mti = mime_type_info_new();
215         mime_type_info_add_file_name(*mti, mime_type, file_name);
216
217         return 0;
218 }
219
220
221 /* create or renew mtlist */
222 static void
223 mime_type_info_list_reload(mime_type_info_list *mtil)
224 {
225         FILE *globs2 = NULL;
226         struct stat globs2_stat;
227         int r;
228         char buf[256];
229
230         if(!mtil) return;
231
232         /* Check glob2's mtime.
233          * If reconstruction is not needed, just exit function */
234         if( stat(GLOBS2_PATH, &globs2_stat) ||
235                         globs2_stat.st_mtime <= mtil->globs2_mtime ) return;
236
237         /* clean old mtil */
238         mime_type_info **mti;
239         for(mti = mtil->mti_list;
240                 *mti;
241                 mti++) {
242                 mime_type_info_free(*mti);
243                 *mti = NULL;
244         }
245
246         /* save globs2's mtime */
247         mtil->globs2_mtime = globs2_stat.st_mtime;
248
249         /* read globs2, and construct data structure */
250         globs2 = fopen(GLOBS2_PATH, "r");
251         if (!globs2) return;
252
253         char *weight, *mime_type, *file_name, *saveptr = NULL;
254         while(fgets(buf, 255, globs2)) {
255                 /* skip comment */
256                 if(*buf == '#') continue;
257                 /* weight:mime_type:file_name */
258                 weight = strtok_r(buf, ":\n", &saveptr);        /* ignored */
259                 mime_type = strtok_r(NULL, ":\n", &saveptr);
260                 file_name = strtok_r(NULL, ":\n", &saveptr);
261
262                 mime_type_info_list_add_file_name(mtil, mime_type, file_name);
263         }
264         fclose(globs2);
265
266         /* TODO: sort it! */
267
268 }
269
270 static const char **
271 mime_type_info_list_get_file_names(mime_type_info_list *mtil,
272                 const char *mime_type)
273 {
274
275         static const char *null_array[] = { NULL };
276
277         if(!mtil) return null_array;
278
279         mime_type_info **_mti;
280         for(_mti = mtil->mti_list; *_mti; _mti++) {
281                 if((*_mti)->mime_type && mime_type &&   /* NULL check */
282                         !strcmp((*_mti)->mime_type, mime_type)) {
283                         return (const char **) (*_mti)->file_names;
284                 }
285         }
286
287         return null_array;
288 }
289
290
291 /* API
292  * Get file names' list from mime type
293  */
294 API const char **
295 xdg_mime_get_file_names_from_mime_type(const char *mime_type)
296 {
297         /* init data structure */
298         static mime_type_info_list *mtil = NULL;
299         if(!mtil) mtil = mime_type_info_list_new();
300         mime_type_info_list_reload(mtil);
301
302         return mime_type_info_list_get_file_names(mtil, mime_type);
303 }
304