1 |
/**
|
2 |
* Navit, a modular navigation system.
|
3 |
* Copyright (C) 2005-2008 Navit Team
|
4 |
*
|
5 |
* This program is free software; you can redistribute it and/or
|
6 |
* modify it under the terms of the GNU General Public License
|
7 |
* version 2 as published by the Free Software Foundation.
|
8 |
*
|
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.
|
13 |
*
|
14 |
* You should have received a copy of the GNU General Public License
|
15 |
* along with this program; if not, write to the
|
16 |
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
17 |
* Boston, MA 02110-1301, USA.
|
18 |
*/
|
19 |
|
20 |
#include <stdlib.h>
|
21 |
#include <glib.h>
|
22 |
#include <stdio.h>
|
23 |
#include <string.h>
|
24 |
#include <math.h>
|
25 |
#include "config.h"
|
26 |
#include "debug.h"
|
27 |
#include "plugin.h"
|
28 |
#include "projection.h"
|
29 |
#include "item.h"
|
30 |
#include "map.h"
|
31 |
#include "maptype.h"
|
32 |
#include "attr.h"
|
33 |
#include "coord.h"
|
34 |
#include "transform.h"
|
35 |
#include "file.h"
|
36 |
#include "zipfile.h"
|
37 |
#include "linguistics.h"
|
38 |
#include "endianess.h"
|
39 |
|
40 |
struct filter_entry {
|
41 |
enum item_type first,last;
|
42 |
enum attr_type cond_attr;
|
43 |
char *cond_str;
|
44 |
};
|
45 |
|
46 |
struct filter {
|
47 |
GList *old;
|
48 |
GList *new;
|
49 |
};
|
50 |
|
51 |
struct map_priv {
|
52 |
struct map *parent;
|
53 |
GList *filters;
|
54 |
};
|
55 |
|
56 |
struct map_rect_priv {
|
57 |
struct map_selection *sel;
|
58 |
struct map_priv *m;
|
59 |
struct map_rect *parent;
|
60 |
struct item item,*parent_item;
|
61 |
};
|
62 |
|
63 |
struct map_search_priv {
|
64 |
struct map_rect_priv *mr;
|
65 |
};
|
66 |
|
67 |
static enum item_type
|
68 |
filter_type(struct map_priv *m, struct item *item)
|
69 |
{
|
70 |
GList *filters=m->filters;
|
71 |
struct filter_entry *entry;
|
72 |
while (filters) {
|
73 |
struct filter *filter=filters->data;
|
74 |
int pos=0,count=0;
|
75 |
GList *old,*new;
|
76 |
old=filter->old;
|
77 |
while (old) {
|
78 |
entry=old->data;
|
79 |
if (item->type >= entry->first && item->type <= entry->last)
|
80 |
break;
|
81 |
pos+=entry->last-entry->first+1;
|
82 |
old=g_list_next(old);
|
83 |
}
|
84 |
if (old && entry && entry->cond_attr != attr_none) {
|
85 |
struct attr attr;
|
86 |
if (!item_attr_get(item, entry->cond_attr, &attr)) {
|
87 |
old=NULL;
|
88 |
} else {
|
89 |
char *wildcard=strchr(entry->cond_str,'*');
|
90 |
int len;
|
91 |
if (!wildcard)
|
92 |
len=strlen(entry->cond_str)+1;
|
93 |
else
|
94 |
len=wildcard-entry->cond_str;
|
95 |
if (strncmp(entry->cond_str, attr.u.str, len))
|
96 |
old=NULL;
|
97 |
}
|
98 |
item_attr_rewind(item);
|
99 |
}
|
100 |
if (old) {
|
101 |
new=filter->new;
|
102 |
if (!new)
|
103 |
return item->type;
|
104 |
while (new) {
|
105 |
struct filter_entry *entry=new->data;
|
106 |
count+=entry->last-entry->first+1;
|
107 |
new=g_list_next(new);
|
108 |
}
|
109 |
pos%=count;
|
110 |
new=filter->new;
|
111 |
while (new) {
|
112 |
struct filter_entry *entry=new->data;
|
113 |
if (pos <= entry->last-entry->first)
|
114 |
return entry->first+pos;
|
115 |
pos-=entry->last-entry->first+1;
|
116 |
new=g_list_next(new);
|
117 |
}
|
118 |
}
|
119 |
filters=g_list_next(filters);
|
120 |
}
|
121 |
return item->type;
|
122 |
}
|
123 |
|
124 |
static void
|
125 |
free_filter_entry(struct filter_entry *filter)
|
126 |
{
|
127 |
g_free(filter->cond_str);
|
128 |
g_free(filter);
|
129 |
}
|
130 |
|
131 |
static void
|
132 |
free_filter(struct filter *filter)
|
133 |
{
|
134 |
g_list_foreach(filter->old, (GFunc)free_filter_entry, NULL);
|
135 |
g_list_free(filter->old);
|
136 |
filter->old=NULL;
|
137 |
g_list_foreach(filter->new, (GFunc)free_filter_entry, NULL);
|
138 |
g_list_free(filter->new);
|
139 |
filter->new=NULL;
|
140 |
}
|
141 |
|
142 |
static void
|
143 |
free_filters(struct map_priv *m)
|
144 |
{
|
145 |
g_list_foreach(m->filters, (GFunc)free_filter, NULL);
|
146 |
g_list_free(m->filters);
|
147 |
m->filters=NULL;
|
148 |
}
|
149 |
|
150 |
static GList *
|
151 |
parse_filter(char *filter)
|
152 |
{
|
153 |
GList *ret=NULL;
|
154 |
for (;;) {
|
155 |
char *condition,*range,*next=strchr(filter,',');
|
156 |
struct filter_entry *entry=g_new0(struct filter_entry, 1);
|
157 |
if (next)
|
158 |
*next++='\0';
|
159 |
condition=strchr(filter,'[');
|
160 |
if (condition)
|
161 |
*condition++='\0';
|
162 |
range=strchr(filter,'-');
|
163 |
if (range)
|
164 |
*range++='\0';
|
165 |
if (!strcmp(filter,"*") && !range) {
|
166 |
entry->first=type_none;
|
167 |
entry->last=type_last;
|
168 |
} else {
|
169 |
entry->first=item_from_name(filter);
|
170 |
if (range)
|
171 |
entry->last=item_from_name(range);
|
172 |
else
|
173 |
entry->last=entry->first;
|
174 |
}
|
175 |
if (condition) {
|
176 |
char *end=strchr(condition,']');
|
177 |
char *eq=strchr(condition,'=');
|
178 |
if (end && eq && eq < end) {
|
179 |
*end='\0';
|
180 |
*eq++='\0';
|
181 |
if (eq[0] == '"' || eq[0] == '\'') {
|
182 |
char *quote=strchr(eq+1,eq[0]);
|
183 |
if (quote) {
|
184 |
eq++;
|
185 |
*quote='\0';
|
186 |
}
|
187 |
}
|
188 |
entry->cond_attr=attr_from_name(condition);
|
189 |
entry->cond_str=g_strdup(eq);
|
190 |
}
|
191 |
}
|
192 |
ret=g_list_append(ret, entry);
|
193 |
if (!next)
|
194 |
break;
|
195 |
filter=next;
|
196 |
}
|
197 |
return ret;
|
198 |
}
|
199 |
|
200 |
static void
|
201 |
parse_filters(struct map_priv *m, char *filter)
|
202 |
{
|
203 |
char *filter_copy=g_strdup(filter);
|
204 |
char *str=filter_copy;
|
205 |
|
206 |
free_filters(m);
|
207 |
for (;;) {
|
208 |
char *pos,*bracket,*eq,*next=strchr(str,';');
|
209 |
struct filter *filter=g_new0(struct filter, 1);
|
210 |
if (next)
|
211 |
*next++='\0';
|
212 |
pos=str;
|
213 |
for (;;) {
|
214 |
eq=strchr(pos,'=');
|
215 |
if (eq) {
|
216 |
bracket=strchr(pos,'[');
|
217 |
if (bracket && bracket < eq) {
|
218 |
bracket=strchr(pos,']');
|
219 |
if (bracket)
|
220 |
pos=bracket+1;
|
221 |
else {
|
222 |
eq=NULL;
|
223 |
break;
|
224 |
}
|
225 |
} else {
|
226 |
*eq++='\0';
|
227 |
break;
|
228 |
}
|
229 |
} else
|
230 |
break;
|
231 |
}
|
232 |
filter->old=parse_filter(str);
|
233 |
if (eq)
|
234 |
filter->new=parse_filter(eq);
|
235 |
m->filters=g_list_append(m->filters,filter);
|
236 |
if (!next)
|
237 |
break;
|
238 |
str=next;
|
239 |
}
|
240 |
g_free(filter_copy);
|
241 |
}
|
242 |
|
243 |
static void
|
244 |
map_filter_coord_rewind(void *priv_data)
|
245 |
{
|
246 |
struct map_rect_priv *mr=priv_data;
|
247 |
item_coord_rewind(mr->parent_item);
|
248 |
}
|
249 |
|
250 |
static int
|
251 |
map_filter_coord_get(void *priv_data, struct coord *c, int count)
|
252 |
{
|
253 |
struct map_rect_priv *mr=priv_data;
|
254 |
return item_coord_get(mr->parent_item, c, count);
|
255 |
}
|
256 |
|
257 |
static void
|
258 |
map_filter_attr_rewind(void *priv_data)
|
259 |
{
|
260 |
struct map_rect_priv *mr=priv_data;
|
261 |
item_attr_rewind(mr->parent_item);
|
262 |
}
|
263 |
|
264 |
static int
|
265 |
map_filter_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
|
266 |
{
|
267 |
struct map_rect_priv *mr=priv_data;
|
268 |
return item_attr_get(mr->parent_item, attr_type, attr);
|
269 |
}
|
270 |
|
271 |
static struct item_methods methods_filter = {
|
272 |
map_filter_coord_rewind,
|
273 |
map_filter_coord_get,
|
274 |
map_filter_attr_rewind,
|
275 |
map_filter_attr_get,
|
276 |
};
|
277 |
|
278 |
static struct map_rect_priv *
|
279 |
map_filter_rect_new(struct map_priv *map, struct map_selection *sel)
|
280 |
{
|
281 |
struct map_rect_priv *mr=NULL;
|
282 |
struct map_rect *parent;
|
283 |
parent=map_rect_new(map->parent, sel);
|
284 |
if (parent) {
|
285 |
mr=g_new0(struct map_rect_priv, 1);
|
286 |
mr->m=map;
|
287 |
mr->sel=sel;
|
288 |
mr->parent=parent;
|
289 |
mr->item.meth=&methods_filter;
|
290 |
mr->item.priv_data=mr;
|
291 |
}
|
292 |
return mr;
|
293 |
}
|
294 |
|
295 |
static void
|
296 |
map_filter_rect_destroy(struct map_rect_priv *mr)
|
297 |
{
|
298 |
map_rect_destroy(mr->parent);
|
299 |
g_free(mr);
|
300 |
}
|
301 |
|
302 |
static struct item *
|
303 |
map_filter_rect_get_item(struct map_rect_priv *mr)
|
304 |
{
|
305 |
mr->parent_item=map_rect_get_item(mr->parent);
|
306 |
if (!mr->parent_item)
|
307 |
return NULL;
|
308 |
mr->item.type=filter_type(mr->m,mr->parent_item);
|
309 |
mr->item.id_lo=mr->parent_item->id_lo;
|
310 |
mr->item.id_hi=mr->parent_item->id_hi;
|
311 |
return &mr->item;
|
312 |
}
|
313 |
|
314 |
static struct item *
|
315 |
map_filter_rect_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
|
316 |
{
|
317 |
dbg(0,"enter\n");
|
318 |
mr->parent_item=map_rect_get_item_byid(mr->parent, id_hi, id_lo);
|
319 |
if (!mr->parent_item)
|
320 |
return NULL;
|
321 |
mr->item.type=filter_type(mr->m,mr->parent_item);
|
322 |
mr->item.id_lo=mr->parent_item->id_lo;
|
323 |
mr->item.id_hi=mr->parent_item->id_hi;
|
324 |
return &mr->item;
|
325 |
}
|
326 |
|
327 |
static struct map_search_priv *
|
328 |
map_filter_search_new(struct map_priv *map, struct item *item, struct attr *search, int partial)
|
329 |
{
|
330 |
dbg(0,"enter\n");
|
331 |
return NULL;
|
332 |
}
|
333 |
|
334 |
static struct item *
|
335 |
map_filter_search_get_item(struct map_search_priv *map_search)
|
336 |
{
|
337 |
dbg(0,"enter\n");
|
338 |
return NULL;
|
339 |
}
|
340 |
|
341 |
static void
|
342 |
map_filter_search_destroy(struct map_search_priv *ms)
|
343 |
{
|
344 |
dbg(0,"enter\n");
|
345 |
}
|
346 |
|
347 |
static void
|
348 |
map_filter_destroy(struct map_priv *m)
|
349 |
{
|
350 |
map_destroy(m->parent);
|
351 |
g_free(m);
|
352 |
}
|
353 |
|
354 |
static int
|
355 |
map_filter_set_attr(struct map_priv *m, struct attr *attr)
|
356 |
{
|
357 |
switch (attr->type) {
|
358 |
case attr_filter:
|
359 |
parse_filters(m,attr->u.str);
|
360 |
return 1;
|
361 |
default:
|
362 |
return 0;
|
363 |
}
|
364 |
}
|
365 |
|
366 |
|
367 |
static struct map_methods map_methods_filter = {
|
368 |
projection_mg,
|
369 |
"utf-8",
|
370 |
map_filter_destroy,
|
371 |
map_filter_rect_new,
|
372 |
map_filter_rect_destroy,
|
373 |
map_filter_rect_get_item,
|
374 |
map_filter_rect_get_item_byid,
|
375 |
map_filter_search_new,
|
376 |
map_filter_search_destroy,
|
377 |
map_filter_search_get_item,
|
378 |
NULL,
|
379 |
NULL,
|
380 |
map_filter_set_attr,
|
381 |
};
|
382 |
|
383 |
|
384 |
|
385 |
static struct map_priv *
|
386 |
map_filter_new(struct map_methods *meth, struct attr **attrs)
|
387 |
{
|
388 |
struct map_priv *m=NULL;
|
389 |
struct attr **parent_attrs,type,*subtype=attr_search(attrs, NULL, attr_subtype),*filter=attr_search(attrs, NULL, attr_filter);
|
390 |
struct map *map;
|
391 |
int i,j;
|
392 |
if (! subtype || !filter)
|
393 |
return NULL;
|
394 |
i=0;
|
395 |
while (attrs[i])
|
396 |
i++;
|
397 |
parent_attrs=g_new(struct attr *,i+1);
|
398 |
i=0;
|
399 |
j=0;
|
400 |
while (attrs[i]) {
|
401 |
if (attrs[i]->type != attr_filter && attrs[i]->type != attr_type) {
|
402 |
if (attrs[i]->type == attr_subtype) {
|
403 |
type=*attrs[i];
|
404 |
type.type = attr_type;
|
405 |
parent_attrs[j]=&type;
|
406 |
} else
|
407 |
parent_attrs[j]=attrs[i];
|
408 |
j++;
|
409 |
}
|
410 |
i++;
|
411 |
}
|
412 |
parent_attrs[j]=NULL;
|
413 |
*meth=map_methods_filter;
|
414 |
map=map_new(NULL, parent_attrs);
|
415 |
if (map) {
|
416 |
m=g_new0(struct map_priv, 1);
|
417 |
m->parent=map;
|
418 |
parse_filters(m,filter->u.str);
|
419 |
}
|
420 |
g_free(parent_attrs);
|
421 |
return m;
|
422 |
}
|
423 |
|
424 |
void
|
425 |
plugin_init(void)
|
426 |
{
|
427 |
dbg(1,"filter: plugin_init\n");
|
428 |
plugin_register_map_type("filter", map_filter_new);
|
429 |
}
|
430 |
|