"Fossies" - the Fresh Open Source Software Archive

Member "navit-0.5.6/navit/map.c" (6 Mar 2021, 22097 Bytes) of package /linux/privat/navit-0.5.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "map.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.5.5_vs_0.5.6.

    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 /** @file
   21  *
   22  * @brief Contains code that makes navit able to load maps
   23  *
   24  * This file contains the code that makes navit able to load maps. Because
   25  * navit is able to open maps in different formats, this code does not handle
   26  * any map format itself. This is done by map plugins which register to this
   27  * code by calling plugin_register_category_map().
   28  *
   29  * When opening a new map, the map plugin will return a pointer to a map_priv
   30  * struct, which can be defined by the map plugin and contains whatever private
   31  * data the map plugin needs to access the map. This pointer will also be used
   32  * as a "handle" to access the map opened.
   33  *
   34  * A common task is to create a "map rect". A map rect is a rectangular part of
   35  * the map, that one can for example retrieve items from. It is not possible to
   36  * retrieve items directly from the complete map. Creating a map rect returns a
   37  * pointer to a map_rect_priv, which contains private data for the map rect and
   38  * will be used as "handle" for this map rect.
   39  */
   40 
   41 #include <glib.h>
   42 #include <string.h>
   43 #include "debug.h"
   44 #include "coord.h"
   45 #include "projection.h"
   46 #include "item.h"
   47 #include "map.h"
   48 #include "maptype.h"
   49 #include "transform.h"
   50 #include "plugin.h"
   51 #include "callback.h"
   52 #include "country.h"
   53 #include "xmlconfig.h"
   54 
   55 struct map {
   56     NAVIT_OBJECT
   57     struct map_methods meth;            /**< Structure with pointers to the map plugin's functions */
   58     struct map_priv *priv;              /**< Private data of the map, only known to the map plugin */
   59     struct callback_list *attr_cbl;     /**< List of callbacks that are called when attributes change */
   60 };
   61 
   62 struct map_rect {
   63     struct map *m;              /**< The map this extract is from */
   64     struct map_rect_priv *priv; /**< Private data of this map rect, only known to the map plugin */
   65 };
   66 
   67 /**
   68  * @brief Opens a new map
   69  *
   70  * This function opens a new map based on the attributes passed. This function
   71  * takes the attribute "attr_type" to determine which type of map to open and passes
   72  * all attributes to the map plugin's function that was specified in the
   73  * plugin_register_new_map_type()-call.
   74  *
   75  * Note that every plugin should accept an attribute of type "attr_data" to be passed
   76  * with the filename of the map to be opened as value.
   77  *
   78  * @param attrs Attributes specifying which map to open, see description
   79  * @return The opened map or NULL on failure
   80  */
   81 struct map *
   82 map_new(struct attr *parent, struct attr **attrs) {
   83     struct map *m;
   84     struct map_priv *(*maptype_new)(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl);
   85     struct attr *type=attr_search(attrs, attr_type);
   86 
   87     if (! type) {
   88         dbg(lvl_error,"missing type");
   89         return NULL;
   90     }
   91     maptype_new=plugin_get_category_map(type->u.str);
   92     if (! maptype_new) {
   93         dbg(lvl_error,"invalid type '%s'", type->u.str);
   94         return NULL;
   95     }
   96 
   97     m=g_new0(struct map, 1);
   98     m->attrs=attr_list_dup(attrs);
   99     m->func=&map_func;
  100     navit_object_ref((struct navit_object *)m);
  101     m->attr_cbl=callback_list_new();
  102     m->priv=maptype_new(&m->meth, attrs, m->attr_cbl);
  103     if (! m->priv) {
  104         map_destroy(m);
  105         m=NULL;
  106     }
  107     return m;
  108 }
  109 
  110 /**
  111  * @brief Gets an attribute from a map
  112  *
  113  * @param this_ The map the attribute should be read from
  114  * @param type The type of the attribute to be read
  115  * @param attr Pointer to an attrib-structure where the attribute should be written to
  116  * @param iter (NOT IMPLEMENTED) Used to iterate through all attributes of a type. Set this to NULL to get the first attribute, set this to an attr_iter to get the next attribute
  117  * @return True if the attribute type was found, false if not
  118  */
  119 int map_get_attr(struct map *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter) {
  120     int ret=0;
  121     if (this_->meth.map_get_attr)
  122         ret=this_->meth.map_get_attr(this_->priv, type, attr);
  123     if (!ret)
  124         ret=attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
  125     if (!ret && type == attr_active) {
  126         attr->type=type;
  127         attr->u.num=1;
  128         return 1;
  129     }
  130     return ret;
  131 }
  132 
  133 /**
  134  * @brief Sets an attribute of a map
  135  *
  136  * This sets an attribute of a map, overwriting an attribute of the same type if it
  137  * already exists. This function also calls all the callbacks that are registred
  138  * to be called when attributes change.
  139  *
  140  * @param this_ The map to set the attribute of
  141  * @param attr The attribute to set
  142  * @return True if the attr could be set, false otherwise
  143  */
  144 int map_set_attr(struct map *this_, struct attr *attr) {
  145     this_->attrs=attr_generic_set_attr(this_->attrs, attr);
  146     if (this_->meth.map_set_attr)
  147         this_->meth.map_set_attr(this_->priv, attr);
  148     callback_list_call_attr_2(this_->attr_cbl, attr->type, this_, attr);
  149     return 1;
  150 }
  151 
  152 /**
  153  * @brief Registers a new callback for attribute-change
  154  *
  155  * This function registers a new callback function that should be called if the attributes
  156  * of the map change.
  157  *
  158  * @param this_ The map to associate the callback with
  159  * @param cb The callback to add
  160  */
  161 void map_add_callback(struct map *this_, struct callback *cb) {
  162     callback_list_add(this_->attr_cbl, cb);
  163 }
  164 
  165 /**
  166  * @brief Removes a callback from the list of attribute-change callbacks
  167  *
  168  * This function removes one callback from the list of callbacks functions that should be called
  169  * when attributes of the map change.
  170  *
  171  * @param this_ The map to remove the callback from
  172  * @param cb The callback to remove
  173  */
  174 void map_remove_callback(struct map *this_, struct callback *cb) {
  175     callback_list_remove(this_->attr_cbl, cb);
  176 }
  177 
  178 
  179 /**
  180  * @brief Checks if strings from a map have to be converted
  181  *
  182  * @param this_ Map to be checked for the need to convert strings
  183  * @return True if strings from the map have to be converted, false otherwise
  184  */
  185 int map_requires_conversion(struct map *this_) {
  186     return (this_->meth.charset != NULL && strcmp(this_->meth.charset, "utf-8"));
  187 }
  188 
  189 char *map_converted_string_tmp=NULL;
  190 
  191 /**
  192  * @brief Converts a string from a map into a temporary allocated buffer. Conversion is not performed and original string is returned
  193  * if map doesn't require conversion. So lifetime of returned value is very limited.
  194  *
  195  * @param this_ The map the string to be converted is from
  196  * @param str The string to be converted
  197  * @return The converted string. Don't care about it after use.
  198  */
  199 char *map_convert_string_tmp(struct map *this_, char *str) {
  200     if(map_converted_string_tmp!=NULL)
  201         g_free(map_converted_string_tmp);
  202     map_converted_string_tmp=NULL;
  203     if(!this_ || !this_->meth.charset || !strcmp(this_->meth.charset, "utf-8"))
  204         return str;
  205     map_converted_string_tmp=g_convert(str, -1, "utf-8", this_->meth.charset, NULL, NULL, NULL);
  206     if(!map_converted_string_tmp) {
  207         dbg(lvl_error,"Error converting '%s' from %s to utf-8", str, this_->meth.charset);
  208         return str;
  209     }
  210     return map_converted_string_tmp;
  211 }
  212 
  213 /**
  214  * @brief Converts a string from a map
  215  *
  216  * @param this_ The map the string to be converted is from
  217  * @param str The string to be converted
  218  * @return The converted string. It has to be map_convert_free()d after use.
  219  */
  220 char *map_convert_string(struct map *this_, char *str) {
  221     return map_convert_dup(map_convert_string_tmp(this_,str));
  222 }
  223 
  224 
  225 char *map_convert_dup(char *str) {
  226     if(map_converted_string_tmp==str) {
  227         map_converted_string_tmp=NULL;
  228         return str;
  229     }
  230     return g_strdup(str);
  231 }
  232 
  233 /**
  234  * @brief Frees the memory allocated for a converted string
  235  *
  236  * @param str The string to be freed
  237  */
  238 void map_convert_free(char *str) {
  239     g_free(str);
  240 }
  241 
  242 /**
  243  * @brief Returns the projection of a map
  244  *
  245  * @param this_ The map to return the projection of
  246  * @return The projection of the map
  247  */
  248 enum projection map_projection(struct map *this_) {
  249     return this_->meth.pro;
  250 }
  251 
  252 /**
  253  * @brief Sets the projection of a map
  254  *
  255  * @param this_ The map to set the projection of
  256  * @param pro The projection to be set
  257  */
  258 void map_set_projection(struct map *this_, enum projection pro) {
  259     this_->meth.pro=pro;
  260 }
  261 
  262 /**
  263  * @brief Destroys an opened map
  264  *
  265  * @param m The map to be destroyed
  266  */
  267 
  268 void map_destroy(struct map *m) {
  269     if (!m)
  270         return;
  271     if (m->priv)
  272         m->meth.map_destroy(m->priv);
  273     attr_list_free(m->attrs);
  274     callback_list_destroy(m->attr_cbl);
  275     g_free(m);
  276 }
  277 
  278 /**
  279  * @brief Creates a new map rect
  280  *
  281  * This creates a new map rect, which can be used to retrieve items from a map. If
  282  * sel is a linked-list of selections, all of them will be used. If you pass NULL as
  283  * sel, this means "get me the whole map".
  284  *
  285  * @param m The map to build the rect on
  286  * @param sel Map selection to choose the rectangle - may be NULL, see description
  287  * @return A new map rect
  288  */
  289 struct map_rect *
  290 map_rect_new(struct map *m, struct map_selection *sel) {
  291     struct map_rect *mr;
  292 
  293 #if 0
  294     printf("map_rect_new 0x%x,0x%x-0x%x,0x%x\n", r->lu.x, r->lu.y, r->rl.x, r->rl.y);
  295 #endif
  296     mr=g_new0(struct map_rect, 1);
  297     mr->m=m;
  298     mr->priv=m->meth.map_rect_new(m->priv, sel);
  299     if (! mr->priv) {
  300         g_free(mr);
  301         mr=NULL;
  302     }
  303 
  304     return mr;
  305 }
  306 
  307 /**
  308  * @brief Gets the next item from a map rect
  309  *
  310  * Returns an item from a map rect and advances the "item pointer" one step further,
  311  * so that at the next call the next item is returned. Returns NULL if there are no more items.
  312  *
  313  * @param mr The map rect to return an item from
  314  * @return An item from the map rect
  315  */
  316 struct item *
  317 map_rect_get_item(struct map_rect *mr) {
  318     struct item *ret;
  319     dbg_assert(mr != NULL);
  320     dbg_assert(mr->m != NULL);
  321     dbg_assert(mr->m->meth.map_rect_get_item != NULL);
  322     ret=mr->m->meth.map_rect_get_item(mr->priv);
  323     if (ret)
  324         ret->map=mr->m;
  325     return ret;
  326 }
  327 
  328 /**
  329  * @brief Returns the item specified by the ID
  330  *
  331  * Map drivers may or may not allow multiple items with identical IDs. This function is not guaranteed to be
  332  * suitable for iterating over multiple items with identical IDs in the same manner as `map_rect_get_item()`,
  333  * as multiple subsequent calls may return items which were already returned by earlier calls.
  334  *
  335  * If you are working with maps which allow multiple items with identical IDs, the only portable way to
  336  * iterate over all items with a given ID is to use `map_rect_get_item()` and skip all items with
  337  * non-matching IDs.
  338  *
  339  * @param mr The map rect to search for the item
  340  * @param id_hi High part of the ID to be found
  341  * @param id_lo Low part of the ID to be found
  342  * @return The item with the specified ID or NULL if not found
  343  */
  344 struct item *
  345 map_rect_get_item_byid(struct map_rect *mr, int id_hi, int id_lo) {
  346     struct item *ret=NULL;
  347     dbg_assert(mr != NULL);
  348     dbg_assert(mr->m != NULL);
  349     if (mr->m->meth.map_rect_get_item_byid)
  350         ret=mr->m->meth.map_rect_get_item_byid(mr->priv, id_hi, id_lo);
  351     if (ret)
  352         ret->map=mr->m;
  353     return ret;
  354 }
  355 
  356 /**
  357  * @brief Destroys a map rect
  358  *
  359  * @param mr The map rect to be destroyed
  360  */
  361 void map_rect_destroy(struct map_rect *mr) {
  362     if (mr) {
  363         mr->m->meth.map_rect_destroy(mr->priv);
  364         g_free(mr);
  365     }
  366 }
  367 
  368 struct map_search {
  369     struct map *m;
  370     struct attr search_attr;
  371     void *priv;
  372 };
  373 
  374 /**
  375  * @brief Starts a search on a map
  376  *
  377  * This function starts a search on a map. What attributes one can search for depends on the
  378  * map plugin.
  379  *
  380  * The OSM/binfile plugin currently supports: attr_town_name, attr_street_name
  381  * The MG plugin currently supports: ttr_town_postal, attr_town_name, attr_street_name
  382  *
  383  * If you enable partial matches bear in mind that the search matches only the begin of the
  384  * strings - a search for a street named "street" would match to "streetfoo", but not to
  385  * "somestreet". Search is case insensitive.
  386  *
  387  * The item passed to this function specifies a "superior item" to "search within" - e.g. a town
  388  * in which we want to search for a street, or a country in which to search for a town.
  389  *
  390  * Please also note that the search for countries is not handled by map plugins but by navit internally -
  391  * have a look into country.c for details. Because of that every map plugin has to accept a country item
  392  * to be passed as "superior item".
  393  *
  394  * Note: If you change something here, please make sure to also update the documentation of mapset_search_new()
  395  * in mapset.c!
  396  *
  397  * @param m The map that should be searched
  398  * @param item Specifies a superior item to "search within" (see description)
  399  * @param search_attr Attribute specifying what to search for. See description.
  400  * @param partial Set this to true to also have partial matches. See description.
  401  * @return A new map search struct for this search
  402  */
  403 struct map_search *
  404 map_search_new(struct map *m, struct item *item, struct attr *search_attr, int partial) {
  405     struct map_search *this_;
  406     dbg(lvl_debug,"enter(%p,%p,%p,%d)", m, item, search_attr, partial);
  407     dbg(lvl_debug,"0x%x 0x%x 0x%x", attr_country_all, search_attr->type, attr_country_name);
  408     this_=g_new0(struct map_search,1);
  409     this_->m=m;
  410     this_->search_attr=*search_attr;
  411     if ((search_attr->type >= attr_country_all && search_attr->type <= attr_country_name)
  412             || search_attr->type == attr_country_id)
  413         this_->priv=country_search_new(&this_->search_attr, partial);
  414     else {
  415         if (m->meth.map_search_new) {
  416             if (m->meth.charset)
  417                 this_->search_attr.u.str=g_convert(this_->search_attr.u.str, -1,m->meth.charset,"utf-8",NULL,NULL,NULL);
  418             this_->priv=m->meth.map_search_new(m->priv, item, &this_->search_attr, partial);
  419             if (! this_->priv) {
  420                 g_free(this_);
  421                 this_=NULL;
  422             }
  423         } else {
  424             g_free(this_);
  425             this_=NULL;
  426         }
  427     }
  428     return this_;
  429 }
  430 
  431 /**
  432  * @brief Returns an item from a map search
  433  *
  434  * This returns an item of the result of a search on a map and advances the "item pointer" one step,
  435  * so that at the next call the next item will be returned. If there are no more items in the result
  436  * NULL is returned.
  437  *
  438  * @param this_ Map search struct of the search
  439  * @return One item of the result
  440  */
  441 struct item *
  442 map_search_get_item(struct map_search *this_) {
  443     struct item *ret;
  444 
  445     if (! this_)
  446         return NULL;
  447     if ((this_->search_attr.type >= attr_country_all && this_->search_attr.type <= attr_country_name)
  448             || this_->search_attr.type == attr_country_id)
  449         return country_search_get_item(this_->priv);
  450     ret=this_->m->meth.map_search_get_item(this_->priv);
  451     if (ret)
  452         ret->map=this_->m;
  453     return ret;
  454 }
  455 
  456 /**
  457  * @brief Destroys a map search struct
  458  *
  459  * @param this_ The map search struct to be destroyed
  460  */
  461 void map_search_destroy(struct map_search *this_) {
  462     if (! this_)
  463         return;
  464     if (this_->search_attr.type >= attr_country_all && this_->search_attr.type <= attr_country_name)
  465         country_search_destroy(this_->priv);
  466     else {
  467         if (this_->m->meth.charset)
  468             g_free(this_->search_attr.u.str);
  469         this_->m->meth.map_search_destroy(this_->priv);
  470     }
  471     g_free(this_);
  472 }
  473 
  474 /**
  475  * @brief Creates a new rectangular map selection
  476  *
  477  * @param center Coordinates of the center of the new rectangle
  478  * @param distance Distance of the rectangle's borders from the center
  479  * @param order Desired order of the new selection
  480  * @return The new map selection
  481  */
  482 struct map_selection *
  483 map_selection_rect_new(struct pcoord *center, int distance, int order) {
  484     struct map_selection *ret=g_new0(struct map_selection, 1);
  485     ret->order=order;
  486     ret->range=item_range_all;
  487     ret->u.c_rect.lu.x=center->x-distance;
  488     ret->u.c_rect.lu.y=center->y+distance;
  489     ret->u.c_rect.rl.x=center->x+distance;
  490     ret->u.c_rect.rl.y=center->y-distance;
  491     return ret;
  492 }
  493 
  494 /**
  495  * @brief Duplicates a map selection, transforming coordinates
  496  *
  497  * This duplicates a map selection and at the same time transforms the internal
  498  * coordinates of the selection from one projection to another.
  499  *
  500  * @param sel The map selection to be duplicated
  501  * @param from The projection used for the selection at the moment
  502  * @param to The projection that should be used for the duplicated selection
  503  * @return A duplicated, transformed map selection
  504  */
  505 struct map_selection *
  506 map_selection_dup_pro(struct map_selection *sel, enum projection from, enum projection to) {
  507     struct map_selection *next,**last;
  508     struct map_selection *ret=NULL;
  509     last=&ret;
  510     while (sel) {
  511         next = g_new(struct map_selection, 1);
  512         *next=*sel;
  513         if (from != projection_none || to != projection_none) {
  514             transform_from_to(&sel->u.c_rect.lu, from, &next->u.c_rect.lu, to);
  515             transform_from_to(&sel->u.c_rect.rl, from, &next->u.c_rect.rl, to);
  516         }
  517         *last=next;
  518         last=&next->next;
  519         sel = sel->next;
  520     }
  521     return ret;
  522 }
  523 
  524 /**
  525  * @brief Duplicates a map selection
  526  *
  527  * @param sel The map selection to duplicate
  528  * @return The duplicated map selection
  529  */
  530 struct map_selection *
  531 map_selection_dup(struct map_selection *sel) {
  532     return map_selection_dup_pro(sel, projection_none, projection_none);
  533 }
  534 
  535 /**
  536  * @brief Destroys a map selection
  537  *
  538  * @param sel The map selection to be destroyed
  539  */
  540 void map_selection_destroy(struct map_selection *sel) {
  541     struct map_selection *next;
  542     while (sel) {
  543         next = sel->next;
  544         g_free(sel);
  545         sel = next;
  546     }
  547 }
  548 
  549 /**
  550  * @brief Checks if a selection contains a rectangle containing an item
  551  *
  552  * This function checks if a selection contains a rectangle which exactly contains
  553  * an item. The rectangle is automatically built around the given item.
  554  *
  555  * @param sel The selection to be checked
  556  * @param item The item that the rectangle should be built around
  557  * @return True if the rectangle is within the selection, false otherwise
  558  */
  559 int map_selection_contains_item_rect(struct map_selection *sel, struct item *item) {
  560     struct coord c;
  561     struct coord_rect r;
  562     int count=0;
  563     while (item_coord_get(item, &c, 1)) {
  564         if (! count) {
  565             r.lu=c;
  566             r.rl=c;
  567         } else
  568             coord_rect_extend(&r, &c);
  569         count++;
  570     }
  571     if (! count)
  572         return 0;
  573     return map_selection_contains_rect(sel, &r);
  574 
  575 }
  576 
  577 
  578 /**
  579  * @brief Checks if a selection contains a item range
  580  *
  581  * This function checks if a selection contains at least one of the items in range
  582  *
  583  * @param sel The selection to be checked
  584  * @param follow Whether the next pointer of the selection should be followed
  585  * @param ranges The item ranges to be checked
  586  * @count the number of elements in ranges
  587  * @return True if there is a match, false otherwise
  588  */
  589 
  590 int map_selection_contains_item_range(struct map_selection *sel, int follow, struct item_range *range, int count) {
  591     int i;
  592     if (! sel)
  593         return 1;
  594     while (sel) {
  595         for (i = 0 ; i < count ; i++) {
  596             if (item_range_intersects_range(&sel->range, &range[i]))
  597                 return 1;
  598         }
  599         if (! follow)
  600             break;
  601         sel=sel->next;
  602     }
  603     return 0;
  604 }
  605 /**
  606  * @brief Checks if a selection contains a item
  607  *
  608  * This function checks if a selection contains a item type
  609  *
  610  * @param sel The selection to be checked
  611  * @param follow Whether the next pointer of the selection should be followed
  612  * @param item The item type to be checked
  613  * @return True if there is a match, false otherwise
  614  */
  615 
  616 int map_selection_contains_item(struct map_selection *sel, int follow, enum item_type type) {
  617     if (! sel)
  618         return 1;
  619     while (sel) {
  620         if (item_range_contains_item(&sel->range, type))
  621             return 1;
  622         if (! follow)
  623             break;
  624         sel=sel->next;
  625     }
  626     return 0;
  627 }
  628 
  629 
  630 
  631 /**
  632  * @brief Checks if a pointer points to the private data of a map
  633  *
  634  * @param map The map whose private data should be checked.
  635  * @param priv The private data that should be checked.
  636  * @return True if priv is the private data of map
  637  */
  638 int map_priv_is(struct map *map, struct map_priv *priv) {
  639     return (map->priv == priv);
  640 }
  641 
  642 void map_dump_filedesc(struct map *map, FILE *out) {
  643     struct map_rect *mr=map_rect_new(map, NULL);
  644     struct item *item;
  645 
  646     while ((item = map_rect_get_item(mr)))
  647         item_dump_filedesc(item, map, out);
  648     map_rect_destroy(mr);
  649 }
  650 
  651 void map_dump_file(struct map *map, const char *file) {
  652     FILE *f;
  653     f=fopen(file,"w");
  654     if (f) {
  655         map_dump_filedesc(map, f);
  656         fclose(f);
  657     } else
  658         dbg(lvl_error,"failed to open file '%s'",file);
  659 }
  660 
  661 void map_dump(struct map *map) {
  662     map_dump_filedesc(map, stdout);
  663 }
  664 
  665 struct item *
  666 map_rect_create_item(struct map_rect *mr, enum item_type type_) {
  667     if(mr && mr->priv && mr->m) {
  668         return mr->m->meth.map_rect_create_item(mr->priv, type_) ;
  669     } else {
  670         return NULL;
  671     }
  672 }
  673 
  674 struct object_func map_func = {
  675     attr_map,
  676     (object_func_new)map_new,
  677     (object_func_get_attr)map_get_attr,
  678     (object_func_iter_new)NULL,
  679     (object_func_iter_destroy)NULL,
  680     (object_func_set_attr)map_set_attr,
  681     (object_func_add_attr)NULL,
  682     (object_func_remove_attr)NULL,
  683     (object_func_init)NULL,
  684     (object_func_destroy)map_destroy,
  685     (object_func_dup)NULL,
  686     (object_func_ref)navit_object_ref,
  687     (object_func_unref)navit_object_unref,
  688 };
  689 
  690 
  691