From df2c55b4d9c334bcc5f74d4d0b456d8e3685c3d1 Mon Sep 17 00:00:00 2001 From: Stefan Wildemann Date: Wed, 30 Oct 2019 00:23:40 +0100 Subject: fix:core:Don't flood stack on big map elements (#928) * fix:core:Don't flood stack on big map elements Use g_malloc instead of g_alloca on huge map elements. Correctly calculate element intersection with map selection even if buffer is too small. --- navit/graphics.c | 232 +++++++++++++++++++++++++++++++++++--------- navit/item.c | 102 ++++++++++++++----- navit/item.h | 2 + navit/map/binfile/binfile.c | 11 +++ 4 files changed, 277 insertions(+), 70 deletions(-) diff --git a/navit/graphics.c b/navit/graphics.c index b3b9e54c2..662a74f0b 100644 --- a/navit/graphics.c +++ b/navit/graphics.c @@ -53,6 +53,10 @@ #include "event.h" #include "navit.h" +/** + * @brief maximum amount of coordinates to allocate on stack using g_alloca + */ +#define ALLOCA_COORD_LIMIT 16384 //############################################################################################################## //# Description: @@ -1035,11 +1039,18 @@ void graphics_draw_mode(struct graphics *this_, enum draw_mode_num mode) { * @author Martin Schaller (04/2008) */ void graphics_draw_lines(struct graphics *this_, struct graphics_gc *gc, struct point *p, int count) { - struct point * p_scaled = g_alloca(sizeof (struct point)*count); + struct point * p_scaled; int a; + if(count < ALLOCA_COORD_LIMIT) + p_scaled = g_alloca(sizeof (struct point)* count); + else + p_scaled = g_malloc(sizeof (struct point)* count); + for(a=0; a < count; a ++) p_scaled[a] = graphics_dpi_scale_point(this_,&(p[a])); this_->meth.draw_lines(this_->priv, gc->priv, p_scaled, count); + if(count >= ALLOCA_COORD_LIMIT) + g_free(p_scaled); } /** @@ -1052,8 +1063,13 @@ void graphics_draw_lines(struct graphics *this_, struct graphics_gc *gc, struct * @author Martin Schaller (04/2008) */ void graphics_draw_circle(struct graphics *this_, struct graphics_gc *gc, struct point *p, int r) { - struct point *pnt=g_alloca(sizeof(struct point)*(r*4+64)); + struct point *pnt; int i=0; + if((r*4+64) < ALLOCA_COORD_LIMIT) + pnt=g_alloca(sizeof(struct point)*(r*4+64)); + else + pnt=g_malloc(sizeof(struct point)*(r*4+64)); + if(this_->meth.draw_circle) { struct point p_scaled; p_scaled = graphics_dpi_scale_point(this_,p); @@ -1065,6 +1081,8 @@ void graphics_draw_circle(struct graphics *this_, struct graphics_gc *gc, struct i++; graphics_draw_lines(this_, gc, pnt, i); } + if((r*4+64) >= ALLOCA_COORD_LIMIT) + g_free(pnt); } /** @@ -1091,11 +1109,18 @@ static void graphics_draw_polygon(struct graphics *gra, struct graphics_gc *gc, if (! gra->meth.draw_polygon) { return; } else { - struct point * pin_scaled = g_alloca(sizeof (struct point)*count_in); + struct point * pin_scaled; int a; + if(count_in < ALLOCA_COORD_LIMIT) + pin_scaled = g_alloca(sizeof (struct point)*count_in); + else + pin_scaled = g_malloc(sizeof (struct point)*count_in); + for(a=0; a < count_in; a ++) pin_scaled[a] = graphics_dpi_scale_point(gra,&(pin[a])); gra->meth.draw_polygon(gra->priv, gc->priv, pin_scaled, count_in); + if(count_in >= ALLOCA_COORD_LIMIT) + g_free(pin_scaled); } } @@ -1120,17 +1145,16 @@ static void graphics_draw_polygon_with_holes(struct graphics *gra, struct graphi graphics_draw_polygon(gra, gc, pin, count_in); return; } else { - int limit=10000; struct point * pin_scaled; struct point ** holes_scaled; int a; int b; - if(count_in < limit) { + if(count_in < ALLOCA_COORD_LIMIT) { pin_scaled = g_alloca(sizeof (struct point)*count_in); } else { pin_scaled = g_malloc(sizeof (struct point)*count_in); } - if(hole_count < limit) { + if(hole_count < ALLOCA_COORD_LIMIT) { holes_scaled = g_alloca(sizeof (struct point *)*hole_count); } else { holes_scaled = g_malloc(sizeof (struct point *)*hole_count); @@ -1148,21 +1172,25 @@ static void graphics_draw_polygon_with_holes(struct graphics *gra, struct graphi /* free the hole arrays */ for(b=0; b < hole_count; b ++) g_free(holes_scaled[b]); - if(count_in >= limit) + if(count_in >= ALLOCA_COORD_LIMIT) g_free(pin_scaled); - if(hole_count >= limit) + if(hole_count >= ALLOCA_COORD_LIMIT) g_free(holes_scaled); } } void graphics_draw_rectangle_rounded(struct graphics *this_, struct graphics_gc *gc, struct point *plu, int w, int h, int r, int fill) { - struct point *p=g_alloca(sizeof(struct point)*(r*4+32)); + struct point *p; struct point pi0= {plu->x+r,plu->y+r}; struct point pi1= {plu->x+w-r,plu->y+r}; struct point pi2= {plu->x+w-r,plu->y+h-r}; struct point pi3= {plu->x+r,plu->y+h-r}; int i=0; + if((r*4+32) < ALLOCA_COORD_LIMIT) + p=g_alloca(sizeof(struct point)*(r*4+32)); + else + p=g_malloc(sizeof(struct point)*(r*4+32)); circle_to_points(&pi2, r*2, 0, -1, 258, p, &i, 1); circle_to_points(&pi1, r*2, 0, 255, 258, p, &i, 1); @@ -1174,6 +1202,8 @@ void graphics_draw_rectangle_rounded(struct graphics *this_, struct graphics_gc graphics_draw_polygon(this_,gc,p,i); else graphics_draw_lines(this_,gc,p,i); + if((r*4+32) >= ALLOCA_COORD_LIMIT) + g_free(p); } @@ -1243,11 +1273,18 @@ void graphics_draw_image(struct graphics *this_, struct graphics_gc *gc, struct static void graphics_draw_image_warp(struct graphics *this_, struct graphics_gc *gc, struct point *p, int count, struct graphics_image *img) { if(this_->meth.draw_image_warp) { - struct point * p_scaled = g_alloca(sizeof (struct point)*count); + struct point * p_scaled; int a; + if(count < ALLOCA_COORD_LIMIT) + p_scaled = g_alloca(sizeof (struct point)*count); + else + p_scaled = g_malloc(sizeof (struct point)*count); + for(a=0; a < count; a ++) p_scaled[a] = graphics_dpi_scale_point(this_,&(p[a])); this_->meth.draw_image_warp(this_->priv, gc->priv, p_scaled, count, img->priv); + if(count >= ALLOCA_COORD_LIMIT) + g_free(p_scaled); } else { dbg(lvl_error,"draw_image_warp not supported by graphics driver"); } @@ -2009,7 +2046,10 @@ static void graphics_draw_polyline_as_polygon(struct graphics *gra, struct graph return; ctx.shape.l=0; ctx.shape.wi=0; - ctx.res=g_alloca(sizeof(struct point)*maxpoints); + if(maxpoints < ALLOCA_COORD_LIMIT) + ctx.res=g_alloca(sizeof(struct point)*maxpoints); + else + ctx.res=g_malloc(sizeof(struct point)*maxpoints); i=0; draw_init_ctx(&ctx, maxpoints); draw_shape(&ctx, pnt, *width++); @@ -2029,6 +2069,8 @@ static void graphics_draw_polyline_as_polygon(struct graphics *gra, struct graph draw_end(&ctx,&pnt[count-1]); ctx.res[ctx.npos]=ctx.res[ctx.ppos-1]; graphics_draw_polygon(gra, gc, ctx.res+ctx.npos, ctx.ppos-ctx.npos); + if(maxpoints >= ALLOCA_COORD_LIMIT) + g_free(ctx.res); } @@ -2128,14 +2170,22 @@ static int clip_line(struct wpoint *p1, struct wpoint *p2, struct point_rect *cl */ void graphics_draw_polyline_clipped(struct graphics *gra, struct graphics_gc *gc, struct point *pa, int count, int *width, int poly) { - struct point *points_to_draw=g_alloca(sizeof(struct point)*(count+1)); - int *w=g_alloca(sizeof(int)*(count+1)); + struct point *points_to_draw; + int *w; struct wpoint segment_start,segment_end; int i,points_to_draw_cnt=0; int clip_result; int r_width, r_height; struct point_rect r=gra->r; + if(count < ALLOCA_COORD_LIMIT) { + points_to_draw=g_alloca(sizeof(struct point)*(count+1)); + w=g_alloca(sizeof(int)*(count+1)); + } else { + points_to_draw=g_malloc(sizeof(struct point)*(count+1)); + w=g_malloc(sizeof(int)*(count+1)); + } + r_width=r.rl.x-r.lu.x; r_height=r.rl.y-r.lu.y; @@ -2186,6 +2236,10 @@ void graphics_draw_polyline_clipped(struct graphics *gra, struct graphics_gc *gc } } } + if(count >= ALLOCA_COORD_LIMIT) { + g_free(points_to_draw); + g_free(w); + } } static int is_inside(struct point *p, struct point_rect *r, int edge) { @@ -2239,11 +2293,9 @@ static void poly_intersection(struct point *p1, struct point *p2, struct point_r */ static void graphics_clip_polygon(struct point_rect * r, struct point * in, int count_in, struct point *out, int* count_out) { - /* set our self a limit for the in stack buffer. To not overflow stack */ - const int limit=10000; /* get a temp buffer to store points after one direction clipping. * since we are clipping 4 directions, result is always in out at the end*/ - struct point *temp=g_alloca(sizeof(struct point) * (count_in < limit ? count_in*8+1:0)); + struct point *temp; struct point *pout; struct point *pin; int edge; @@ -2258,7 +2310,9 @@ static void graphics_clip_polygon(struct point_rect * r, struct point * in, int * 1. the output buffer * 2. temp */ - if (count_in >= limit) { + if (count_in < ALLOCA_COORD_LIMIT) { + temp=g_alloca(sizeof(struct point) * (count_in < ALLOCA_COORD_LIMIT ? count_in*8+1:0)); + } else { /* too big. Allocate a buffer (slower) */ temp=g_new(struct point, count_in*8+1); } @@ -2319,7 +2373,7 @@ static void graphics_clip_polygon(struct point_rect * r, struct point * in, int /* have clipped poly in out. And number of points now in *count_out */ /* if we had to allocate the buffer, we need to free it */ - if (count_in >= limit) { + if (count_in >= ALLOCA_COORD_LIMIT) { g_free(temp); } return; @@ -2335,14 +2389,13 @@ static void graphics_clip_polygon(struct point_rect * r, struct point * in, int */ void graphics_draw_polygon_clipped(struct graphics *gra, struct graphics_gc *gc, struct point *pin, int count_in) { struct point_rect r=gra->r; - int limit=10000; struct point *clipped; int count_out = count_in*8+1; /* prepare buffer */ - if (count_in < limit) { + if (count_in < ALLOCA_COORD_LIMIT) { /* use on stack buffer */ - clipped=g_alloca(sizeof(struct point) * (count_in < limit ? count_in*8+1:0)); + clipped=g_alloca(sizeof(struct point) * (count_in < ALLOCA_COORD_LIMIT ? count_in*8+1:0)); } else { /* too big. allocate buffer (slower) */ clipped=g_new(struct point, count_in*8+1); @@ -2352,7 +2405,7 @@ void graphics_draw_polygon_clipped(struct graphics *gra, struct graphics_gc *gc, graphics_draw_polygon(gra, gc, clipped, count_out); /* if we had to allocate buffer, free it */ - if (count_in >= limit) { + if (count_in >= ALLOCA_COORD_LIMIT) { g_free(clipped); } } @@ -2373,7 +2426,6 @@ static void graphics_draw_polygon_with_holes_clipped(struct graphics *gra, struc int count_in, int hole_count, int* ccount, struct point **holes) { int i; struct point_rect r=gra->r; - int limit=10000; struct point *clipped; int total_count_in; int count_out; @@ -2390,7 +2442,7 @@ static void graphics_draw_polygon_with_holes_clipped(struct graphics *gra, struc count_out = total_count_in*8+1+hole_count; /* prepare buffer for outer and all holes!*/ - if (count_out < limit) { + if (count_out < ALLOCA_COORD_LIMIT) { /* use on stack buffer */ clipped=g_alloca(sizeof(struct point) * count_out); /* no need to free on stack buffer */ @@ -2404,7 +2456,7 @@ static void graphics_draw_polygon_with_holes_clipped(struct graphics *gra, struc count_used=0; /* prepare arrays for new holes */ - if(hole_count < limit) { + if(hole_count < ALLOCA_COORD_LIMIT) { found_ccount=g_alloca(sizeof(int)* hole_count); found_holes=g_alloca(sizeof(struct point*)* hole_count); } else { @@ -2431,7 +2483,7 @@ static void graphics_draw_polygon_with_holes_clipped(struct graphics *gra, struc } /* call drawing function */ graphics_draw_polygon_with_holes(gra, gc, clipped, count_out, found_hole_count, found_ccount, found_holes); - if(hole_count >= limit) { + if(hole_count >= ALLOCA_COORD_LIMIT) { g_free(found_ccount); g_free(found_holes); } @@ -2763,13 +2815,21 @@ static inline void displayitem_draw_image (struct displayitem *di, struct displa * @brief dc The display_context to use to draw items */ static void displayitem_draw(struct displayitem *di, struct layout *l, struct display_context *dc) { - int *width=g_alloca(sizeof(int)*dc->maxlen); + int *width; int limit=0; - struct point *pa=g_alloca(sizeof(struct point)*dc->maxlen); + struct point *pa; struct graphics *gra=dc->gra; struct element *e=dc->e; int draw_underground=0; + if (dc->maxlen < ALLOCA_COORD_LIMIT) { + width=g_alloca(sizeof(int)*dc->maxlen); + pa=g_alloca(sizeof(struct point)*dc->maxlen); + } else { + width=g_malloc(sizeof(int)*dc->maxlen); + pa=g_malloc(sizeof(struct point)*dc->maxlen); + } + while (di) { int count=di->count,mindist=dc->mindist; struct displayitem_poly_holes t_holes; @@ -2852,6 +2912,10 @@ static void displayitem_draw(struct displayitem *di, struct layout *l, struct di di=di->next; } + if (dc->maxlen >= ALLOCA_COORD_LIMIT) { + g_free(width); + g_free(pa); + } } /** * FIXME @@ -2888,8 +2952,15 @@ void graphics_draw_itemgra(struct graphics *gra, struct itemgra *itm, struct tra GList *es; struct display_context dc; int max_coord=32; - char *buffer=g_alloca(sizeof(struct displayitem)+max_coord*sizeof(struct coord)); - struct displayitem *di=(struct displayitem *)buffer; + char *buffer; + struct displayitem *di; + if (max_coord < ALLOCA_COORD_LIMIT) { + buffer=g_alloca(sizeof(struct displayitem)+max_coord*sizeof(struct coord)); + } else { + buffer=g_malloc(sizeof(struct displayitem)+max_coord*sizeof(struct coord)); + } + di=(struct displayitem *)buffer; + es=itm->elements; di->item.type=type_none; di->item.id_hi=0; @@ -2927,6 +2998,9 @@ void graphics_draw_itemgra(struct graphics *gra, struct itemgra *itm, struct tra display_context_free(&dc); es=g_list_next(es); } + if (max_coord >= ALLOCA_COORD_LIMIT) { + g_free(buffer); + } } /** @@ -3061,9 +3135,19 @@ GList *displaylist_get_clicked_list(struct displaylist *displaylist, struct poin static void do_draw(struct displaylist *displaylist, int cancel, int flags) { struct item *item; int count,max=displaylist->dc.maxlen,workload=0; - struct coord *ca=g_alloca(sizeof(struct coord)*max); + int used=0; + struct coord *ca; struct attr attr,attr2; enum projection pro; + int need_free=0; + + if (max < ALLOCA_COORD_LIMIT) { + ca=g_alloca(sizeof(struct coord)*max); + need_free=0; + } else { + ca=g_malloc(sizeof(struct coord)*max); + need_free=1; + } if (displaylist->order != displaylist->order_hashed || displaylist->layout != displaylist->layout_hashed) { displaylist_update_hash(displaylist); @@ -3095,24 +3179,59 @@ static void do_draw(struct displaylist *displaylist, int cancel, int flags) { int label_count=0; char *labels[2]; struct hash_entry *entry; + int coords_left; if (item == &busy_item) { - if (displaylist->workload) + if (displaylist->workload) { + if (need_free) { + g_free(ca); + } return; - else + } else continue; } entry=get_hash_entry(displaylist, item->type); if (!entry) continue; count=item_coord_get_within_selection(item, ca, item->type < type_line ? 1: max, displaylist->sel); + /* abort if no coordinates within selection at all */ if (! count) continue; - if (displaylist->dc.pro != pro) - transform_from_to_count(ca, displaylist->dc.pro, ca, pro, count); + /* handle overflow */ if (count == max) { - dbg(lvl_error,"point count overflow %d for %s "ITEM_ID_FMT"", count,item_to_name(item->type),ITEM_ID_ARGS(*item)); - displaylist->dc.maxlen=max*2; + /* get required space */ + item_coord_rewind(item); + coords_left=item_coords_left(item); + /* increase to required space, or double space if we couldn't get required space */ + if(coords_left > 0) { + displaylist->dc.maxlen=(coords_left+2); + } else { + displaylist->dc.maxlen=max*2; + } + dbg(lvl_error,"point count overflow %d for %s "ITEM_ID_FMT". Increase to %d", count,item_to_name(item->type), + ITEM_ID_ARGS(*item), displaylist->dc.maxlen); + /* remember the new maximum */ + max=displaylist->dc.maxlen; + /* get more memory */ + if(need_free) + g_free(ca); + ca=g_malloc(sizeof(struct coord)*(displaylist->dc.maxlen)); + need_free=1; + /* try again to get coordinates */ + item_coord_rewind(item); + count=item_coord_get_within_selection(item, ca, item->type < type_line ? 1: max, displaylist->sel); + /* check if we got valid coordinates in second attempt. If not don't try to draw this at all */ + if(count <= 0) { + continue; + } } + /* transform the coordinates */ + if (displaylist->dc.pro != pro) + transform_from_to_count(ca, displaylist->dc.pro, ca, pro, count); + + /* remember the peak coordinates actually used */ + if(used < count) + used=count; + if (item_is_custom_poi(*item)) { if (item_attr_get(item, attr_icon_src, &attr2)) labels[1]=map_convert_string(displaylist->m, attr2.u.str); @@ -3138,8 +3257,12 @@ static void do_draw(struct displaylist *displaylist, int cancel, int flags) { if (labels[1]) map_convert_free(labels[1]); workload++; - if (workload == displaylist->workload) + if (workload == displaylist->workload) { + if (need_free) { + g_free(ca); + } return; + } } map_rect_destroy(displaylist->mr); } @@ -3170,6 +3293,15 @@ static void do_draw(struct displaylist *displaylist, int cancel, int flags) { displaylist->msh=NULL; profile(1,"callback\n"); callback_call_1(displaylist->cb, cancel); + /* check if we can shrink item buffer next time */ + if((displaylist->dc.maxlen > ALLOCA_COORD_LIMIT) && (used < ALLOCA_COORD_LIMIT)) { + dbg(lvl_debug, "Shrink memory. %d actually used", used); + displaylist->dc.maxlen=ALLOCA_COORD_LIMIT; + } + /* clean up if required */ + if (need_free) { + g_free(ca); + } profile(0,"end\n"); } @@ -3336,7 +3468,7 @@ void graphics_displaylist_close(struct displaylist_handle *dlh) { struct displaylist * graphics_displaylist_new(void) { struct displaylist *ret=g_new0(struct displaylist, 1); - ret->dc.maxlen=16384; + ret->dc.maxlen=ALLOCA_COORD_LIMIT; return ret; } @@ -3503,18 +3635,28 @@ static int within_dist_polygon(struct point *p, struct point *poly_pnt, int coun */ int graphics_displayitem_within_dist(struct displaylist *displaylist, struct displayitem *di, struct point *p, int dist) { - struct point *pa=g_alloca(sizeof(struct point)*displaylist->dc.maxlen); + int result; + struct point *pa; int count; + if (displaylist->dc.maxlen < ALLOCA_COORD_LIMIT) { + pa=g_alloca(sizeof(struct point)*displaylist->dc.maxlen); + } else { + pa=g_malloc(sizeof(struct point)*displaylist->dc.maxlen); + } count=transform(displaylist->dc.trans, displaylist->dc.pro, di->c, pa, di->count, 0, 0, NULL); if (di->item.type < type_line) { - return within_dist_point(p, &pa[0], dist); - } - if (di->item.type < type_area) { - return within_dist_polyline(p, pa, count, dist, 0); + result = within_dist_point(p, &pa[0], dist); + } else if (di->item.type < type_area) { + result = within_dist_polyline(p, pa, count, dist, 0); + } else + result = within_dist_polygon(p, pa, count, dist); + + if (displaylist->dc.maxlen >= ALLOCA_COORD_LIMIT) { + g_free(pa); } - return within_dist_polygon(p, pa, count, dist); + return result; } diff --git a/navit/item.c b/navit/item.c index c17f31f8b..ab590cb4e 100644 --- a/navit/item.c +++ b/navit/item.c @@ -164,6 +164,22 @@ int item_coord_get(struct item *it, struct coord *c, int count) { return it->meth->item_coord_get(it->priv_data, c, count); } +/** + * @brief Gets the number of coordinates left for this item + * + * This function returnes the number of coordinates left to get for this item. It does not + * change the "coordinates pointer". + * + * @param it The map item + * @returns The number of coordinates left. -1 if not supported by the actual map. + */ +int item_coords_left(struct item * it) { + if(!it->meth->item_coords_left) { + return (-1); + } + return it->meth->item_coords_left(it->priv_data); +} + /** * @brief Sets coordinates of an item * @@ -195,33 +211,69 @@ int item_coord_set(struct item *it, struct coord *c, int count, enum change_mode return it->meth->item_coord_set(it->priv_data, c, count, mode); } +/** + * @brief Get coordinates within selection + * This function returns the coordinates of an item if at least one coordinate of that item is inside the + * selection. If the given buffer is too small, it returns the buffer size if at least one coordinate + * intersects with the selection, otherwise it returnes 0 + * + * If the return value equals count, the content of c is undefined. + * + * @param it requested item + * @param c preallocated buffer for the result + * @param count number of coordinates in c + * @param sel current map selection + * @return number of coordinates read to c, or count if out of space, or 0 if not intersecting, or <0 on read error. + */ int item_coord_get_within_selection(struct item *it, struct coord *c, int count, struct map_selection *sel) { - int i,ret=it->meth->item_coord_get(it->priv_data, c, count); - struct coord_rect r; - struct map_selection *curr; - if (ret <= 0 || !sel) - return ret; - r.lu=c[0]; - r.rl=c[0]; - for (i = 1 ; i < ret ; i++) { - if (r.lu.x > c[i].x) - r.lu.x=c[i].x; - if (r.rl.x < c[i].x) - r.rl.x=c[i].x; - if (r.rl.y > c[i].y) - r.rl.y=c[i].y; - if (r.lu.y < c[i].y) - r.lu.y=c[i].y; - } - curr=sel; - while (curr) { - struct coord_rect *sr=&curr->u.c_rect; - if (r.lu.x <= sr->rl.x && r.rl.x >= sr->lu.x && - r.lu.y >= sr->rl.y && r.rl.y <= sr->lu.y) - return ret; - curr=curr->next; + int in_coords; + int ret = 0; + struct coord_rect bbox; + int intersects=0; + + /* scan all coordinates. Even if buffer is too small */ + while ((in_coords=item_coord_get(it, c, count)) > 0) { + int i; + struct map_selection *curr; + /* update ret */ + if(ret == 0) { + ret=in_coords; + /* init bbox */ + bbox.lu=c[0]; + bbox.rl=c[0]; + } + + /* update bbox */ + for (i = 0 ; i < in_coords ; i++) { + if (bbox.lu.x > c[i].x) + bbox.lu.x=c[i].x; + if (bbox.rl.x < c[i].x) + bbox.rl.x=c[i].x; + if (bbox.rl.y > c[i].y) + bbox.rl.y=c[i].y; + if (bbox.lu.y < c[i].y) + bbox.lu.y=c[i].y; + } + /* check if bbox intersects already with selection */ + curr=sel; + while ((!intersects) && (curr)) { + struct coord_rect *sr=&curr->u.c_rect; + if (bbox.lu.x <= sr->rl.x && bbox.rl.x >= sr->lu.x && + bbox.lu.y >= sr->rl.y && bbox.rl.y <= sr->lu.y) + intersects=1; + curr=curr->next; + } + + /* abort on the special case to read only one coord. */ + if(count == 1) + break; + /* we can abort if already intersecting. */ + if(intersects) + break; } - return 0; + if(!intersects) + ret=0; + return ret; } /** diff --git a/navit/item.h b/navit/item.h index 0d0e84c7f..26c83cd72 100644 --- a/navit/item.h +++ b/navit/item.h @@ -83,6 +83,7 @@ struct item_methods { int (*item_attr_set)(void *priv_data, struct attr *attr, enum change_mode mode); int (*item_coord_set)(void *priv_data, struct coord *c, int count, enum change_mode mode); int (*item_type_set)(void *priv_data, enum item_type type); + int (*item_coords_left)(void *priv_data); }; struct item_id { @@ -127,6 +128,7 @@ void item_create_hash(void); void item_destroy_hash(void); int *item_get_default_flags(enum item_type type); void item_coord_rewind(struct item *it); +int item_coords_left(struct item * it); int item_coord_get(struct item *it, struct coord *c, int count); int item_coord_set(struct item *it, struct coord *c, int count, enum change_mode mode); int item_coord_get_within_selection(struct item *it, struct coord *c, int count, struct map_selection *sel); diff --git a/navit/map/binfile/binfile.c b/navit/map/binfile/binfile.c index 7cc707ac8..18a4166b1 100644 --- a/navit/map/binfile/binfile.c +++ b/navit/map/binfile/binfile.c @@ -453,6 +453,15 @@ static int binfile_coord_get(void *priv_data, struct coord *c, int count) { return ret; } +/** + * @brief Get nuber of coords left for current item + * + * @param prv_data + */ +static int binfile_coords_left(void *priv_data) { + return binfile_coord_left(priv_data); +} + /** * @brief * @param @@ -829,6 +838,8 @@ static struct item_methods methods_binfile = { NULL, binfile_attr_set, binfile_coord_set, + NULL, + binfile_coords_left, }; static void push_tile(struct map_rect_priv *mr, struct tile *t, int offset, int length) { -- cgit v1.2.1