pax_global_header00006660000000000000000000000064111254446500014514gustar00rootroot0000000000000052 comment=29772022e8c75de1e161c03b8f1e20b7dfc28c2b libgarmin-0~svn320/000077500000000000000000000000001112544465000143335ustar00rootroot00000000000000libgarmin-0~svn320/.gitignore000066400000000000000000000003561112544465000163270ustar00rootroot00000000000000Makefile Makefile.in config.h configure data/Makefile data/Makefile.in libgarmin.pc src/Makefile src/Makefile.in stamp-h1 utils/Makefile utils/Makefile.in utils/bsptest utils/garroute utils/gartest utils/garxor utils/garxtract version.h libgarmin-0~svn320/AUTHORS000066400000000000000000000007071112544465000154070ustar00rootroot00000000000000Alexander Atanasov The decoding of the *.img files is based on John Mechalas Garmin IMG File Format documentation. http://sourceforge.net/projects/garmin-img/ QLandKarte source code by Oliver Eichler (oliver.eichler@gmx.de) was used too. http://qlandkarte.sf.net/ The missing bits and errors where rectified by studying the source code of Konstantin Galichsky's (kg@geopainting.com) GPSMapEdit. http://www.geopainting.com/ libgarmin-0~svn320/COPYING000066400000000000000000000433351112544465000153760ustar00rootroot00000000000000Note GPL v2 ONLY, unless stated in the file otherwise Alexander Atanasov --------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. libgarmin-0~svn320/ChangeLog000066400000000000000000000000001112544465000160730ustar00rootroot00000000000000libgarmin-0~svn320/INSTALL000066400000000000000000000220711112544465000153660ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PREFIX', the package will use PREFIX as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. libgarmin-0~svn320/Makefile.am000066400000000000000000000020161112544465000163660ustar00rootroot00000000000000AUTOMAKE_OPTIONS = dist-bzip2 include $(top_srcdir)/Makefile.inc SUBDIRS=src data if !TARGET_WIN32CE SUBDIRS+=utils endif DIST_SUBDIRS=src data utils pkgdoc_DATA = README COPYING TODO EXTRA_DIST = README COPYING TODO autosh.sh pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libgarmin.pc noinst_HEADERS=version.h CLEANFILES=version.h BUILT_SOURCES=version.h clean-local: rm -rf *~ *.bak core ## ## on every build, record the working copy revision string ## .svnversion: @if test -d .svn; then \ svnversion > .svnversion; \ fi; version.h: .svnversion @echo "Generate version.h"; \ echo -n "#define LIBVERSION \"$(PACKAGE_STRING)" > version.h; \ if test -d .svn; then \ echo -n "-r`svnversion -n`" >> version.h; \ fi; \ echo "\"" >> version.h # echo -n 'const char* svn_version(void) { const char* SVN_Version = "' \ # > svn_version.c # svnversion -n . >> svn_version.c # echo '"; return SVN_Version; }' >> svn_version.c libgarmin-0~svn320/Makefile.inc000066400000000000000000000002361112544465000165440ustar00rootroot00000000000000pkgdocdir=$(pkgdatadir)/doc AM_CPPFLAGS = if !TARGET_WIN32CE CFLAGS += -shared AM_CPPFLAGS += -fPIC endif if DEBUG CFLAGS += -g AM_CPPFLAGS += -DDEBUG endif libgarmin-0~svn320/NEWS000066400000000000000000000000001112544465000150200ustar00rootroot00000000000000libgarmin-0~svn320/README000066400000000000000000000022341112544465000152140ustar00rootroot00000000000000Libgarmin: ========== Libgarmin is an open source (GPLv2) for Garmin image format maps. For more information, please, visit http://libgarmin.sf.net. or email libgarmin@gmail.com. Motivation: =========== Garmin is a leader in the gps navigation, so learn from the best. Open source community is moving towards www.openstreetmap.org data. Understanding Garmin's format will allow creation of Garmin compatible maps from OSM data and creation/design of a new map format for OSM data. Installation: ============ If you are building a svn checkout. First run ./autosh.sh then ./configure. You may want to check available options. Compiling is stright forward - make and make install. Usage: ====== This library, as other open source Garmin format support projects, is based on top of public documents and reverse engeneering. Currently there are two main types of maps - original Garmin maps and cgpsmapper compiled. Garmin maps do not allow reverse engeneering and usage with other software than Garmin's. There are a lot of free cgpsmapper maps that can be used. Check your map license and your local country laws before using. Contacts: ========= E-mail: libgarmin@gmail.com libgarmin-0~svn320/TODO000066400000000000000000000005251112544465000150250ustar00rootroot00000000000000Move subdivs into arrays for O(1) access Done: Make data load on demand Done: Load objects into arrays instead of lists Done: Order polygons Done: Parse TDB Done: Parse MPS Done: Parse NET - unknown bytes at the end of some roads Parse unknown data in RGN/TRE, needed for routing. Parse NOD Parse TYP Parse MDR Parse SRT Parse DEM Parse TRF libgarmin-0~svn320/autosh.sh000077500000000000000000000001321112544465000161710ustar00rootroot00000000000000#! /bin/bash aclocal && autoheader && automake --add-missing && autoreconf && ./configure libgarmin-0~svn320/config.h.in000066400000000000000000000050571112544465000163650ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Building for WINCE */ #undef TARGET_WIN32CE /* Version number of package */ #undef VERSION /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to `long int' if does not define. */ #undef off_t /* Define to `int' if does not define. */ #undef ssize_t libgarmin-0~svn320/configure.ac000066400000000000000000000035601112544465000166250ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT(libgarmin, 0.1, libgarmin@gmail.com) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADER([config.h]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) # Checks for programs. AC_PROG_CC if eval "test x$GCC = xyes"; then CFLAGS="$CFLAGS -Wall -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith -Wreturn-type" fi AC_PROG_RANLIB # Checks for libraries. # FIXME: Replace `main' with a function in `-lgarmin': #AC_CHECK_LIB([garmin], [main]) # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h malloc.h stdlib.h string.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_INT32_T AC_TYPE_OFF_T AC_TYPE_SSIZE_T # Checks for library functions. AC_FUNC_VPRINTF AC_CHECK_FUNCS([strchr strdup strerror strrchr]) AC_ARG_ENABLE([debug], [ --enable-debug Turn on debugging (default:true)], [case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; esac],[debug=true]) AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) if eval "test x$GCC = xyes"; then CFLAGS="$CFLAGS -DDEBUG" fi extras=false if test -f "src/extras.c"; then extras=true CFLAGS="$CFLAGS -DEXTRAS" fi AM_CONDITIONAL([HAVEEXTRAS], [test x$extras = xtrue]) AC_CANONICAL_HOST win32=no case $host_os in wince) win32=yes AC_DEFINE(TARGET_WIN32CE, 1, [Building for WINCE]) ;; esac AM_CONDITIONAL(TARGET_WIN32CE, [test "x$win32" = "xyes"]) if test "x$win32" = "xyes"; then # adding -Wcast-align gives a lot of false positives for lists CFLAGS="$CFLAGS -Wpadded" fi AC_CONFIG_FILES([Makefile src/Makefile data/Makefile utils/Makefile libgarmin.pc]) AC_OUTPUT libgarmin-0~svn320/data/000077500000000000000000000000001112544465000152445ustar00rootroot00000000000000libgarmin-0~svn320/data/Makefile.am000066400000000000000000000002041112544465000172740ustar00rootroot00000000000000include $(top_srcdir)/Makefile.inc pkgdata_DATA = garmintypes.txt EXTRA_DIST = garmintypes.txt clean-local: rm -rf *~ *.bak core libgarmin-0~svn320/data/garmintypes.txt000066400000000000000000000337641112544465000203640ustar00rootroot00000000000000# # # POINT 0x0000 = label_unkn, Unknown label 0x0100 = town_label_1e5, Megapolis (10M +) 0x0200 = town_label_5e4, Megapolis (5-10M) 0x0300 = town_label_2e4, Big City (2-5M) 0x0400 = town_label_1e4, Big City (1-2M) 0x0500 = town_label_5e3, Big City (0.5-1M) 0x0600 = town_label_2e3, City (200-500k) 0x0700 = town_label_1e3, City (100-200k) 0x0800 = town_label_5e2, City (50-100k) 0x0900 = town_label_2e2, City (20-50k) 0x0a00 = town_label_1e2, City (10-20k) 0x0b00 = town_label_5e1, Small City (5-10k) 0x0c00 = town_label_2e1, Small City (2-5k) 0x0d00 = town_label_1e1, Village (1-2k) 0x0e00 = town_label_5e0, Village (500-1000) 0x0f00 = town_label_2e0, Village (200-500) 0x1000 = town_label_1e0, Village (100-200) 0x1100 = town_label_0e0, Village (0-100) 0x1200 = port_label, Port with services 0x1300 = label_unkn, Unknown label2 0x1400-0x14FF = country_label, Large Country Name 0x1500-0x15FF = country_label, Country Name 0x1c00 = poi_wreck, Unclassified Obstruction 0x1c01 = poi_wreck, Wreck 0x1c02 = poi_dangerous, submerged wreck, dangerous 0x1c03 = poi_nondangerous, submerged wreck, non-dangerous 0x1c04 = poi_wreck, Wreck, cleared by wire drag 0x1c05 = poi_rock, Obstruction, visible at high water 0x1c06 = poi_rock, Obstruction, awash 0x1c07 = poi_rock, Obstruction, submerged 0x1c08 = poi_rock, Obstruction, cleared by wire drag 0x1c09 = poi_rock, Rock, awash 0x1c0a = poi_rock, Rock, submerged at low Water 0x1c0b = poi_sounding, Sounding 0x1d00 = poi_tide, Tide Prediction 0x1e00-0x1e3f = district_label, District, Province, State Name 0x1f00 = district_label_0e0, Region, District Name # Fixme if it has label how to change to highway_exit_with_label ?? 0x2000-0x203F = highway_exit, Exit 0x2100-0x213F = highway_exit, Exit with Services 0x2200-0x223F = highway_exit, Exit with Restroom 0x2300-0x233F = highway_exit, Exit with Convinience Store 0x2400-0x243F = highway_exit, Exit with Weight Station 0x2500-0x253F = highway_exit, Exit with Toolbooth Booth 0x2600-0x263F = highway_exit, Exit with Information 0x2700-0x273F = highway_exit, Exit 0x2800-0x283F = district_label_e01, Region Name 0x2900 = poi_public_utilities, Services 0x2A00 = poi_restaurant, Dining(Other) 0x2A01 = poi_restaurant, Dining(American) 0x2A02 = poi_restaurant, Dining(Asian) 0x2A03 = poi_restaurant, Dining(Barbecue) 0x2A04 = poi_restaurant, Dining(Chinese) 0x2A05 = poi_restaurant, Dining(Deli/Bakery) 0x2A06 = poi_restaurant, Dining(International) 0x2A07 = poi_fastfood, Fast Food 0x2A08 = poi_restaurant, Dining(Italian) 0x2A09 = poi_restaurant, Dining(Mexican) 0x2A0A = poi_restaurant, Dining(Pizza) 0x2A0B = poi_restaurant, Dining(Sea Food) 0x2A0C = poi_restaurant, Dining(Steak/Grill) 0x2A0D = poi_restaurant, Dining(Bagel/Donut) 0x2A0E = poi_restaurant, Dining(Cafe/Diner) 0x2A0F = poi_restaurant, Dining(French) 0x2A10 = poi_restaurant, Dining(German) 0x2A11 = poi_restaurant, Dining(British Isles) 0x2A12 = poi_restaurant, Dining(Special Foods) 0x2B00 = poi_hotel, Hotel(Other) 0x2B01 = poi_hotel, Hotel/Motel 0x2B02 = poi_hotel, Bed & Breakfast inn 0x2B03 = poi_camp_rv, Camping/RV-Park 0x2B04 = poi_resort, Resort 0x2C01 = poi_attraction, Amusement Park 0x2C02 = poi_museum_history, Museum/History 0x2C03 = poi_library, Libraries 0x2C04 = poi_landmark, Land Mark 0x2C05 = poi_school, School 0x2C06 = poi_park, Park 0x2C07 = poi_zoo, Zoo 0x2C08 = poi_stadium, Sportpark, Stadium,(point) 0x2C09 = poi_fair, Fair, Conference(point) 0x2C0A = poi_vine, Vine restaurant(point) 0x2C0B = poi_worship, Place of Worship 0x2C0C = poi_hotspring, Hot Spring 0x2D01 = poi_theater, Theater 0x2D02 = poi_bar, Bar 0x2D03 = poi_cinema, Cinema 0x2D04 = poi_casino, Casino 0x2D05 = poi_golf, Golf 0x2D06 = poi_skiing, Skiing Center 0x2D07 = poi_bowling, Bowling 0x2D08 = poi_icesport, Ice/Sporting 0x2D09 = poi_swimming, Swimming 0x2D0A = poi_sport, Sports(point) 0x2D0B = poi_sailing, Sailing Airport 0x2E00 = poi_shopping, Shoping general 0x2E01 = poi_shop_department, Department Store 0x2E02 = poi_shop_grocery, Grocery 0x2E03 = poi_shop_merchandise, General Merchandiser 0x2E04 = poi_mall, Shopping Center 0x2E05 = poi_pharmacy, Pharmacy 0x2E06 = poi_shopping, Convenience 0x2E07 = poi_shop_apparel, Apparel 0x2E08 = poi_shop_handg, House and Garden 0x2E09 = poi_shop_furnish, Home Furnishing 0x2E0a = poi_shop_retail, Special Retail 0x2E0b = poi_shop_computer, Computer/Software 0x2F00 = poi_service, generic service 0x2F01 = poi_fuel, Fuel/Gas 0x2F02 = poi_car_rent, Car Rental 0x2F03 = poi_autoservice, Car Repair 0x2F04 = poi_airport, Airport 0x2F05 = poi_post, Post Office 0x2F06 = poi_bank, Bank 0x2F07 = poi_car_dealer_parts, Car Dealer(point) 0x2F08 = poi_bus_station, Bus Station 0x2F09 = poi_marina, Marina 0x2F0A = poi_wrecker, Wrecker Service 0x2F0B = poi_car_parking, Parking 0x2F0C = poi_rest_room, Restroom 0x2F0D = poi_auto_club, Automobile Club 0x2F0E = poi_car_wash, Car Wash 0x2F0F = poi_garmin, Garmin Dealer 0x2F10 = poi_personal_service, Personal Service 0x2F11 = poi_bussines_service, Business Service 0x2F12 = poi_communication, Communication 0x2F13 = poi_repair_service, Repair Service 0x2F14 = poi_social_service, Social Service 0x2F15 = poi_public_utilities, Utility 0x2F16 = poi_truck_stop, Truck Stop 0x2F17 = poi_bus_stop, Bus Stop 0x3000 = poi_emergency, generic emergency/government 0x3001 = poi_police, Police Station 0x3002 = poi_hospital, Hospital 0x3003 = poi_public_office, Public Office 0x3004 = poi_justice, Justice 0x3005 = poi_concert, Concert hall(point) 0x3006 = poi_border_station, Border Station(point) 0x3007 = poi_goverment_building, Goverment Building 0x3008 = poi_firebriade, FireFighters Station 0x4000-0x403F = poi_golf, Golf 0x4100-0x413F = poi_fish, Fish 0x4200-0x423F = poi_wreck, Wreck 0x4300-0x433F = poi_marina, Marina 0x4400-0x443F = poi_fuel, Gas 0x4500-0x453F = poi_restaurant, Restaurant 0x4600-0x463F = poi_bar, Bar 0x4700-0x473F = poi_boat_ramp, Boat Ramp 0x4800-0x483F = poi_camping, Camping 0x4900-0x493F = poi_park, Park 0x4A00-0x4A3F = poi_picnic, Picnic Area 0x4B00-0x4B3F = poi_hospital, Hospital 0x4C00-0x4C3F = poi_information, Information 0x4D00-0x4D3F = poi_car_parking, Parking 0x4E00-0x4E3F = poi_restroom, Restroom 0x4F00-0x4F3F = poi_shower, Shower 0x5000-0x503F = poi_drinking_water, Drinking Water 0x5100-0x513F = poi_telephone, Telephone 0x5200-0x523F = poi_scenic_area, Scenic Area 0x5300-0x533F = poi_skiing, Skiing 0x5400-0x543F = poi_swimming, Swimming 0x5500-0x553F = poi_dam, Dam 0x5600-0x563F = poi_forbiden_area, Forbiden Area 0x5700-0x573F = poi_danger_area, Danger Area 0x5800-0x583F = poi_restricted_area, Restricted Area 0x5900 = poi_airport, Generic Airport 0x5901 = poi_airport, Large Airport 0x5902 = poi_airport, Medium Airport 0x5903 = poi_airport, Small Airport 0x5904 = poi_heliport, Heliport 0x5905-0x593F = poi_airport, Airport 0x5a00 = poi_mark, Kilometer Pole 0x5b00 = poi_mark, Kolokol 0x5c00 = poi_diving, Diving Place 0x5D00-0x5D3F = poi_daymark, Daymark,Green Square 0x5E00-0x5E3F = poi_daymark, Daymark,Red Triangle 0x6000 = poi_loudspeaker, LoudSpeaker 0x6100 = poi_building, House 0x6200 = poi_height, Height with point in feet one decimal place 0x6300 = poi_height, Height without point in feet no decimal place 0x6400 = poi_manmade_feature, Manmade Feature 0x6401 = poi_bridge, Bridge 0x6402 = poi_building, Building 0x6403 = poi_cemetery, Cemetery 0x6404 = poi_church, Church 0x6405 = poi_civil, Civil 0x6406 = poi_crossing, Crossing 0x6407 = poi_dam, Dam 0x6408 = poi_hospital, Hospital 0x6409 = poi_levee, Levee 0x640A = poi_locale, Locale 0x640B = poi_military, Military 0x640C = poi_mine, Mine 0x640D = poi_oil_field, Oil Field 0x640E = poi_park, Park 0x640F = poi_post, Post 0x6410 = poi_school, School 0x6411 = poi_tower, Tower 0x6412 = poi_trail, Trail 0x6413 = poi_tunnel, Tunnel 0x6414 = poi_drinking_water, Drink water 0x6415 = town_ghost, Ghost Town 0x6416 = poi_subdivision, Subdivision 0x6500 = poi_water_feature, Water Feature 0x6501 = poi_water_feature, Arroyo 0x6502 = poi_water_feature, Sand Bar 0x6503 = poi_bay, Bay 0x6504 = poi_bend, Bend 0x6505 = poi_water_feature, Canal 0x6506 = poi_water_feature, Channel 0x6507 = poi_cove, Cove 0x6508 = poi_water_feature, Falls 0x6509 = poi_water_feature, Geyser 0x650A = poi_water_feature, Glacier 0x650B = poi_marine, Harbour 0x650C = poi_island, Island 0x650D = poi_water_feature, Lake 0x650E = poi_water_feature, Rapids 0x650F = poi_water_feature, Reservoir 0x6510 = poi_water_feature, Sea 0x6511 = poi_water_feature, Spring 0x6512 = poi_water_feature, Stream 0x6513 = poi_water_feature, Swamp 0x6600 = poi_land_feature, Land Feature 0x6601 = poi_land_feature, Arch 0x6602 = poi_land_feature, Area 0x6603 = poi_land_feature, Basin 0x6604 = poi_land_feature, Beach 0x6605 = poi_land_feature, Bench 0x6606 = poi_land_feature, Cape 0x6607 = poi_land_feature, Cliff 0x6608 = poi_land_feature, Crater 0x6609 = poi_land_feature, Flat 0x660A = poi_land_feature, Forest 0x660B = poi_land_feature, Gap 0x660C = poi_land_feature, Gut 0x660D = poi_land_feature, Isthmus 0x660E = poi_land_feature, Lava 0x660F = poi_land_feature, Pillar 0x6610 = poi_land_feature, Plain 0x6611 = poi_land_feature, Range 0x6612 = poi_land_feature, Reserve 0x6613 = poi_land_feature, Ridge 0x6614 = poi_land_feature, Rock 0x6615 = poi_land_feature, Slope 0x6616 = poi_land_feature, Summit 0x6617 = poi_land_feature, Valley 0x6618 = poi_land_feature, Woods # This are dublicated to 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00 # fix them if you need them 0x1600 = poi_marine_type, Beakon 0x1601 = poi_marine_type, Fog Horn 0x1602 = poi_marine_type, Radio Beacon 0x1603 = poi_marine_type, Racon 0x1604 = poi_marine_type, Day Beacon, red triangle 0x1605 = poi_marine_type, Day Beacon, green square 0x1606 = poi_marine_type, Day Beacon, white diamond 0x1607 = poi_marine_type, unlit Navaid, white 0x1608 = poi_marine_type, unlit Navaid, red 0x1609 = poi_marine_type, unlit Navaid, green 0x160a = poi_marine_type, unlit Navaid, black 0x160b = poi_marine_type, unlit Navaid, yellow or amber 0x160c = poi_marine_type, unlit Navaid, orange 0x160d = poi_marine_type, unlit Navaid, multi colored 0x160e = poi_marine_type, Navaid, unknown 0x160f = poi_marine_type, lighted Navaid, white 0x1610 = poi_marine_type, lighted Navaid, red 0x1611 = poi_marine_type, lighted Navaid, green 0x1612 = poi_marine_type, lighted Navaid, yellow or amber 0x1613 = poi_marine_type, lighted Navaid, orange 0x1614 = poi_marine_type, lighted Navaid, violet 0x1615 = poi_marine_type, lighted Navaid, blue 0x1616 = poi_marine_type, lighted Navaid, multi colored # # Street's are routable by: # ALL - by all # W pedestrian # B bycycle # M motorcycle # C car # T truck # L largetruck # this is probably, encoded into the map POLYLINE 0x00 = ALL, street_1_land, Road 0x01 = MCTL, highway_land, Major HWY thick 0x02 = MCTL, street_4_land, Principal HWY-thick 0x03 = MCTL, street_2_land, Principal HWY-medium 0x04 = MCTL, street_3_city, Arterial Road-medium 0x05 = MCTL, street_4_city, Arterial Road-thick 0x06 = MCTL, street_2_city, Road-thin 0x07 = MCTL, street_1_city, Alley-thick 0x08 = MCTL, ramp, Ramp 0x09 = MCTL, ramp, Ramp highspeed 0x0a = MCTL, street_0, Unpaved Road-thin 0x0b = MCTL, ramp, Major HWY Connector-thick 0x0c = MCTL, roundabout, Roundabout 0x0d = MCTL, street_unkn, Reservation/Zapovednik? 0x0e = MCTL, street_unkn, Unknown Element 0x0e 0x0f = NONE, street_unkn, Unknown Element 0x0f 0x10 = NONE, street_unkn, Unknown Element 0x10 0x11 = NONE, street_unkn, Unknown Element 0x11 0x12 = NONE, street_unkn, Unknown Element 0x12 0x13 = NONE, street_unkn, Unknown Element 0x13 0x14 = NONE, rail, Railroad 0x15 = NONE, water_line, Shoreline 0x16 = W, street_nopass, Trail 0x18 = NONE, water_line, Stream-thin 0x19 = NONE, time_zone, Time-Zone 0x1a = ALL, ferry, Ferry 0x1b = ALL, ferry, Ferry 0x1c = NONE, border_country, Political Boundary 0x1d = NONE, border_country, County Boundary 0x1e = NONE, border_country, Intl. Boundary 0x1f = NONE, water_line, River 0x20 = NONE, height_line_1, Land Contour (thin) Height in feet 0x21 = NONE, height_line_2, Land Contour (medium) Height in feet 0x22 = NONE, height_line_3, Land Contour (thick) Height in feet 0x23 = NONE, depth_line_1, Depth Contour (thin) Depth in feet 0x24 = NONE, depth_line_2, Depth Contour (medium) Depth in feet 0x25 = NONE, depth_line_3, Depth Contour (thick) Depth in feet 0x26 = NONE, water_line, Intermittent River 0x27 = NONE, street_nopass, Airport Runway 0x28 = NONE, pipeline, Pipeline 0x29 = NONE, powerline, Powerline 0x2a = NONE, marine_boundary, Marine Boundary (no line) 0x2b = NONE, marine_hazard, Marine Hazard (no line) POLYGONE 0x01 = town_poly, City (>200k) 0x02 = town_poly, City (<200k) 0x03 = town_poly, Village 0x04 = military_zone, Military 0x05 = parking_lot_poly, Parking Lot 0x06 = parking_lot_poly, Parking Garage 0x07 = airport_poly, Airport 0x08 = commercial_center, Shopping Center 0x09 = marine_poly, Marina 0x0a = university, University/College 0x0b = hospital_poly, Hospital 0x0c = industry_poly, Industrial 0x0d = area, Reservation 0x0e = airport_poly, Airport Runway 0x13 = area_unspecified, Man made area 0x14 = park_poly, National park 0x15 = park_poly, National park 0x16 = park_poly, National park 0x17 = park_poly, City Park 0x18 = golf_course, Golf 0x19 = sport_poly, Sport 0x1a = cemetery_poly, Cemetery 0x1e = park_poly, State Park 0x1f = park_poly, State Park 0x20 = park_poly, State Park 0x28 = water_poly, Ocean 0x29 = water_poly, Water Reservour 0x32 = water_poly, Sea 0x3b = water_poly, Water Reservour 0x3c = water_poly, Lake (250-600 km2) 0x3d = water_poly, Lake (77-250 km2) 0x3e = water_poly, Lake (25-77 km2) 0x3f = water_poly, Lake (11-25 km2) 0x40 = water_poly, Lake (0.25-11 km2) 0x41 = water_poly, Lake (<0.25 km2) 0x42 = water_poly, Lake (>3.3k km2) 0x43 = water_poly, Lake (1.1-3.3k km2) 0x44 = water_poly, Lake (0.6-1.1k km2) 0x45 = water_poly, Water Reservour 0x46 = water_poly, River (>1km) 0x47 = water_poly, River (200m-1km) 0x48 = water_poly, River (40-200m) 0x49 = water_poly, River (<40m) 0x4a = area, Map region 0x4b = area, Background 0x4c = water_poly, Intermittent River/Lake 0x4d = water_poly, Glaciers 0x4e = plantation, Orchard or plantation 0x4f = scrub, Scrub 0x50 = wood, Woods 0x51 = water_poly, Wetland 0x52 = tundra, Tundra 0x53 = flats, Flats libgarmin-0~svn320/depcomp000077500000000000000000000355451112544465000157240ustar00rootroot00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2004-05-31.23 # Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit 0 ;; -v | --v*) echo "depcomp $scriptversion" exit 0 ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` tmpdepfile="$stripped.u" if test "$libtool" = yes; then "$@" -Wc,-M else "$@" -M fi stat=$? if test -f "$tmpdepfile"; then : else stripped=`echo "$stripped" | sed 's,^.*/,,'` tmpdepfile="$stripped.u" fi if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi if test -f "$tmpdepfile"; then outname="$stripped.o" # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # Dependencies are output in .lo.d with libtool 1.4. # With libtool 1.5 they are output both in $dir.libs/$base.o.d # and in $dir.libs/$base.o.d and $dir$base.o.d. We process the # latter, because the former will be cleaned when $dir.libs is # erased. tmpdepfile1="$dir.libs/$base.lo.d" tmpdepfile2="$dir$base.o.d" tmpdepfile3="$dir.libs/$base.d" "$@" -Wc,-MD else tmpdepfile1="$dir$base.o.d" tmpdepfile2="$dir$base.d" tmpdepfile3="$dir$base.d" "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi if test -f "$tmpdepfile1"; then tmpdepfile="$tmpdepfile1" elif test -f "$tmpdepfile2"; then tmpdepfile="$tmpdepfile2" else tmpdepfile="$tmpdepfile3" fi if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # X makedepend shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes ;; esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. "$@" || exit $? IFS=" " for arg do case "$arg" in "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: libgarmin-0~svn320/install-sh000077500000000000000000000220171112544465000163410ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2004-12-17.09 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit 0;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit 0;; *) # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. test -n "$dir_arg$dstarg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then mkdircmd=: chmodcmd= else mkdircmd=$mkdirprog fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` shift IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift if test ! -d "$pathcomp"; then $mkdirprog "$pathcomp" # mkdir can fail with a `File exist' error in case several # install-sh are creating the directory concurrently. This # is OK. test -d "$pathcomp" || exit fi pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $mkdircmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 # Copy the file name to the temp name. $doit $cpprog "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" } } fi || { (exit 1); exit 1; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit 0 } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: libgarmin-0~svn320/libgarmin.pc.in000066400000000000000000000003201112544465000172230ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libgarmin Description: Handle Garmin image files Version: @VERSION@ Libs: -L${libdir} -lgarmin Cflags: -I${includedir} libgarmin-0~svn320/missing000077500000000000000000000245331112544465000157410ustar00rootroot00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2004-09-07.08 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit 0 ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit 0 ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case "$1" in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` fi touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: libgarmin-0~svn320/src/000077500000000000000000000000001112544465000151225ustar00rootroot00000000000000libgarmin-0~svn320/src/GarminTypedef.h000066400000000000000000000300341112544465000200310ustar00rootroot00000000000000/********************************************************************************************** Copyright (C) 2006, 2007 Oliver Eichler oliver.eichler@gmx.de Copyright (C) 2008 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA Garmin and MapSource are registered trademarks or trademarks of Garmin Ltd. or one of its subsidiaries. **********************************************************************************************/ #ifndef GARMINTYPEDEF_H #define GARMINTYPEDEF_H #include "config.h" #pragma pack(push, 1) struct FATblock_t { u_int8_t flag; ///< 0x00000000 char name[8]; ///< 0x00000001 .. 0x00000008 char type[3]; ///< 0x00000009 .. 0x0000000B u_int32_t size; ///< 0x0000000C .. 0x0000000F u_int16_t part; ///< 0x00000010 .. 0x00000011 u_int8_t byte0x00000012_0x0000001F[14]; u_int16_t blocks[240]; ///< 0x00000020 .. 0x000001FF } __attribute__((packed)); struct hdr_img_t { u_int8_t xorByte; ///< 0x00000000 u_int8_t byte0x00000001_0x0000000F[15]; char signature[7]; ///< 0x00000010 .. 0x00000016 u_int8_t byte0x00000017_0x00000039[41]; u_int8_t fat_offset; // in blocks of 512bytes from the start char identifier[7]; ///< 0x00000041 .. 0x00000047 u_int8_t byte0x00000048; char desc1[20]; ///< 0x00000049 .. 0x0000005C u_int8_t byte0x0000005D_0x00000060[4]; u_int8_t e1; ///< 0x00000061 u_int8_t e2; ///< 0x00000062 u_int8_t byte0x00000063_0x00000064[2]; char desc2[31]; ///< 0x00000065 .. 0x00000083 u_int8_t byte0x00000084_0x0000040B[904]; u_int32_t dataoffset; ///< 0x0000040C .. 0x0000040F u_int8_t byte0x00000410_0x0000041F[16]; u_int16_t blocks[240]; ///< 0x00000420 .. 0x000005FF } __attribute__((packed)); static int inline get_blocksize(struct hdr_img_t *i) { return (1<<(i->e1+i->e2)); } struct hdr_subfile_part_t { u_int16_t length; ///< 0x00000000 .. 0x00000001 char type[10]; ///< 0x00000002 .. 0x0000000B u_int8_t byte0x0000000C; // = 0x01 u_int8_t flag; ///< 0x0000000D u_int16_t year; u_int8_t month; u_int8_t day; u_int8_t hour; u_int8_t min; u_int8_t sec; } __attribute__((packed)); struct hdr_rgn_t { struct hdr_subfile_part_t hsub; u_int32_t offset; u_int32_t length; u_int32_t offset2; u_int32_t length2; u_int8_t unknown2[8]; u_int8_t unknown3[8]; u_int32_t unknown4; u_int32_t offset3; u_int32_t length3; u_int8_t unknown5[16]; u_int32_t unknown6; u_int32_t offset4; u_int32_t length4; u_int8_t unknown7[16]; u_int32_t unknown8; u_int32_t offset5; u_int32_t length5; u_int32_t unknown9; } __attribute__((packed)); typedef u_int8_t u_int24_t[3]; struct hdr_tre_t { struct hdr_subfile_part_t hsub; u_int8_t northbound[3]; ///< 0x00000015 .. 0x00000017 u_int8_t eastbound[3]; ///< 0x00000018 .. 0x0000001A u_int8_t southbound[3]; ///< 0x0000001B .. 0x0000001D u_int8_t westbound[3]; ///< 0x0000001E .. 0x00000020 u_int32_t tre1_offset; ///< 0x00000021 .. 0x00000024 u_int32_t tre1_size; ///< 0x00000025 .. 0x00000028 u_int32_t tre2_offset; ///< 0x00000029 .. 0x0000002C u_int32_t tre2_size; ///< 0x0000002D .. 0x00000030 u_int32_t tre3_offset; ///< 0x00000031 .. 0x00000034 u_int32_t tre3_size; ///< 0x00000035 .. 0x00000038 u_int16_t tre3_rec_size; ///< 0x00000039 .. 0x0000003A u_int8_t byte0x0000003B_0x0000003E[4]; u_int8_t POI_flags; ///< 0x0000003F u_int8_t drawprio; // map draw priority u_int8_t byte0x00000041_0x00000049[9]; u_int32_t tre4_offset; ///< 0x0000004A .. 0x0000004D u_int32_t tre4_size; ///< 0x0000004E .. 0x00000051 u_int16_t tre4_rec_size; ///< 0x00000052 .. 0x00000053 u_int8_t byte0x00000054_0x00000057[4]; u_int32_t tre5_offset; ///< 0x00000058 .. 0x0000005B u_int32_t tre5_size; ///< 0x0000005C .. 0x0000005F u_int16_t tre5_rec_size; ///< 0x00000060 .. 0x00000061 u_int8_t byte0x00000062_0x00000065[4]; u_int32_t tre6_offset; ///< 0x00000066 .. 0x00000069 u_int32_t tre6_size; ///< 0x0000006A .. 0x0000006D u_int16_t tre6_rec_size; ///< 0x0000006E .. 0x0000006F u_int8_t byte0x00000070_0x00000073[4]; /*-----------------------------------------------------*/ u_int32_t mapID; u_int8_t byte0x00000078_0x0000007B[4]; u_int32_t tre7_offset; ///< 0x0000007C .. 0x0000007F u_int32_t tre7_size; ///< 0x00000080 .. 0x00000083 u_int16_t tre7_rec_size; ///< 0x00000084 .. 0x00000085 u_int8_t byte0x00000086_0x00000089[4]; u_int32_t tre8_offset; ///< 0x0000008A .. 0x0000008D u_int32_t tre8_size; ///< 0x0000008E .. 0x00000091 u_int16_t tre8_rec_size; u_int8_t byte0x00000092_0x00000099[6]; /*-----------------------------------------------------*/ u_int8_t key[20]; ///< 0x0000009A .. 0x000000AD u_int8_t gap1[4]; u_int32_t tre9_offset; ///< 0x000000AE .. 0x000000B1 u_int32_t tre9_size; ///< 0x000000B2 .. 0x000000B5 u_int16_t tre9_rec_size; ///< 0x000000B6 .. 0x000000B7 u_int8_t gap2[4]; u_int32_t tre10_offset; ///< 0x000000AE .. 0x000000B1 u_int32_t tre10_size; ///< 0x000000B2 .. 0x000000B5 u_int16_t tre10_rec_size; ///< 0x000000B6 .. 0x000000B7 } __attribute__((packed)); struct tre_map_level_t { u_int8_t level :4; u_int8_t bit4 :1; u_int8_t bit5 :1; u_int8_t bit6 :1; u_int8_t inherited :1; u_int8_t bits; u_int16_t nsubdiv; } __attribute__((packed)); struct tre_subdiv_t { u_int24_t rgn_offset; u_int8_t elements; u_int24_t center_lng; u_int24_t center_lat; u_int16_t width :15; u_int16_t terminate :1; u_int16_t height; } __attribute__((packed)); struct tre_subdiv_next_t { struct tre_subdiv_t tresub; u_int16_t next; } __attribute__((packed)); struct hdr_lbl_t { struct hdr_subfile_part_t hsub; u_int32_t lbl1_offset; ///< 0x00000015 .. 0x00000018 u_int32_t lbl1_length; ///< 0x00000019 .. 0x0000001C u_int8_t addr_shift; ///< 0x0000001D u_int8_t coding; ///< 0x0000001E u_int32_t lbl2_offset; ///< 0x0000001F .. 0x00000022 u_int32_t lbl2_length; ///< 0x00000023 .. 0x00000026 u_int16_t lbl2_rec_size; ///< 0x00000027 .. 0x00000028 u_int8_t byte0x00000029_0x0000002C[4]; u_int32_t lbl3_offset; ///< 0x0000002D .. 0x00000030 u_int32_t lbl3_length; ///< 0x00000031 .. 0x00000034 u_int16_t lbl3_rec_size; ///< 0x00000035 .. 0x00000036 u_int8_t byte0x00000037_0x0000003A[4]; u_int32_t lbl4_offset; ///< 0x0000003B .. 0x0000003E u_int32_t lbl4_length; ///< 0x0000003F .. 0x00000042 u_int16_t lbl4_rec_size; ///< 0x00000043 .. 0x00000044 u_int8_t byte0x00000045_0x00000048[4]; u_int32_t lbl5_offset; ///< 0x00000049 .. 0x0000004C u_int32_t lbl5_length; ///< 0x0000004D .. 0x00000050 u_int16_t lbl5_rec_size; ///< 0x00000051 .. 0x00000052 u_int8_t byte0x00000053_0x00000056[4]; u_int32_t lbl6_offset; ///< 0x00000057 .. 0x0000005A u_int32_t lbl6_length; ///< 0x0000005B .. 0x0000005E u_int8_t lbl6_addr_shift; ///< 0x0000005F u_int8_t lbl6_glob_mask; ///< 0x00000060 u_int8_t byte0x00000061_0x00000063[3]; u_int32_t lbl7_offset; ///< 0x00000064 .. 0x00000067 u_int32_t lbl7_length; ///< 0x00000068 .. 0x0000006B u_int16_t lbl7_rec_size; ///< 0x0000006C .. 0x0000006D u_int8_t byte0x0000006E_0x00000071[4]; u_int32_t lbl8_offset; ///< 0x00000072 .. 0x00000075 u_int32_t lbl8_length; ///< 0x00000076 .. 0x00000079 u_int16_t lbl8_rec_size; ///< 0x0000007A .. 0x0000007B u_int8_t byte0x0000007C_0x0000007F[4]; u_int32_t lbl9_offset; ///< 0x00000080 .. 0x00000083 u_int32_t lbl9_length; ///< 0x00000084 .. 0x00000087 u_int16_t lbl9_rec_size; ///< 0x00000088 .. 0x00000089 u_int8_t byte0x0000008A_0x0000008D[4]; u_int32_t lbl10_offset; ///< 0x0000008E .. 0x00000091 u_int32_t lbl10_length; ///< 0x00000092 .. 0x00000095 u_int16_t lbl10_rec_size; ///< 0x00000096 .. 0x00000097 u_int8_t byte0x00000098_0x0000009B[4]; u_int32_t lbl11_offset; ///< 0x0000009C .. 0x0000009F u_int32_t lbl11_length; ///< 0x000000A0 .. 0x000000A3 u_int16_t lbl11_rec_size; ///< 0x000000A4 .. 0x000000A5 u_int8_t byte0x000000A6_0x000000AB[4]; u_int16_t codepage; ///< 0x000000AA .. 0x000000AB optional check length } __attribute__((packed)); struct hdr_net_t { struct hdr_subfile_part_t hsub; // NET1 Road definitions u_int32_t net1_offset; ///< 0x00000015 .. 0x00000018 u_int32_t net1_length; ///< 0x00000019 .. 0x0000001C u_int8_t net1_addr_shift; ///< 0x0000001D // Segmented roads u_int32_t net2_offset; ///< 0x0000001E .. 0x00000021 u_int32_t net2_length; ///< 0x00000022 .. 0x00000025 u_int8_t net2_addr_shift; ///< 0x00000026 // Sorted Roads u_int32_t net3_offset; ///< 0x00000027 .. 0x0000002A u_int32_t net3_length; ///< 0x0000002B .. 0x0000002E } __attribute__((packed)); struct garmin_bmp_t{ u_int16_t bfType; u_int32_t bfSize; u_int32_t bfReserved; u_int32_t bfOffBits; u_int32_t biSize; int32_t biWidth; int32_t biHeight; u_int16_t biPlanes; u_int16_t biBitCount; u_int32_t biCompression; u_int32_t biSizeImage; u_int32_t biXPelsPerMeter; u_int32_t biYPelsPerMeter; u_int32_t biClrUsed; u_int32_t biClrImportant; u_int32_t clrtbl[0x100]; u_int8_t data[]; } __attribute__((packed)); struct hdr_nod_t { struct hdr_subfile_part_t hsub; // Unknown u_int32_t nod1offset; // 0x15 Offset for section NOD1 4 u_int32_t nod1length; // 0x19 Length of section NOD1 4 u_int8_t nodbits; u_int8_t b2; u_int8_t b3; u_int8_t b4; u_int8_t cpalign; // 0x24 u_int8_t unknown3; // 0x25 0x21 Unknown 2 u_int16_t roadptrsize; // 0x26 0x23 Unknown 2 // Road Data u_int32_t nod2offset; // 0x25 Road data offset, NOD2 4 u_int32_t nod2length; // 0x29 Road data length 4 u_int32_t unknown5; // // Boundary Nodes u_int32_t bondoffset; // 0x31 Boundary nodes offset, NOD3 4 u_int32_t bondlength; // 0x35 Boundary nodes length 4 u_int8_t bondrecsize; // 0x39 Boundary nodes record length 1 u_int16_t zeroterm1; // 0x21 Unknown 2 u_int16_t zeroterm2; // 0x23 Unknown 2 // if header len > 63 u_int8_t zero5; u_int16_t bond2offset; u_int16_t zero3; u_int16_t bond2lenght; u_int16_t zero4; u_int32_t u1offset; u_int32_t u1lenght; u_int32_t u2offset; u_int32_t u2lenght; } __attribute__((packed)); #define SPEEDCLASS(x) (((x)>>1)&0x07) #define ROADTYPE(x) (((x)>>4)&0x07) #define HAVENODES(x) ((x) & 1) #define CHARINFO(x) ((x) & (1<<7)) struct nod_bond { u_int24_t east; // coord_east 3 u_int24_t north; // coord_north 3 u_int24_t offset; // offset 3 }; #define TDB_HEADER 0x50 #define TDB_TRADEMARK 0x52 #define TDB_REGIONS 0x53 #define TDB_TAIL 0x54 #define TDB_COPYRIGHT 0x44 #define TDB_BASEMAP 0x42 #define TDB_DETAILMAP 0x4C struct tdb_block { u_int8_t id; u_int16_t size; } __attribute__((packed)); struct hdr_gmp_t { struct hdr_subfile_part_t hsub; u_int32_t unknown1; u_int32_t tre_offset; u_int32_t rgn_offset; u_int32_t lbl_offset; u_int32_t net_offset; u_int32_t nod_offset; u_int32_t unknown2; } __attribute__((packed)); #pragma pack(pop) #endif //GARMINTYPEDEF_H libgarmin-0~svn320/src/Makefile.am000066400000000000000000000013601112544465000171560ustar00rootroot00000000000000include $(top_srcdir)/Makefile.inc AM_CPPFLAGS += -DDATAPREFIX=\"@datarootdir@\" lib_LIBRARIES = libgarmin.a libgarmin_a_SOURCES = GarminTypedef.h garmin_fat.c garmin_rgn.h \ bsp.c garmin_fat.h garmin_subdiv.c libgarmin_priv.h \ bsp.h garmin_lbl.c garmin_subdiv.h \ garmin_lbl.h garmin_typ.c list.c \ garmin_obj.c geoutils.c list.h \ garmin.c garmin_rgn.c geoutils.h \ garmin_order.c garmin_order.h \ garmin_net.c garmin_net.h \ garmin_tdb.c garmin_tdb.h \ array.h array.c \ garmin_nod.c garmin_nod.h \ garmin_mdr.c garmin_mdr.h \ garmin_route.c align.h extras.h nodist_libgarmin_a_SOURCES= if HAVEEXTRAS nodist_libgarmin_a_SOURCES+=extras.c endif include_HEADERS = libgarmin.h clean-local: rm -rf *~ *.bak core libgarmin-0~svn320/src/align.h000066400000000000000000000014371112544465000163720ustar00rootroot00000000000000#include "config.h" #ifdef TARGET_WIN32CE static inline unsigned int get_u32(void *ptr) { unsigned char *p = ptr; unsigned long ret; ret=*p++; ret|=(*p++) << 8; ret|=(*p++) << 16; ret|=(*p++) << 24; return ret; } static inline unsigned int get_u24(void *ptr) { unsigned char *p = ptr; unsigned int ret; ret=*p++; ret|=(*p++) << 8; ret|=(*p++) << 16; return ret; } static inline unsigned short get_u16(void *ptr) { unsigned char *p = ptr; unsigned short ret; ret=*p++; ret|=(*p++) << 8; return ret; } static inline unsigned char get_u8(void *ptr) { unsigned char *p = ptr; return *p; } #else #define get_u32(ptr) (*(u_int32_t *)ptr) #define get_u24(ptr) ((*(u_int32_t*)ptr) & 0x00FFFFFF) #define get_u16(ptr) (*(u_int16_t *)ptr) #define get_u8(ptr) (*(u_int8_t *)ptr) #endif libgarmin-0~svn320/src/array.c000066400000000000000000000042361112544465000164110ustar00rootroot00000000000000#include #include "array.h" #define ARR_DEF_SIZE 4096 /* Array index starts from 1 */ int ga_init(struct garray *ga, unsigned int base, unsigned int isize) { unsigned int s = isize; ga->lastidx = 0; if (!s) s = ARR_DEF_SIZE; ga->ar = calloc(s, sizeof(void *)); if (!ga->ar) return -1; ga->base = base; ga->elements = s; ga->resize = s; return s; } void ga_free(struct garray *ga) { if (ga->ar) free(ga->ar); } int ga_append(struct garray *ga, void *el) { if (ga->lastidx == ga->elements) { void *rptr; rptr = realloc(ga->ar, sizeof(void *) * (ga->elements + ga->resize)); if (!rptr) return -1; ga->elements += ga->resize; ga->ar = rptr; } ga->ar[ga->lastidx] = el; ga->lastidx ++; return 0; } int ga_trim(struct garray *ga) { void *rptr; int s; s = sizeof(void *) * ga->lastidx; if (!s) s = 1; rptr = realloc(ga->ar, s); if (!rptr) return -1; ga->elements = ga->lastidx; ga->ar = rptr; return 0; } void *ga_get_abs(struct garray *ga, unsigned int idx) { if (idx >= ga->base + ga->lastidx) return NULL; if (idx < ga->base) return NULL; return ga->ar[idx-ga->base]; } void *ga_get(struct garray *ga, unsigned int idx) { if (idx >= ga->lastidx) return NULL; return ga->ar[idx]; } void ga_clear(struct garray *ga, unsigned int idx) { ga->ar[idx] = NULL; if (idx == ga->lastidx - 1) ga->lastidx --; } void ga_empty(struct garray *ga) { int i; for (i=0; i < ga->lastidx; i++) ga->ar[i] = NULL; ga->lastidx = 0; ga_trim(ga); } int ga_get_count(struct garray *ga) { return ga->lastidx; } int ga_get_base(struct garray *ga) { return ga->base; } void ga_set_base(struct garray *ga, unsigned int base) { ga->base = base; } #ifdef STANDALONE int main(int argc, char **argv) { struct garray g; int i; char aaa[] = "alabala"; char *d; ga_init(&g, 10); for (i=1; i < 16; i++) { ga_append(&g, aaa); } ga_trim(&g); for (i=1; i < 15; i++) { d = ga_get(&g, i); printf("%s\n", d); } printf("%d\n", g.elements); } #endif int bm_is_set(unsigned char *bmap, int bit) { if (bmap[bit/8] & (1<<(bit%8))) return 1; return 0; } int bm_set_bit(unsigned char *bmap, int bit) { bmap[bit/8] |= 1<<(bit%8); return 1; } libgarmin-0~svn320/src/array.h000066400000000000000000000015001112544465000164050ustar00rootroot00000000000000#ifndef _GAR_ARRAY_H__ struct garray { unsigned int base; unsigned int elements; unsigned int resize; unsigned int lastidx; void **ar; }; int ga_init(struct garray *ga, unsigned int base, unsigned int isize); void ga_free(struct garray *ga); int ga_append(struct garray *ga, void *el); int ga_trim(struct garray *ga); // Get zero based index void *ga_get(struct garray *ga, unsigned int idx); // Get absolute index void *ga_get_abs(struct garray *ga, unsigned int idx); void ga_clear(struct garray *ga, unsigned int idx); int ga_get_count(struct garray *ga); void ga_set_base(struct garray *ga, unsigned int base); int ga_get_base(struct garray *ga); void ga_empty(struct garray *ga); /* Bitmap arrays */ int bm_is_set(unsigned char *bmap, int bit); int bm_set_bit(unsigned char *bmap, int bit); #define _GAR_ARRAY_H__ #endif libgarmin-0~svn320/src/bsp.c000066400000000000000000000060701112544465000160550ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Simple bitstream reading functions */ #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "bsp.h" void bsp_init(struct bsp *bp, u_int8_t *data, u_int32_t len) { bp->cbit = 0; bp->data = data; bp->ep = data+len; bp->cb = bp->data; } void bsp_fd_init(struct bspfd *bp, struct gimg *g) { bp->cbit = 7; bp->g = g; bp->datalen = 0; bp->ep = bp->cb = bp->buf; } static int bsp_fd_read(struct bspfd *bp) { int rc; rc = gread(bp->g, bp->buf, sizeof(bp->buf)); if (rc < 0) return -1; // hexdump(bp->buf, rc); bp->cb = bp->buf; bp->ep = bp->cb + rc; bp->datalen = rc; return rc; } // MSB to LSB int bsp_fd_get_bits(struct bspfd *bp, int bits) { u_int32_t ret = 0; int i; if (!bp->datalen) { if (bsp_fd_read(bp) < 0) return -1; } if (bits > 32) { log(1, "BSP: Error can not handle more than 32bits\n"); return -1; } if (!bp->datalen) return -1; if (bp->cb == bp->ep) if (bsp_fd_read(bp) < 0) return -1; if (!bp->datalen) return -1; if (bits == 8 && bp->cbit == 7) { ret = *bp->cb; bp->cb++; if (bp->cb == bp->ep) { if (bsp_fd_read(bp) < 0) return -1; if (!bp->datalen) return -1; } return ret; } for (i=0; i < bits; i++) { if (bp->cbit < 0) { bp->cbit = 7; bp->cb++; } if (bp->cb == bp->ep) { if (bsp_fd_read(bp) < 0) return -1; if (!bp->datalen) return -1; } ret |= (!!(*bp->cb & (1<cbit))) << (bits - i - 1); bp->cbit --; } return ret; } // LSB to msb FIXME int bsp_fd_get_bitsmsb(struct bspfd *bp, int bits) { u_int32_t ret = 0; int i; if (!bp->datalen) { if (bsp_fd_read(bp) < 0) return -1; } if (bits > 32) { log(1, "BSP: Error can not handle more than 32bits\n"); return -1; } if (!bp->datalen) return -1; if (bp->cb == bp->ep) if (bsp_fd_read(bp) < 0) return -1; if (!bp->datalen) return -1; if (bits == 8 && bp->cbit == 7) { ret = *bp->cb; bp->cb++; if (bp->cb == bp->ep) { if (bsp_fd_read(bp) < 0) return -1; if (!bp->datalen) return -1; } return ret; } for (i=0; i < bits; i++) { if (bp->cbit < 0) { bp->cbit = 7; bp->cb++; } if (bp->cb == bp->ep) { if (bsp_fd_read(bp) < 0) return -1; if (!bp->datalen) return -1; } ret |= (!!(*bp->cb & (1<cbit))) << (bits - i - 1); bp->cbit --; } return ret; } libgarmin-0~svn320/src/bsp.h000066400000000000000000000013571112544465000160650ustar00rootroot00000000000000struct gimg; /* Can read up to 32 bits */ struct bspfd { struct gimg *g; u_int8_t buf[64]; int datalen; u_int8_t *cb; u_int8_t *ep; int cbit; }; struct bsp { u_int8_t *data; u_int8_t *ep; u_int8_t *cb; int cbit; }; void bsp_init(struct bsp *bp, u_int8_t *data, u_int32_t len); void bsp_fd_init(struct bspfd *bp, struct gimg *g); int bsp_fd_get_bits(struct bspfd *bp, int bits); int bsp_fd_get_bitsmsb(struct bspfd *bp, int bits); // LSB to MSB static int inline bsp_get_bits(struct bsp *bp, int bits) { u_int32_t ret = 0; int i; for (i=0; i < bits; i++) { if (bp->cbit == 8) { bp->cbit = 0; bp->cb++; } if (bp->cb >= bp->ep) return -1; if (*bp->cb & (1<cbit)) ret |= 1 << i; bp->cbit ++; } return ret; } libgarmin-0~svn320/src/extras.h000066400000000000000000000003021112544465000165740ustar00rootroot00000000000000/* * Experimental stuff */ #ifdef EXTRAS int fixup_tre(struct hdr_tre_t *tre, unsigned char *data); #else static int fixup_tre(struct hdr_tre_t *tre, unsigned char *data) { return 0;}; #endif libgarmin-0~svn320/src/garmin.c000066400000000000000000000260541112544465000165520ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include #include #include #include #include #ifndef TARGET_WIN32CE #include #endif #include #define __USE_GNU #include #include #include #include "version.h" #include "libgarmin.h" #include "libgarmin_priv.h" #include "garmin_fat.h" #include "garmin_rgn.h" #include "garmin_lbl.h" #include "garmin_tdb.h" #include "garmin_mdr.h" log_fn glogfn; int gar_debug_level = 1; #ifdef DEBUG void gar_print_buf(char *pref, unsigned char *a, int s) { char buf[4096]; int i,sz = 0; for (i=0; i < s; i++) { sz += sprintf(buf+sz, "%02X ",a[i]); } log(11, "%s :%s\n", pref, buf); } #else void gar_print_buf(char *pref, unsigned char *a, int s) {} #endif void gar_log_file_date(int l, char *pref, struct hdr_subfile_part_t *h) { log(l, "%s: %04d-%02d-%02d %02d:%02d:%02d\n", pref, h->year, h->month, h->day, h->hour, h->min, h->sec); } static int g_safe_open(char *file, int fl) { int flags = fl; int fd; reopen: fd = open(file, flags); if (fd == -1 && errno == EPERM && (flags & O_NOATIME)) { static int no_atime_warned; if (!no_atime_warned) { log(1, "WARNING: You can change the ownership of the maps to the same user for faster reading\n"); no_atime_warned = 1; } flags &= ~O_NOATIME; goto reopen; } return fd; } static void inline gcheckfd(struct gimg *g) { if (g->fd == -1) { g->fd = g_safe_open(g->file, OPENFLAGS); if (g->fd == -1) { log(1, "Error can not open:[%s] errno=%d(%s)\n", g->file, errno, strerror(errno)); } } } int gopen(struct gimg *g) { if (g->fd == -1) g->fd = g_safe_open(g->file, OPENFLAGS); return g->fd; } int gclose(struct gimg *g) { int fd = g->fd; g->fd = -1; if (fd != -1) return close(fd); return 0; } off_t glseek(struct gimg *g, off_t offset, int whence) { gcheckfd(g); return lseek(g->fd, offset, whence); } ssize_t gread(struct gimg *g, void *buf, size_t count) { ssize_t rc; gcheckfd(g); rc = read(g->fd, buf, count); if (rc > 0 && g->xor) { ssize_t i; for (i=0; i < rc; i++) ((unsigned char *)buf)[i] ^= g->xor; } return rc; } ssize_t gread_safe(struct gimg *g, void *buf, size_t count) { ssize_t rc; int err; off_t osave; gcheckfd(g); osave = lseek(g->fd, 0, SEEK_CUR); rc = read(g->fd, buf, count); if (rc > 0 && g->xor) { ssize_t i; for (i=0; i < rc; i++) ((unsigned char *)buf)[i] ^= g->xor; } err = errno; lseek(g->fd, osave, SEEK_SET); #ifdef TARGET_WIN32CE SetLastError(err); #else errno = err; #endif return rc; } ssize_t gwrite(struct gimg *g, void *buf, size_t count) { gcheckfd(g); if (g->xor) { ssize_t i; for (i=0; i < count; i++) ((unsigned char *)buf)[i] ^= g->xor; } return write(g->fd, buf, count); } static struct gimg *gimg_alloc(struct gar *gar, char *file) { struct gimg *g; g = calloc(1, sizeof(*g)); if (!g) return NULL; g->gar = gar; if (file) { g->file = strdup(file); if (!g->file) { free(g); return NULL; } } list_init(&g->lfatfiles); list_init(&g->lsubfiles); return g; } struct gar *gar_init_cfg(char *tbd, log_fn l, struct gar_config *cfg) { struct gar *gar; char modename[50] = ""; if (cfg->opm == OPM_DUMP) { log(1, "Data dumping not implemented\n"); return NULL; } if (cfg->opm != OPM_PARSE && cfg->opm != OPM_GPS) { log(1, "Unknown op mode: %d\n", cfg->opm); return NULL; } gar = calloc(1, sizeof(*gar)); if (!gar) return NULL; if (l) { gar->logfn = l; glogfn = l; } gar->cfg = *cfg; if (gar->cfg.opm == OPM_GPS) strcpy(modename, "GPS Backend"); else if (gar->cfg.opm == OPM_PARSE) strcpy(modename, "Parser"); else if (gar->cfg.opm == OPM_DUMP) strcpy(modename, "Data dumper"); gar_debug_level = cfg->debuglevel; log(1, "%s initializing as %s\n", LIBVERSION, modename); list_init(&gar->limgs); #if 0 log(1, "struct gimg=%d\n", sizeof(struct gimg)); log(1, "struct gar_subfile=%d\n", sizeof(struct gar_subfile)); log(1, "struct gar_subdiv=%d\n", sizeof(struct gar_subdiv)); #endif #ifndef TARGET_WIN32CE if (0) { struct rlimit rlmt; rlmt.rlim_cur = 300 * 1024 * 1024; rlmt.rlim_max = 300 * 1024 * 1024; if(setrlimit(RLIMIT_AS, &rlmt)) log(1, "setrlimit DATA failed (%s)\n", strerror(errno)); } #endif return gar; } struct gar *gar_init(char *tdb, log_fn l) { struct gar_config cfg; memset(&cfg, 0, sizeof(struct gar_config)); cfg.opm = OPM_GPS; cfg.debuglevel = 10; return gar_init_cfg(tdb, l, &cfg); } void gar_free(struct gar *g) { if (g->gmap) free(g->gmap); log(1, "Implement me\n"); } static int gar_load_img_hdr(struct gimg *g, unsigned int *dataoffset, unsigned int *blocksize, unsigned int *fatoffset) { int rc; struct hdr_img_t hdr; rc = gread(g, &hdr, sizeof(struct hdr_img_t)); if (rc < 0) { log(7, "Read error: %d(%s)\n", errno, strerror(errno)); return -1; } if (rc != sizeof(struct hdr_img_t)) { log(7, "Error reading header want %d got %d\n", sizeof(struct hdr_img_t), rc); return -1; } if (hdr.xorByte != 0) { log(1, "Please, xor the file key:%02X, use garxor\n", hdr.xorByte); return -1; } if (strncmp(hdr.signature,"DSKIMG",6)) { log(1, "Invalid signature: [%s]\n", hdr.signature); return -1; } if (strncmp(hdr.identifier,"GARMIN",6)) { log(1, "Invalid identifier: [%s]\n", hdr.identifier); return -1; } log(17, "Fat offset: %d hdr:%d\n", hdr.fat_offset, sizeof(hdr)); log(15, "File: [%s]\n", g->file); log(10, "Desc1:[%s]\n", hdr.desc1); log(10, "Desc2:[%s]\n", hdr.desc2); *blocksize = get_blocksize(&hdr); log(15, "Blocksize: %u\n", *blocksize); *dataoffset = hdr.dataoffset; *fatoffset = hdr.fat_offset; log(15, "Dataoffset: %u[%08X]\n", *dataoffset, *dataoffset); return 1; } static void gar_register_gmp_files(struct gimg *g, char *gmpfile) { struct hdr_gmp_t gmp; char buf[20], *cp; char buf1[20]; int rc; off_t gmpoff; strcpy(buf, gmpfile); cp = strchr(buf, '.'); if (!cp) return; *cp = '\0'; gmpoff = gar_file_offset(g, gmpfile); log(10, "GMP %s at %ld\n", buf, gmpoff); glseek(g, gmpoff, SEEK_SET); rc = gread(g, &gmp, sizeof(gmp)); if (rc != sizeof(gmp)) { log(1, "Error reading GMP at %ld\n", gmpoff); return; } gar_log_file_date(11, "GMP Created", &gmp.hsub); log(11, "GMP type:[%s] len=%d vs %d\n", gmp.hsub.type, gmp.hsub.length, sizeof(gmp)); log(11, "GMP TRE at %d\n", gmp.tre_offset); log(11, "GMP RGN at %d\n", gmp.rgn_offset); log(11, "GMP LBL at %d\n", gmp.lbl_offset); log(11, "GMP NET at %d\n", gmp.net_offset); log(11, "GMP NOD at %d\n", gmp.nod_offset); log(11, "GMP UN1 at %d\n", gmp.unknown1); log(11, "GMP UN2 at %d\n", gmp.unknown2); sprintf(buf1, "%s.TRE", buf); gar_fat_add_file(g, buf1, gmp.tre_offset + gmpoff); sprintf(buf1, "%s.RGN", buf); gar_fat_add_file(g, buf1, gmp.rgn_offset + gmpoff); sprintf(buf1, "%s.LBL", buf); gar_fat_add_file(g, buf1, gmp.lbl_offset + gmpoff); sprintf(buf1, "%s.NET", buf); gar_fat_add_file(g, buf1, gmp.net_offset + gmpoff); sprintf(buf1, "%s.NOD", buf); gar_fat_add_file(g, buf1, gmp.nod_offset + gmpoff); } static void gar_check_nt_map(struct gimg *g) { int rc; char **imgs; int nimgs; imgs = gar_file_get_subfiles(g, &nimgs, "GMP"); if (nimgs) { log(4, "NT Map registering files\n"); for (rc = 0; rc < nimgs; rc++) { gar_register_gmp_files(g, imgs[rc]); } free(imgs); g->is_nt = 1; } } int gar_img_load_dskimg(struct gar *gar, char *file, int tdbbase, int data, double north, double east, double south, double west) { struct gimg *g; int rc; unsigned int blocksize; unsigned int dataoffset; unsigned int fatoffset; g = gimg_alloc(gar, file); if (!g) { log(1,"Out of memory!\n"); return -1; } g->tdbbasemap = tdbbase; g->file = strdup(file); g->fd = g_safe_open(file, OPENFLAGS); if (g->fd == -1) { log(1, "Can not open file: [%s] errno=%d(%s)\n", g->file, errno, strerror(errno)); return -1; } if (read(g->fd, &g->xor, sizeof(g->xor)) != sizeof(g->xor)) { log(1, "Error reading xor byte\n"); return -1; } lseek(g->fd, 0, SEEK_SET); if (g->xor) { log(1, "Map is XORed you can use garxor to speed the reading\n"); } if (gar_load_img_hdr(g, &dataoffset, &blocksize, &fatoffset) < 0) { log(1, "Failed to load header from: [%s]\n", g->file); return -1; } rc = gar_load_fat(g, dataoffset, blocksize, fatoffset); if (rc == 0) return -1; gar_check_nt_map(g); if (data) { // FIXME: When we have a TDB we can skip this // but when no TDB must load, we will keep // the dskimg loaded and deal w/ subfiles // We can use MPS file to do this gar_load_subfiles(g); log(6, "Loaded %d mapsets\n", g->mapsets); } gar_init_mdr(g); #if 0 g->north = north; g->east = east; g->south = south; g->west = west; #endif list_append(&g->l, &gar->limgs); return 1; } static int gar_is_gmapsupp(char *file) { int rc, fd; struct hdr_img_t hdr; unsigned char xor; unsigned char *cp; fd = g_safe_open(file, OPENFLAGS); if (fd == -1) return -1; rc = read(fd, &hdr, sizeof(struct hdr_img_t)); close(fd); if (rc < 0) { log(7, "Read error: %d(%s)\n", errno, strerror(errno)); return -1; } if (rc != sizeof(struct hdr_img_t)) { log(11, "Error reading header want %d got %d\n", sizeof(struct hdr_img_t), rc); return 0; } if (hdr.xorByte != 0) { xor = hdr.xorByte; cp = (unsigned char *)&hdr; for (rc = 0; rc < sizeof(struct hdr_img_t); rc++) { *cp = *cp ^ xor; cp++; } } if (strncmp(hdr.signature,"DSKIMG",6)) { return 0; } if (strncmp(hdr.identifier,"GARMIN",6)) { return 0; } return 1; } static void gar_calc_tdblevels(struct gar *gar) { int minbits = 0; int maxbits = 0; int p; struct gimg *g; list_for_entry(g, &gar->limgs, l) { if (g->tdbbasemap) { minbits = g->basebits; } else { p = g->basebits+g->zoomlevels; if (p > maxbits) maxbits = p; } } gar->basebits = minbits; gar->zoomlevels = maxbits - minbits; } int gar_img_load(struct gar *gar, char *file, int data) { if (gar_is_gmapsupp(file) == 1) { log(1, "Loading %s as disk image\n", file); return gar_img_load_dskimg(gar, file, 0, data, 0,0,0,0); } else { int rc; log(1, "Loading %s as TDB\n", file); rc = gar_parse_tdb(gar, file, data); gar_calc_tdblevels(gar); return rc; } } struct gimg *gar_get_dskimg(struct gar *gar, char *file) { struct gimg *g; if (gar->tdbloaded && !file) return NULL; list_for_entry(g, &gar->limgs, l) { if (!file) return g; if (!strcmp(file, g->file)) return g; } return NULL; } libgarmin-0~svn320/src/garmin_fat.c000066400000000000000000000151321112544465000173770ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "garmin_fat.h" #include "garmin_rgn.h" /* Load FAT structure and ASSUME that all files are continious */ char **gar_file_get_subfiles(struct gimg *g, int *count, const char *subext) { struct fat_entry *fe; char *cp; char **ret; int cf = 0; *count = 0; list_for_entry(fe, &g->lfatfiles, l) { cp = strrchr(fe->filename,'.'); if (!cp) continue; cp ++; if (!strcmp(cp, subext)) { cf++; } } if (!cf) return NULL; ret = calloc(cf+1, sizeof(char *)); if (!ret) return NULL; *count = cf; cf = 0; list_for_entry(fe, &g->lfatfiles, l) { cp = strrchr(fe->filename,'.'); if (!cp) continue; cp ++; if (!strcmp(cp, subext)) { ret[cf++] = fe->filename; } } return ret; } ssize_t gar_file_offset(struct gimg *g, char *file) { struct fat_entry *fe; list_for_entry(fe, &g->lfatfiles, l) { if (!strcmp(fe->filename, file)) return fe->offset; } return 0; } ssize_t gar_file_baseoffset(struct gimg *g, char *file) { struct fat_entry *fe; if (g->is_nt) { list_for_entry(fe, &g->lfatfiles, l) { if (strstr(fe->filename, "GMP")) return fe->offset; } log(1, "Error no GMP\n"); } list_for_entry(fe, &g->lfatfiles, l) { if (!strcmp(fe->filename, file)) return fe->offset; } return 0; } ssize_t gar_subfile_offset(struct gar_subfile *sub, char *ext) { struct fat_entry *fe; struct gimg *g = sub->gimg; char fn[20]; sprintf(fn,"%s.%s", sub->mapid, ext); list_for_entry(fe, &g->lfatfiles, l) { if (!strcmp(fe->filename, fn)) return fe->offset; } return 0; } ssize_t gar_subfile_baseoffset(struct gar_subfile *sub, char *ext) { struct fat_entry *fe; struct gimg *g = sub->gimg; char fn[20]; if (g->is_nt) { sprintf(fn,"%s.GMP", sub->mapid); list_for_entry(fe, &g->lfatfiles, l) { if (!strcmp(fe->filename, fn)) return fe->offset; } log(1, "Error no GMP\n"); } sprintf(fn,"%s.%s", sub->mapid, ext); list_for_entry(fe, &g->lfatfiles, l) { if (!strcmp(fe->filename, fn)) return fe->offset; } return 0; } ssize_t gar_file_size(struct gimg *g, char *ext) { struct fat_entry *fe; char *cp; list_for_entry(fe, &g->lfatfiles, l) { cp = strrchr(fe->filename,'.'); if (!cp) continue; cp ++; if (!strcmp(cp, ext)) return fe->size; } return 0; } struct fat_entry *gar_fat_get_fe_by_name(struct gimg *g, char *name) { struct fat_entry *fe; list_for_entry(fe, &g->lfatfiles, l) { if (!strcmp(fe->filename, name)) return fe; } return NULL; } int gar_fat_add_file(struct gimg *g, char *name, off_t offset) { struct fat_entry *fe; fe = calloc(1, sizeof(*fe)); if (!fe) return -1; strcpy(fe->filename, name); fe->size = 0; // fe->offset = offset; log(10, "Creating FAT file:[%s] offset %ld\n", fe->filename, fe->offset); list_append(&fe->l, &g->lfatfiles); return 0; } static int gar_add_fe(struct gimg *g, struct FATblock_t *fent, int blocksize) { struct fat_entry *fe, *fe1; char *cp; fe = calloc(1, sizeof(*fe)); if (!fe) return -1; memcpy(fe->filename, fent->name, 8); cp = strchr(fe->filename, ' '); if (!cp) cp = fe->filename + 8; *cp++ = '.'; memcpy(cp, fent->type, 3); cp += 3; *cp = '\0'; fe->size = fent->size; fe->offset = fent->blocks[0] * blocksize; log(15, "File: [%s] size:[%ld] offset:[%ld/%08lX]\n", fe->filename, fe->size, fe->offset,fe->offset); fe1 = gar_fat_get_fe_by_name(g, fe->filename); if (fe1) { // check to see if the offset is less if (fe1->offset > fe->offset) { log(10, "Correcting offset for [%s]\n", fe->filename); fe1->offset = fe->offset; } if (fe1->size < fe->size) fe1->size = fe->size; free(fe); } else { log(15, "Creating FAT file:[%s] %ld\n", fe->filename, fe->size); list_append(&fe->l, &g->lfatfiles); } return 0; } int gar_load_fat(struct gimg *g, int dataoffset, int blocksize, unsigned int fatoffset) { struct FATblock_t fent; ssize_t s = sizeof(struct FATblock_t); int count = 0; int rc, rsz = 0; struct fat_entry *fe; int userootdir = 0; int fatend = dataoffset; int seendot = 0; if (!fatend) { log(15, "FAT Will use size from rootdir\n"); userootdir = 1; } else { fatend -= sizeof(struct hdr_img_t); log(15, "FAT size %d\n", fatend); } /* This explains the 'reserved entries at start' */ if (fatoffset) { log(14, "FAT offset: %d\n", fatoffset); glseek(g, fatoffset * 512, SEEK_SET); } /* Read reserved FAT entries first */ while ((rc = gread(g, &fent, s)) == s) { if (fent.flag != 0x00) break; rsz+=rc; count ++; } log(17, "FAT Reserved entries %d(%ld)\n", count, s); count = 0; do { rsz+=rc; if(fent.flag != 0x01 && !fatend) break; if(fent.flag != 0x01 && fatend) { if (fatend && rsz>=fatend) break; continue; } if (!seendot||(userootdir && !fatend)) { if (fent.name[0] == ' ' && fent.type[0] == ' ') { fatend = fent.size - s; seendot = 1; } } gar_add_fe(g, &fent, blocksize); count ++; if (fatend && rsz>=fatend) break; } while ((rc = gread(g, &fent, s)) == s); if (!count) { log(1, "Failed to read FAT\n"); return 0; } log(10, "FAT Directory %d entries %d bytes\n", count, rsz); list_for_entry(fe, &g->lfatfiles, l) { log(10,"%s %ld\n",fe->filename,fe->size); } if (userootdir) { dataoffset = fatend + sizeof(struct hdr_img_t); log(15, "FAT DataOffset corrected to %d\n", dataoffset); } return count * s; } int gar_fat_file2fd(struct gimg *g, char *name, int fd) { struct fat_entry *fe; int sz, rc; char buf[4096]; fe = gar_fat_get_fe_by_name(g, name); if (!fe) { log(1, "%s not found in image\n", name); return -1; } sz = fe->size; glseek(g, fe->offset, SEEK_SET); while (sz) { rc = gread(g, buf, sz > sizeof(buf) ? sizeof(buf) : sz); if (rc < 0) { log(1, "Error reading file\n"); return -1; } if (write(fd, buf, rc) != rc) return -1; sz -= rc; } return 0; } libgarmin-0~svn320/src/garmin_fat.h000066400000000000000000000013441112544465000174040ustar00rootroot00000000000000struct fat_entry { list_t l; char filename[13]; off_t size; off_t offset; }; typedef struct fat_block_struct fat_entry_t; int gar_load_fat(struct gimg *g, int dataoffset, int blocksize, unsigned int fatoffset); struct gar_subfile; ssize_t gar_subfile_offset(struct gar_subfile *sub, char *ext); ssize_t gar_file_size(struct gimg *g, char *ext); char **gar_file_get_subfiles(struct gimg *g, int *count, const char *subext); struct fat_entry *gar_fat_get_fe_by_name(struct gimg *g, char *name); ssize_t gar_file_offset(struct gimg *g, char *file); int gar_fat_add_file(struct gimg *g, char *name, off_t offset); ssize_t gar_subfile_baseoffset(struct gar_subfile *sub, char *ext); ssize_t gar_file_baseoffset(struct gimg *g, char *file); libgarmin-0~svn320/src/garmin_lbl.c000066400000000000000000000541321112544465000174010ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "garmin_fat.h" #include "garmin_lbl.h" #include "garmin_rgn.h" #include "garmin_net.h" #include "bsp.h" // process .LBL static const char str6tbl1[] = { ' ','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R' ,'S','T','U','V','W','X','Y','Z' ,0,0,0,0,0 ,'0','1','2','3','4','5','6','7','8','9' ,0,0,0,0,0,0 }; static const char str6tbl2[] = { //@ ! " # $ % & ' ( ) * + , - . / '@','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/' ,0,0,0,0,0,0,0,0,0,0 //: ; < = > ? ,':',';','<','=','>','?' ,0,0,0,0,0,0,0,0,0,0,0 //[ \ ] ^ _ ,'[','\\',']','^','_' }; static const char str6tbl3[] = { '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r', 's','t','u','v','w','x','y','z' }; static int gar_lbl_decode6(struct bspfd *bp, u_int8_t *out, ssize_t len) { int c; unsigned char ch; u_int8_t *cp; int sz = 0; cp = out; while ((c = bsp_fd_get_bits(bp,6)) > -1) { log(20,"got c:%d[%02X]\n",c,c); if (c > 0x2f) break; ch = str6tbl1[c]; if (ch == 0) { if (c == 0x1C) { c = bsp_fd_get_bits(bp,6); if (c < 0) break; ch = str6tbl2[c]; *cp++ = ch; sz++; } else if (c == 0x1B) { c = bsp_fd_get_bits(bp,6); if (c < 0) break; ch = str6tbl3[c]; *cp++ = ch; sz++; } else if (c == 0x1D) { // delimiter for formal name *cp++ = '|'; sz++; } else if (c == 0x1E) { *cp++ = '_'; // hide previous symbols sz++; } else if (c == 0x1F) { *cp++ = '^'; // hide next symbols sz++; } else if (c >= 0x20 && c <= 0x2F ) { *cp++ = '@'; sz++; } } else { *cp++ = ch; sz++; } if (sz >= len-1) break; } *cp = '\0'; return sz; } static int gar_lbl_decode8(struct bspfd *bp, u_int8_t *out, ssize_t len) { int c, sz = 0; unsigned char *cp = out; while ((c = bsp_fd_get_bits(bp,8)) > -1) { if (!c) break; if (c == 0x1A) { *cp++ = '$'; sz++; } else if (c == 0x1B) { *cp++ = '#'; sz++; } else if (c == 0x1C) { *cp++ = '~'; sz++; } else if (c == 0x1D) { // delimiter for formal name *cp++ = '|'; sz++; } else if (c == 0x1E) { *cp++ = '_'; // hide previous symbols sz++; } else if (c == 0x1F) { *cp++ = '^'; // hide next symbols sz++; } else if (c>= 0x01 && c<=0x06) { *cp++ = '@'; sz++; } else { *cp++ = c; sz ++; } if (sz >=len-1) break; } *cp = '\0'; return sz; } static int gar_lbl_decode9(struct bspfd *bp, u_int8_t *out, ssize_t len) { return gar_lbl_decode8(bp, out, len); } static int gar_lbl_decode10(struct bspfd *bp, u_int8_t *out, ssize_t len) { return gar_lbl_decode8(bp, out, len); } static int gar_lbl_decode16(struct bspfd *bp, u_int8_t *out, ssize_t len) { int c, sz = 0; unsigned char *cp = out; int i; // *(cp+sz) = '\0'; // return sz; sz = gread(bp->g, cp, len); if (0 ) { char dbuf[5*len]; c = 0; for (i=0; i < sz; i++) c+=sprintf(dbuf+c, "0x%02X,", cp[i]); log(14, "LBLR:[%s]\n", dbuf); } return sz; #if 0 while ((c = bsp_fd_get_bits(bp,8)) > -1) { if (c == 0x1A) { *cp++ = '$'; sz++; } else if (c == 0x1B) { *cp++ = '#'; sz++; } else if (c == 0x1C) { *cp++ = '~'; sz++; } else if (c == 0x1D) { // delimiter for formal name *cp++ = '|'; sz++; } else if (c == 0x1E) { *cp++ = '_'; // hide previous symbols sz++; } else if (c == 0x1F) { *cp++ = '^'; // hide next symbols sz++; } else if (c>= 0x01 && c<=0x06) { *cp++ = '@'; sz++; } else { *cp++ = c; sz ++; } /* *cp++ = c>>8; sz++; if (sz >=len-1) break; *cp++ = c&0xff; sz++; */ sz += snprintf(cp+sz, len-sz, "%02x", c); if (sz >=len-1 || sz > 64) break; if (c == 1) break; } *(cp+sz) = '\0'; return sz; #endif } static struct gar_lbl_t *gar_alloc_lbl(void) { return calloc(1, sizeof(struct gar_lbl_t)); } static u_int32_t gar_lbl_offset(struct gar_subfile *sub ,u_int32_t offlbl, int type) { u_int32_t off1, off = 0xFFFFFFFF; switch(type) { case L_LBL: if (sub->lbl) off = sub->lbl->offset + sub->lbl->lbl1off + ( offlbl << sub->lbl->addrshift); break; case L_POI: if (sub->lbl) { struct gimg *gimg = sub->gimg; char b[3]; int rc; off = sub->lbl->offset + sub->lbl->lbl6off + offlbl; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %zd\n", off); return 0xFFFFFFFF; } rc = gread(gimg, b, 3); if (rc!=3) return 0xFFFFFFFF; off = get_u24(b); off &= 0x3FFFFF; off = sub->lbl->offset + sub->lbl->lbl1off + ( off << sub->lbl->addrshift); } break; case L_NET: off1 = gar_net_get_lbl_offset(sub, offlbl, 0); if (off1) { off = sub->lbl->offset + sub->lbl->lbl1off + (off1 << sub->lbl->addrshift); } break; default: log(1, "Unknown label type: %d\n", type); } return off; } int gar_get_lbl(struct gar_subfile *sub, off_t offset, int type, u_int8_t *buf, int buflen) { u_int32_t off; struct bspfd bp; struct gimg *gimg = sub->gimg; *buf = '\0'; if (!sub->lbl || !sub->lbl->decode) return 0; if (offset == 0) return 0; off = gar_lbl_offset(sub, offset, type); if (off == 0xFFFFFFFF) return 0; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %zd\n", off); return -1; } bsp_fd_init(&bp, gimg); return sub->lbl->decode(&bp, buf, buflen); } static int gar_lbl_init_obj_counts(struct gar_subfile *sub, struct hdr_lbl_t *lbl) { if (lbl->lbl2_rec_size) sub->lbl_countries = lbl->lbl2_length/lbl->lbl2_rec_size; if (lbl->lbl3_rec_size) sub->lbl_regions = lbl->lbl3_length/lbl->lbl3_rec_size; if (lbl->lbl4_rec_size) sub->lbl_cities = lbl->lbl4_length/lbl->lbl4_rec_size; if (lbl->lbl8_rec_size) sub->lbl_zips = lbl->lbl8_length/lbl->lbl8_rec_size; log(1, "Have %d countries, %d regions, %d cities, %d zip codes\n", sub->lbl_countries, sub->lbl_regions, sub->lbl_cities, sub->lbl_zips); return 0; } int gar_init_lbl(struct gar_subfile *sub) { struct hdr_lbl_t lbl; struct gar_lbl_t *l; off_t off; struct gimg *gimg = sub->gimg; int rc; log(11, "LBL initializing ...\n"); off = gar_subfile_offset(sub, "LBL"); if (!off) { log(1,"No LBL file\n"); return 0; } if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); return -1; } rc = gread(gimg, &lbl, sizeof(struct hdr_lbl_t)); if (rc != sizeof(struct hdr_lbl_t)) { log(1, "LBL: Can not read header\n"); return -1; } if (strncmp("GARMIN LBL", lbl.hsub.type, 10)) { log(1, "LBL: Invalid header type:[%s]\n", lbl.hsub.type); return -1; } gar_log_file_date(11, "LBL Created", &lbl.hsub); l = gar_alloc_lbl(); if (!l) { log(1, "LBL: Out of memory\n"); return -1; } switch(lbl.coding) { case 0x06: log(11,"LBL: Uses 6bit coding\n"); l->decode = gar_lbl_decode6; l->bits = 6; break; case 0x08: log(11,"LBL: Uses 8bit coding\n"); l->decode = gar_lbl_decode8; l->bits = 8; break; case 0x09: log(11,"LBL: Uses 9bit coding\n"); l->decode = gar_lbl_decode9; l->bits = 9; break; case 0x0A: log(11,"LBL: Uses 10bit coding\n"); l->decode = gar_lbl_decode10; l->bits = 0x0a; break; case 0x0B: log(11,"LBL: Unknown Uses 0x0b(NT) bit coding\n"); l->decode = gar_lbl_decode16; l->bits = 0x0b; break; default: log(1,"LBL: %02X unknown coding\n",lbl.coding); break; }; if (lbl.hsub.length > 0xAA) { if (1250 <= lbl.codepage && lbl.codepage <=1258) { sprintf(l->codepage,"Windows-%d", lbl.codepage); } else if (lbl.codepage == 950) sprintf(l->codepage,"Big5"); else sprintf(l->codepage,"ascii"); log(11,"LBL: Uses %s encoding:%d\n", l->codepage,lbl.codepage); } l->offset = gar_subfile_baseoffset(sub, "LBL"); l->lbl1off = lbl.lbl1_offset; l->lbl1size = lbl.lbl1_length; l->lbl6off = lbl.lbl6_offset; l->lbl6size = lbl.lbl6_length; l->addrshift = lbl.addr_shift; l->addrshiftpoi = lbl.lbl6_addr_shift; l->lbl6_glob_mask = lbl.lbl6_glob_mask; sub->lbl = l; gar_lbl_init_obj_counts(sub, &lbl); return 0; } void gar_free_lbl(struct gar_subfile *sub) { free(sub->lbl); sub->lbl = NULL; } static int gar_get_at(struct gar_subfile *sub, off_t offset, char *buf, int buflen) { u_int32_t off = offset; struct bspfd bp; struct gimg *gimg = sub->gimg; *buf = '\0'; if (off == 0xFFFFFFFF) return -1; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %zd\n", off); return -1; } bsp_fd_init(&bp, gimg); if (!sub->lbl->decode) return 0; return sub->lbl->decode(&bp, (u_int8_t *)buf, buflen); } int gar_init_srch(struct gar_subfile *sub, int what) { struct hdr_lbl_t lbl; struct gimg *gimg = sub->gimg; off_t off, off1; int nc, rc; int idx; char *rb; char *cp; char buf[1024]; off = gar_subfile_offset(sub, "LBL"); if (!off) { log(1,"No LBL file\n"); return 0; } if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); goto outerr; } rc = gread(gimg, &lbl, sizeof(struct hdr_lbl_t)); if (rc != sizeof(struct hdr_lbl_t)) { log(1, "LBL: Can not read header\n"); goto outerr; } off = gar_subfile_baseoffset(sub, "LBL"); off1 = off; if (what == 0) { if (lbl.lbl2_rec_size == 0) goto outerr; nc = lbl.lbl2_length/lbl.lbl2_rec_size; log(1, "%d countries defined %d\n", nc,lbl.lbl2_length); if (!nc) goto out; sub->countries = calloc(nc + 1, sizeof(char *)); if (!sub->countries) goto outerr; idx = 1; rb = malloc(lbl.lbl2_length); if (!rb) { free(sub->countries); sub->countries = NULL; goto outerr; } off += lbl.lbl2_offset; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); goto outerr; } rc = gread(gimg, rb, lbl.lbl2_length); if (rc != lbl.lbl2_length) { log(1, "LBL: Error reading countries\n"); free(rb); free(sub->countries); sub->countries = NULL; goto outerr; } cp = rb; while (cp < rb + lbl.lbl2_length) { off = get_u24(cp); off <<= lbl.addr_shift; off += off1 + lbl.lbl1_offset;// + sizeof(struct hdr_lbl_t); gar_get_at(sub, off, buf, sizeof(buf)); log(15, "LBL: CNT[%d] off=%03lX [%s]\n", idx, off, buf); sub->countries[idx] = strdup(buf); idx++; cp += lbl.lbl2_rec_size; } sub->ccount = idx; free(rb); //return idx; goto out; } if (lbl.lbl3_rec_size) { nc = lbl.lbl3_length/lbl.lbl3_rec_size; log(1, "%d regions defined sz=%d\n", nc,lbl.lbl3_rec_size); if (!nc) goto out; sub->regions = calloc(nc + 1, sizeof(struct region_def *)); if (!sub->regions) goto outerr; rb = malloc(lbl.lbl3_length); off = off1 + lbl.lbl3_offset; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); goto outerr; } rc = gread(gimg, rb, lbl.lbl3_length); if (rc != lbl.lbl3_length) { log(1, "LBL: Error reading regions\n"); free(rb); free(sub->regions); sub->regions = NULL; goto outerr; } cp = rb; idx = 1; while (cp < rb + lbl.lbl3_length) { off = get_u24(cp+2); off <<= lbl.addr_shift; off += off1 + lbl.lbl1_offset;// + sizeof(struct hdr_lbl_t); gar_get_at(sub, off, buf, sizeof(buf)); log(15, "LBL: CNT[%d] off=%03lX cnt:%d [%s]\n", idx, off, get_u16(cp),buf); sub->regions[idx] = calloc(1, sizeof(struct region_def)); if (!sub->regions[idx]) break; sub->regions[idx]->name = strdup(buf); sub->regions[idx]->country = get_u16(cp); idx++; cp += lbl.lbl3_rec_size; } sub->rcount = idx; free(rb); } if (lbl.lbl4_rec_size) { // cities nc = lbl.lbl4_length/lbl.lbl4_rec_size; log(1, "%d cities defined sz=%d\n", nc,lbl.lbl4_rec_size); if (!nc) goto out; sub->cities = calloc(nc + 1, sizeof(struct city_def *)); if (!sub->cities) goto outerr; rb = malloc(lbl.lbl4_length); off = off1 + lbl.lbl4_offset; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); goto outerr; } rc = gread(gimg, rb, lbl.lbl4_length); if (rc != lbl.lbl4_length) { log(1, "LBL: Error reading cities\n"); free(rb); free(sub->cities); sub->regions = NULL; goto outerr; } cp = rb; idx = 1; while (cp < rb + lbl.lbl4_length) { unsigned short tmp = get_u16(cp+3); sub->cities[idx] = calloc(1, sizeof(struct city_def)); if (!sub->cities[idx]) break; sub->cities[idx]->region_idx = tmp & 0x1fff; if (tmp & (1<<15)) { sub->cities[idx]->point_idx = *(char *)cp; sub->cities[idx]->subdiv_idx = get_u16(cp+1); log(15, "LBL: City def region %d at pointidx: %d, subdividx:%d\n", sub->cities[idx]->region_idx, sub->cities[idx]->point_idx, sub->cities[idx]->subdiv_idx); } else { off = get_u24(cp); off <<= lbl.addr_shift; off += off1 + lbl.lbl1_offset;// + sizeof(struct hdr_lbl_t); gar_get_at(sub, off, buf, sizeof(buf)); log(15, "LBL: CNT[%d] off=%03lX cnt:%d region:%d [%s]\n", idx, off, *(short *)cp,sub->cities[idx]->region_idx,buf); sub->cities[idx]->label = strdup(buf); } idx++; cp += lbl.lbl4_rec_size; } free(rb); sub->cicount = idx; } // lbl7 = index of POI types log(1,"lbl7 off=%04X size=%d, recsize=%d\n", lbl.lbl7_offset, lbl.lbl7_length,lbl.lbl7_rec_size); off = off1 + lbl.lbl7_offset; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); goto outerr; } if (sub->gimg->gar->cfg.opm == OPM_PARSE) { unsigned char rec[lbl.lbl7_rec_size]; idx = 0; while (idx < lbl.lbl7_length) { gread(gimg, rec, lbl.lbl7_rec_size); log(11, "%d: %x\n", idx, *(int *)rec); idx+=lbl.lbl7_rec_size; } } // ZIPs if (!lbl.lbl8_rec_size) goto pois; nc = lbl.lbl8_length/lbl.lbl8_rec_size; log(1, "%d ZIPs defined sz=%d\n", nc,lbl.lbl8_rec_size); if (!nc) goto pois; sub->zips = calloc(nc + 1, sizeof(struct zip_def *)); if (!sub->zips) goto outerr; rb = malloc(lbl.lbl8_length); off = off1 + lbl.lbl8_offset; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); goto outerr; } rc = gread(gimg, rb, lbl.lbl8_length); if (rc != lbl.lbl8_length) { log(1, "LBL: Error reading ZIPs\n"); free(rb); free(sub->zips); sub->zips = NULL; goto outerr; } cp = rb; idx = 1; while (cp < rb + lbl.lbl8_length) { sub->zips[idx] = calloc(1, sizeof(struct zip_def)); if (!sub->zips[idx]) break; off = get_u24(cp); off <<= lbl.addr_shift; off += off1 + lbl.lbl1_offset; gar_get_at(sub, off, buf, sizeof(buf)); log(15, "LBL: ZIP[%d] off=%03lX [%s]\n", idx, off, buf); sub->zips[idx]->code = strdup(buf); idx++; cp += lbl.lbl8_rec_size; } free(rb); sub->czips = idx; pois: // Parse POIs // lbl5 = index of POIS sorted by types and names log(1,"lbl5 off=%04X size=%d, recsize=%d\n", lbl.lbl5_offset, lbl.lbl5_length,lbl.lbl5_rec_size); off = off1 + lbl.lbl5_offset; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); goto outerr; } if (sub->gimg->gar->cfg.opm == OPM_PARSE) { struct gar_poi_properties *pr; unsigned char rec[lbl.lbl5_rec_size]; int of,si,id; struct gobject *o; idx = 0; while (idx < lbl.lbl5_length) { off = off1 + lbl.lbl5_offset + idx; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %ld\n", off); goto outerr; } gread(gimg, rec, lbl.lbl5_rec_size); of = get_u24(rec); si = of >> 8; id = of & 0xff; log(11, "%d: type:%d sdidx:%d idx:%d %x\n", idx, *(u_int8_t *)(rec+3),si,id, *(int *)rec); o = gar_get_subfile_object_byidx(sub, si, id, GO_POINT); if (o) { char *cp = gar_object_debug_str(o); if (cp) { log(11, "poi:%s\n", cp); free(cp); cp = gar_get_object_lbl(o); if (cp) { log(11, "poi:%s\n", cp); free(cp); } } pr = gar_get_poi_properties(o->gptr); if (pr) { gar_log_poi_properties(sub, pr); gar_free_poi_properties(pr); } gar_free_objects(o); } else { log(11, "not found\n"); } idx+=lbl.lbl5_rec_size; } } out: return 0; outerr: return -1; } static void gar_free_region_def(struct region_def *rd) { if (rd->name) free(rd->name); free(rd); } static void gar_free_city_def(struct city_def *cd) { if (cd->label) free(cd->label); free(cd); } static void gar_free_zip_def(struct zip_def *zd) { if (zd->code) free(zd->code); free(zd); } void gar_free_srch(struct gar_subfile *f) { int i; if (f->countries) { for (i = 0; i < f->ccount; i++) { if (f->countries[i]) free(f->countries[i]); } f->ccount = 0; free(f->countries); f->countries = NULL; } if (f->regions) { for (i = 0; i < f->rcount; i++) { if (f->regions[i]) gar_free_region_def(f->regions[i]); } f->rcount = 0; free(f->regions); f->regions = NULL; } if (f->cities) { for (i = 0; i < f->cicount; i++) { if (f->cities[i]) gar_free_city_def(f->cities[i]); } f->cicount = 0; free(f->cities); f->cities = NULL; } if (f->zips) { for (i = 0; i < f->czips; i++) { if (f->zips[i]) gar_free_zip_def(f->zips[i]); } f->czips = 0; free(f->zips); f->zips = NULL; } } void gar_log_poi_properties(struct gar_subfile *sub, struct gar_poi_properties *p) { unsigned char buf[1024]; log(11, "POI: flags:%x, lblat:%d, number=%s,city=%d,zip=%d,phone=%s\n", p->flags, p->lbloff, p->number?:"", p->cityidx, p->zipidx, p->phone?:""); if (p->flags&POI_CITY) { if (p->cityidx < sub->cicount) { if (sub->cities[p->cityidx]->label) { log(11, "POI: city=%s\n", sub->cities[p->cityidx]->label); } else { struct gobject *o; o = gar_get_subfile_object_byidx(sub, sub->cities[p->cityidx]->subdiv_idx, sub->cities[p->cityidx]->point_idx, GO_POINT); if (o) { char *l; l = gar_get_object_lbl(o); if (l) { log(11, "POI: city=%s\n", l); free(l); } gar_free_objects(o); } } } else log(11, "POI: invalid cityidx\n"); } if (p->flags&POI_ZIP) { if (p->zipidx < sub->czips) log(11, "POI: zip=%s\n", sub->zips[p->zipidx]->code); else log(11, "POI: invalid zipidx\n"); } gar_get_lbl(sub, p->lbloff, L_LBL, buf, sizeof(buf)); log(11, "POI: label=%s\n", buf); if (p->flags&POI_STREET) { gar_get_lbl(sub, p->streetoff, L_LBL, buf, sizeof(buf)); log(11, "POI: street=%s\n", buf); } } void gar_free_poi_properties(struct gar_poi_properties *p) { if (p->number) free(p->number); if (p->phone) free(p->phone); free(p); } static int gar_decode_base11(unsigned char *cp, char *out, int l) { int sz = 0; int a, b; int done = 0; int rb = 0; *cp &= 0x7f; do { done = (*cp) & 0x80; *cp &= 0x7f; a = (*(cp))/11; b = (*(cp))%11; if (a!=10&&b!=10) { sz += sprintf(out+sz, "%d%d", a, b); } else { if (a!=10) sz += sprintf(out+sz, "%d-", a); else if (b!=10) sz += sprintf(out+sz, "-%d", b); else sz += sprintf(out+sz, " "); } if (sz >= l-3) break; rb++; cp++; } while (!done); return rb; } static unsigned char gar_get_setbit(unsigned char b, int bit) { int set=0; int i; for (i=0; i < 8; i++) { if (b&(1<> (8-bits); for (i=0; i < bits; i++) { if (!(mask&(1<subdiv->subfile->gimg; struct gar_poi_properties *p; u_int32_t off; u_int8_t fl; int tmp; unsigned char buf[256]; char l[1024]; unsigned char *cp = buf; if (!poi->is_poi) return NULL; off = poi->subdiv->subfile->lbl->offset + poi->subdiv->subfile->lbl->lbl6off + poi->lbloffset; if (glseek(gimg, off, SEEK_SET) != off) { log(1, "LBL: Error can not seek to %zd\n", off); return NULL; } fl = poi->subdiv->subfile->lbl->lbl6_glob_mask; log(12, "POI global properties: %x\n", fl); tmp = gread(gimg, buf, sizeof(buf)); if (tmp < 0) { log(1, "LBL: Error reading poi properties\n"); return NULL; } p = calloc(1, sizeof(*p)); if (!p) return NULL; tmp = get_u24(cp); cp+=3; p->lbloff = tmp & 0x3fffff; if (tmp & (1<<23)) { log(12, "Partial properties: %x\n", *cp); // p->flags = fl-*(signed char *)cp++;//gar_mask_properties(fl, *cp++); fl = p->flags = gar_mask_properties(fl, *cp++); log(12, "Partial properties: %x\n", p->flags); } else p->flags = fl; if (fl & POI_STREET_NUM) { if (*cp&0x80) { // base11 cp += gar_decode_base11(cp, l, sizeof(l)); p->number = strdup(l); } else { // ptr to lbl tmp = get_u24(cp); if (gar_get_lbl(poi->subdiv->subfile, L_LBL, tmp, (unsigned char*)l, sizeof(l))) p->number = strdup(l); cp+=3; } } if (fl & POI_STREET) { // 3 bytes ptr to lbl1 p->streetoff = get_u24(cp)&0x3fffff; cp+=3; } if (fl & POI_CITY) { if (poi->subdiv->subfile->cicount < 256) p->cityidx = *cp++; else { p->cityidx = get_u16(cp); cp+=2; } } if (fl & POI_ZIP) { if (poi->subdiv->subfile->czips < 256) p->zipidx = *cp++; else { p->zipidx = get_u16(cp); cp+=2; } } if (fl & POI_PHONE) { cp += gar_decode_base11(cp, l, sizeof(l)); p->phone = strdup(l); } if (fl & POI_EXIT) { // ptr to lblX exits p->exitoff = get_u24(cp); cp+=3; } if (fl & POI_TIDE_PREDICT) { // ptr to lblX tide p->tideoff = get_u24(cp); cp+=3; } return p; } libgarmin-0~svn320/src/garmin_lbl.h000066400000000000000000000016711112544465000174060ustar00rootroot00000000000000int gar_init_lbl(struct gar_subfile *sub); void gar_free_lbl(struct gar_subfile *sub); int gar_get_lbl(struct gar_subfile *sub, off_t offset, int type, u_int8_t *buf, int buflen); int gar_init_srch(struct gar_subfile *sub, int what); void gar_free_srch(struct gar_subfile *sub); struct gar_poi_properties; void gar_free_poi_properties(struct gar_poi_properties *p); struct gar_poi_properties *gar_get_poi_properties(struct gpoint *poi); void gar_log_poi_properties(struct gar_subfile *sub, struct gar_poi_properties *p); #define POI_STREET_NUM (1<<0) #define POI_STREET (1<<1) #define POI_CITY (1<<2) #define POI_ZIP (1<<3) #define POI_PHONE (1<<4) #define POI_EXIT (1<<5) #define POI_TIDE_PREDICT (1<<6) #define POI_UNKNOW (1<<7) struct gar_poi_properties { u_int8_t flags; u_int32_t lbloff; char *number; u_int32_t streetoff; unsigned short cityidx; unsigned short zipidx; char *phone; u_int32_t exitoff; u_int32_t tideoff; }; libgarmin-0~svn320/src/garmin_mdr.c000066400000000000000000000360001112544465000174040ustar00rootroot00000000000000#include #include #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "garmin_fat.h" #include "garmin_rgn.h" #include "garmin_mdr.h" #include #include #include #include "GarminTypedef.h" struct hdr_mdr_t { struct hdr_subfile_part_t hsub; u_int32_t hdr1; // some kind of header u_int32_t hdr2; //////////////////// // images u_int32_t offset1; u_int32_t length1; u_int16_t unknown11; u_int32_t unknown12; u_int32_t offset2; u_int32_t length2; u_int16_t unknown21; u_int32_t unknown22; u_int32_t offset3; u_int32_t length3; u_int16_t unknown31; u_int32_t unknown32; u_int32_t offset4; u_int32_t length4; u_int16_t unknown41; u_int32_t unknown42; u_int32_t offset5; u_int32_t length5; u_int16_t unknown51; u_int32_t unknown52; u_int32_t offset6; u_int32_t length6; u_int16_t unknown61; u_int32_t unknown62; u_int32_t offset7; u_int32_t length7; u_int16_t unknown71; u_int32_t unknown72; u_int32_t offset8; u_int32_t length8; u_int16_t unknown81; u_int32_t unknown82; u_int32_t offset9; u_int32_t length9; u_int16_t unknown91; u_int32_t unknown92; u_int32_t offset10; u_int32_t length10; u_int32_t unknown101; u_int32_t offset11; u_int32_t length11; u_int16_t unknown111; u_int32_t unknown112; u_int32_t offset12; u_int32_t length12; u_int16_t unknown121; u_int32_t unknown122; u_int32_t offset13; u_int32_t length13; u_int16_t unknown131; u_int32_t unknown132; u_int32_t offset14; u_int32_t length14; u_int16_t unknown141; u_int32_t unknown142; u_int32_t offset15; u_int32_t length15; u_int8_t unknown151; u_int32_t offset16; u_int32_t length16; u_int16_t unknown161; u_int32_t unknown162; // second block? u_int32_t offset17; u_int32_t length17; u_int32_t unknown171; u_int32_t offset18; u_int32_t length18; u_int16_t unknown181; u_int32_t unknown182; u_int32_t offset20; u_int32_t length20; u_int16_t unknown201; u_int32_t unknown202; u_int32_t offset21; u_int32_t length21; u_int16_t unknown211; u_int32_t unknown212; u_int32_t offset22; u_int32_t length22; u_int16_t unknown221; u_int32_t unknown222; u_int32_t offset23; u_int32_t length23; u_int32_t unknown231; u_int16_t unknown232; u_int32_t offset24; u_int32_t length24; u_int32_t unknown241; u_int16_t unknown242; u_int32_t offset25; u_int32_t length25; u_int32_t unknown251; u_int16_t unknown252; u_int32_t offset26; u_int32_t length26; u_int32_t unknown261; u_int16_t unknown262; u_int32_t offset27; u_int32_t length27; u_int16_t unknown271; u_int32_t unknown272; u_int32_t offset28; u_int32_t length28; u_int16_t unknown281; u_int32_t unknown282; u_int32_t offset29; u_int32_t length29; u_int16_t unknown291; u_int32_t unknown292; u_int32_t offset30; u_int32_t length30; u_int16_t unknown301; u_int32_t unknown302; u_int32_t offset31; u_int32_t length31; u_int16_t unknown311; u_int32_t unknown312; u_int32_t offset32; u_int32_t length32; u_int16_t unknown321; u_int32_t unknown322; // u_int8_t unknownbl21[8]; u_int32_t offset33; u_int32_t length33; // u_int32_t unknown331; // u_int16_t unknown332; // u_int8_t unknownbl2[6]; /* u_int32_t offset34; u_int32_t length34; u_int32_t unknown341; u_int16_t unknown342; */ u_int32_t offset35; u_int32_t length35; u_int16_t unknown351; u_int32_t unknown352; u_int32_t offset36; u_int32_t length36; u_int32_t offset37; u_int32_t length37; u_int16_t unknown371; u_int32_t unknown372; u_int32_t offset38; u_int32_t length38; u_int16_t unknown381; u_int32_t unknown382; u_int32_t offset39; u_int32_t length39; u_int16_t unknown391; u_int32_t unknown392; u_int32_t offset40; u_int32_t length40; u_int16_t unknown401; u_int32_t unknown402; u_int32_t offset41; u_int32_t length41; u_int16_t unknown411; u_int32_t unknown412; // len = 568 } __attribute((packed)); int gar_init_mdr(struct gimg *g) { int fcnt; int i,rc; struct gar_mdr *m; char **files; struct hdr_mdr_t mdr; m = calloc(1, sizeof(*m)); if (!m) return -1; files = gar_file_get_subfiles(g, &fcnt, "MDR"); if (files) { if (fcnt > 1) { log(1, "Warning: More than one MDR is not supported\n"); } for (i=0; i < fcnt; i++) { ssize_t off = gar_file_offset(g, files[i]); if (glseek(g, off, SEEK_SET) != off) { log(1, "Error seeking to %zd\n", off); return -1; } rc = gread(g, &mdr, sizeof(mdr)); if (rc < 0) { log(1, "Error reading MDR header\n"); return -1; } log(1, "HDR len =%d our=%d\n", mdr.hsub.length, sizeof(mdr)); m->mdroff = gar_file_baseoffset(g, files[i]); m->idxfiles_offset = mdr.offset1; m->idxfiles_len = mdr.length1; g->mdr = m; break; } free(files); } return 1; } int gar_mdr_get_files(struct gmap *files, struct gimg *g) { struct gar_mdr *m = g->mdr; int i, cnt = m->idxfiles_len/4; struct gar_subfile *sub; unsigned int *id; char buf[m->idxfiles_len]; unsigned int off; int idx = 0; off = g->mdr->mdroff + m->idxfiles_offset; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error seeking to %d\n", off); return -1; } i = gread(g, &buf, m->idxfiles_len); if (i!=m->idxfiles_len) { log(1, "Error reading indexed files\n"); return -1; } id = (unsigned int *)&buf[0]; files->subs = calloc(cnt, sizeof(struct gar_subfile *)); if (!files->subs) return -1; files->subfiles = cnt; for (i = 0; i < cnt; i++) { sub = gar_find_subfile_byid(g, *id); if (!sub) { log(1, "Error can not find id %d\n", *id); } else { files->subs[idx++] = sub; } id++; } files->lastsub = idx; return idx; } #ifdef STANDALONE static void print_buf(char *pref, unsigned char *a, int s) { char buf[4096]; int i,sz = 0; for (i=0; i < s; i++) { sz += sprintf(buf+sz, "%02X ",a[i]); } log(1, "%s :%s\n", pref, buf); } static void print_bufa(char *pref, unsigned char *a, int s) { char buf[4096]; int i,sz = 0; int inasc = 0; for (i=0; i < s; i++) { if (isprint(a[i])) { sz += sprintf(buf+sz, "%s%c", inasc ? "" : "[", a[i]); inasc = 1; } else { sz += sprintf(buf+sz, "%s%02X ", inasc ? "]" : "",a[i]); inasc = 0; } } log(1, "%s :%s\n", pref, buf); } struct shead { // unsigned char b1; unsigned char head[6]; } __attribute((packed)); struct search_entry { unsigned char text[3]; u_int8_t b1; u_int8_t b2; u_int8_t b3; } __attribute((packed)); static int gar_log_o17(struct gimg *g, u_int32_t base, u_int32_t offset, u_int32_t len) { int i = 0, rc, sz = 0, bp = 0; off_t off = base+offset; unsigned char buf[1024]; int dl = gar_debug_level; char pref[10]; struct shead head; struct search_entry ent; if (!len) return 0; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error seeking to %zd\n", off); return -1; } gread(g, &head, sizeof(head)); sprintf(pref, "header"); print_buf(pref, (char *)&head, sizeof(head)); sz = sizeof(head); while (sz < len) { rc = gread(g, &ent, sizeof(ent)); if ( rc < 0) break; log(1, "%x %02X %02X %02X [%.3s]\n", sz, ent.b1, ent.b2,ent.b3,ent.text); sz += rc; i++; } log(1, "Done %d len:%d sz=%d\n",i, len, sz); } static int gar_log_cstrings(struct gimg *g, u_int32_t base, u_int32_t offset, u_int32_t len) { int i = 0, rc, sz = 0, bp = 0; off_t off = base+offset; unsigned char buf[1024]; int dl = gar_debug_level; char pref[10]; if (!len) return 0; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error seeking to %zd\n", off); return -1; } sprintf(pref, "lbl"); do { rc = gread(g, buf + bp, sizeof(buf) - bp); print_buf(pref, buf, rc); // log(1, "STR:[%s] len:[%d]\n", buf, strlen(buf)); // memmove(buf, buf + strlen(buf) + 1, strlen(buf)); // bp = i++; sz += rc; } while (sz < len); log(1, "Done %d len:%d rs:%d\n",i); return i; } static int gar_log_imgs(struct gimg *g, u_int32_t base, u_int32_t offset, u_int32_t len, u_int16_t recsize) { int i,rc; off_t off = base+offset; unsigned char buf[recsize]; int dl = gar_debug_level; char pref[10]; if (!len) return; gar_debug_level = 13; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error seeking to %zd\n", off); return -1; } for (i=0; i < len/recsize; i++) { rc = gread(g, buf, recsize); if (rc != recsize) { log(1, "Error reading record %d\n", i); } log(1, "IMG: %d/I%08X\n", *(u_int32_t*)buf,*(u_int32_t*)buf); } gar_debug_level = dl; log(1, "Done %d len:%d rs:%d\n",i, len, recsize); return i; } static int gar_log_recs(struct gimg *g, u_int32_t base, u_int32_t offset, u_int32_t len, u_int16_t recsize) { int i,rc; off_t off = base+offset; unsigned char buf[recsize]; int dl = gar_debug_level; char pref[10]; if (!len) return; gar_debug_level = 13; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error seeking to %zd\n", off); return -1; } for (i=0; i < len/recsize; i++) { rc = gread(g, buf, recsize); if (rc != recsize) { log(1, "Error reading record %d\n", i); } sprintf(pref, "%d", i); print_buf(pref, buf, recsize); } gar_debug_level = dl; log(1, "Done %d len:%d rs:%d\n",i, len, recsize); return i; } static int gar_read_mdr(struct gimg *g, char *file) { int rc; struct hdr_mdr_t mdr; ssize_t off = gar_file_offset(g, file); if (glseek(g, off, SEEK_SET) != off) { log(1, "Error seeking to %zd\n", off); return -1; } rc = gread(g, &mdr, sizeof(mdr)); if (rc < 0) { log(1, "Error reading MDR header\n"); return -1; } log(1, "HDR len =%d our=%d\n", mdr.hsub.length, sizeof(mdr)); log(1, "hdr: %08X %08X\n", mdr.hdr1, mdr.hdr2); log(1, "o1: %d %d %d %d\n", mdr.offset1, mdr.length1, mdr.unknown11, mdr.unknown12); // recsz ok if more than 256 images 2b img idx // gar_log_recs(g, off, mdr.offset1, mdr.length1, mdr.unknown11); gar_log_imgs(g, off, mdr.offset1, mdr.length1, mdr.unknown11); log(1, "o2: %d %d %d %d\n", mdr.offset2, mdr.length2, mdr.unknown21, mdr.unknown22); gar_log_recs(g, off, mdr.offset2, mdr.length2, mdr.unknown21); log(1, "o3: %d %d %d %d\n", mdr.offset3, mdr.length3, mdr.unknown31, mdr.unknown32); // // gar_log_recs(g, off, mdr.offset3, mdr.length3, mdr.unknown31); // log(1, "o4: %d %d %d %d\n", mdr.offset4, mdr.length4, mdr.unknown41, mdr.unknown42); // lots of ok 3 bytes - indexed by ... ? // gar_log_recs(g, off, mdr.offset4, mdr.length4, mdr.unknown41); log(1, "o5: %d %d %d %d\n", mdr.offset5, mdr.length5, mdr.unknown51, mdr.unknown52); // size = 8 ok cities 1b map 1/2b idx 8A 08 80 00 00 // gar_log_recs(g, off, mdr.offset5, mdr.length5, mdr.unknown51); log(1, "o6: %d %d %d %d\n", mdr.offset6, mdr.length6, mdr.unknown61, mdr.unknown62); // ok sz gar_log_recs(g, off, mdr.offset6, mdr.length6, mdr.unknown61); log(1, "o7: %d %d %d %d\n", mdr.offset7, mdr.length7, mdr.unknown71, mdr.unknown72); // size ok = 7 streets: 1b map 3b roadptr ?? ?? ?? // gar_log_recs(g, off, mdr.offset7, mdr.length7, mdr.unknown71); log(1, "o8: %d %d %d %d\n", mdr.offset8, mdr.length8, mdr.unknown81, mdr.unknown82); gar_log_recs(g, off, mdr.offset8, mdr.length8, mdr.unknown81); log(1, "o9: %d %d %d %d\n", mdr.offset9, mdr.length9, mdr.unknown91, mdr.unknown92); // ok sz 4 gar_log_recs(g, off, mdr.offset9, mdr.length9, mdr.unknown91); log(1, "o10: %d %d %d %d\n", mdr.offset10, mdr.length10, mdr.unknown101,mdr.unknown101); gar_log_cstrings(g, off, mdr.offset10, mdr.length10); log(1, "o11: %d %d %d %d\n", mdr.offset11, mdr.length11, mdr.unknown111, mdr.unknown112); // size = 9 ?? // gar_log_recs(g, off, mdr.offset11, mdr.length11, mdr.unknown111); log(1, "o12: %d %d %d %d\n", mdr.offset12, mdr.length12, mdr.unknown121, mdr.unknown122); // size = 9 ?? // gar_log_recs(g, off, mdr.offset12, mdr.length12, mdr.unknown121); log(1, "o13: %d %d %d %d\n", mdr.offset13, mdr.length13, mdr.unknown131, mdr.unknown132); log(1, "o14: %d %d %d %d\n", mdr.offset14, mdr.length14, mdr.unknown141, mdr.unknown142); // size ok = 6/8 ??? 1/2b map idx // gar_log_recs(g, off, mdr.offset14, mdr.length14, mdr.unknown141); log(1, "o15: %d %d %d\n", mdr.offset15, mdr.length15, mdr.unknown151/*, mdr.unknown162*/); gar_log_cstrings(g, off, mdr.offset15, mdr.length15); // log(1, "o17: %x %x\n", mdr.offset17, mdr.length17); log(1, "o16: %d %d %d %d\n", mdr.offset16, mdr.length16, mdr.unknown161 /*, mdr.unknown162*/); log(1, "o17: %d %d %d \n", mdr.offset17, mdr.length17, mdr.unknown171/*, mdr.unknown172*/); // strings : gar_log_o17(g, off, mdr.offset17, mdr.length17); // gar_log_cstrings(g, off, mdr.offset17, mdr.length17); log(1, "o20: %d %d %d %d\n", mdr.offset20, mdr.length20, mdr.unknown201, mdr.unknown202); log(1, "o21: %d %d %d %d\n", mdr.offset21, mdr.length21, mdr.unknown211, mdr.unknown212); log(1, "o22: %d %d %d %d\n", mdr.offset22, mdr.length22, mdr.unknown221, mdr.unknown222); log(1, "o23: %d %d %d %d\n", mdr.offset23, mdr.length23, mdr.unknown231, mdr.unknown232); log(1, "o24: %d %d %d %d\n", mdr.offset24, mdr.length24, mdr.unknown241, mdr.unknown242); log(1, "o25: %d %d %d %d\n", mdr.offset25, mdr.length25, mdr.unknown251, mdr.unknown252); log(1, "o26: %d %d %d %d\n", mdr.offset26, mdr.length26, mdr.unknown261, mdr.unknown262); log(1, "o27: %d %d %d %d\n", mdr.offset27, mdr.length27, mdr.unknown271, mdr.unknown272); log(1, "o28: %d %d %d %d\n", mdr.offset28, mdr.length28, mdr.unknown281, mdr.unknown282); log(1, "o29: %d %d %d\n", mdr.offset29, mdr.length29, mdr.unknown291); log(1, "o30: %d %d %d %d\n", mdr.offset30, mdr.length30, mdr.unknown301, mdr.unknown302); log(1, "o31: %d %d %d %d\n", mdr.offset31, mdr.length31, mdr.unknown311, mdr.unknown312); log(1, "o32: %d %d\n", mdr.offset32, mdr.length32); log(1, "o33: %d %d\n", mdr.offset33, mdr.length33/*, mdr.unknown331, mdr.unknown332*/); // log(1, "o34: %d %d\n", mdr.offset34, mdr.length34); log(1, "o35: %d %d\n", mdr.offset35, mdr.length35); log(1, "o36: %d %d\n", mdr.offset36, mdr.length36); log(1, "o37: %d %d\n", mdr.offset37, mdr.length37); log(1, "o38: %d %d\n", mdr.offset38, mdr.length38); log(1, "o39: %d %d\n", mdr.offset39, mdr.length39); log(1, "o40: %d %d\n", mdr.offset40, mdr.length40); log(1, "o41: %d %d\n", mdr.offset41, mdr.length41); // log(1, "o42: %d %d\n", mdr.offset42, mdr.length42); // log(1, "o43: %d %d\n", mdr.offset43, mdr.length43); } static int debug = 10; static void logfn(char *file, int line, int level, char *fmt, ...) { va_list ap; if (level > debug) return; va_start(ap, fmt); fprintf(stdout, "%s:%d:%d|", file, line, level); vfprintf(stdout, fmt, ap); va_end(ap); } static struct gar * load(char *file) { struct gar *g; struct gar_config cfg; cfg.opm = OPM_PARSE; // FIXME: make cmdline arg cfg.debugmask = 0; // DBGM_LBLS | DBGM_OBJSRC; cfg.debuglevel = debug; g = gar_init_cfg(NULL, logfn, &cfg); if (!g) return NULL; if (gar_img_load(g, file, 1) > 0) return g; else { gar_free(g); return NULL; } } static int usage(char *pn) { fprintf(stderr, "%s [-d level] garmin.img\n", pn); return -1; } int main(int argc, char **argv) { struct gar *gar; struct gar_subfile *sub; struct gimg *g; char **files; int fcnt; int i; if (argc < 2) { return usage(argv[0]); } gar = load(argv[1]); if (!gar) return -1; g = gar_get_dskimg(gar, NULL); files = gar_file_get_subfiles(g, &fcnt, "MDR"); if (files) { for (i=0; i < fcnt; i++) { gar_read_mdr(g, files[i]); } } } #endif libgarmin-0~svn320/src/garmin_mdr.h000066400000000000000000000002761112544465000174170ustar00rootroot00000000000000struct gar_mdr { unsigned int mdroff; u_int32_t idxfiles_offset; u_int32_t idxfiles_len; }; int gar_init_mdr(struct gimg *g); int gar_mdr_get_files(struct gmap *files, struct gimg *g); libgarmin-0~svn320/src/garmin_mps.c000066400000000000000000000060231112544465000174230ustar00rootroot00000000000000#include #include #include #include #include #include #define __USE_GNU #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "GarminTypedef.h" #include "garmin_tdb.h" #define MPS_PRODUCT 0x46 #define MPS_BASEMAP 0x4c #define MPS_UNLOCK 0x55 #define MPS_DETAILMAP 0x56 #ifdef STANDALONE #undef log #define log(x, y...) fprintf(stderr, ## y) int gar_img_load_dskimg(struct gar *gar, char *a, int bm, int data, double north, double east, double south, double west) { } #endif #define GAR4DEG(x) ((double)(x)* 360.0 / (1<<31)) /* * XXX: Use TDB for lookups */ static int gar_mps_load_img(struct gar *gar, char *file, int basemap, int data, double north, double east, double south, double west) { char path[4096]; int rc; if (!gar) return 0; if (!gar->tdbdir) { log(1, "Trying to load [%s] but not TDB header seen yet\n", file); return -1; } sprintf(path, "%s/%s.img", gar->tdbdir, file); rc = gar_img_load_dskimg(gar, path, basemap, data, DEGGAR(north), DEGGAR(east), DEGGAR(south), DEGGAR(west)); if (rc < 0) log(1, "Failed to load [%s]\n", path); return rc; } int gar_parse_mps(struct gar *gar, char *file, int data) { int fd, rc; u_int16_t s,t; char *buf, *cp, *tp; unsigned char *uc; struct tdb_block block; int version = 0; int c; int havebase = -1; int td4bm = 0; float north, south, east, west; char imgname[128]; fd = open(file, OPENFLAGS); if (fd <0) { log(1, "Can not open:[%s] errno=%d(%s)\n", file, errno, strerror(errno)); return -1; } while (read(fd, &block, sizeof(struct tdb_block)) == sizeof(struct tdb_block)) { log(11,"Block type: %02X size=%d\n", block.id, block.size); buf = malloc(block.size); if (!buf) { break; } rc = read(fd, buf, block.size); if (rc != block.size) break; cp = buf; switch (block.id) { case MPS_PRODUCT: log(11, "ProductID: %d/%x\n", *(u_int32_t *)cp, *(u_int32_t *)cp); cp+=4; log(11, "Name: %s\n", cp); cp+=strlen(cp) + 1; break; case MPS_BASEMAP: log(11, "ProductID: %d\n", *(u_int32_t *)cp); cp+=4; // if == 0 it's a base map log(11, "MapID: %d\n", *(u_int32_t *)cp); cp+=4; log(11, "Name: %s\n", cp); cp += strlen(cp) + 1; log(11, "Area: %s\n", cp); cp += strlen(cp) + 1; log(11, "Product: %s\n", cp); cp += strlen(cp) + 1; log(11, "MapID: %d/%x\n", *(u_int32_t *)cp,*(u_int32_t *)cp); cp+=4; log(11, "ParentMapID?: %d/%x\n", *(u_int32_t *)cp,*(u_int32_t *)cp); cp+=4; break; case MPS_UNLOCK: // don't care log(11, "Unlock section\n"); break; case MPS_DETAILMAP: log(11, "Map: %s\n", cp); cp+=strlen(cp)+1; log(11, "??: %x\n", *cp); cp++; break; default: log(1, "Unknown MPS block ID:0x%02X\n", block.id); } log(11,"size=%d read=%d\n", block.size, cp-buf); free(buf); } close(fd); return havebase; } #ifdef STANDALONE int main(int argc, char **argv) { return gar_parse_mps(NULL,argv[1],0); } #endif libgarmin-0~svn320/src/garmin_net.c000066400000000000000000000457121112544465000174220ustar00rootroot00000000000000/* Copyright (C) 2007,2008 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "GarminTypedef.h" #include "garmin_fat.h" #include "garmin_rgn.h" #include "garmin_net.h" #include "garmin_nod.h" #include "garmin_lbl.h" struct street_addr_info { u_int8_t flags; u_int8_t *field1; u_int8_t *field2; u_int8_t *field3; }; /* * There is no bitstream at the end of this as the PDF says in the maps i have */ int gar_init_net(struct gar_subfile *sub) { struct gimg *gimg = sub->gimg; off_t off; struct gar_net_info *ni; struct hdr_net_t net; int rc; off = gar_subfile_offset(sub, "NET"); if (!off) { log(11,"No NET file\n"); return 0; } log(11, "NET initializing ...\n"); if (glseek(gimg, off, SEEK_SET) != off) { log(1, "NET: Error can not seek to %ld\n", off); return -1; } rc = gread(gimg, &net, sizeof(struct hdr_net_t)); if (rc != sizeof(struct hdr_net_t)) { log(1, "NET: Can not read header\n"); return -1; } if (strncmp("GARMIN NET", net.hsub.type,10)) { log(1, "NET: Invalid header type: [%s]\n", net.hsub.type); return -1; } ni = malloc(sizeof(*ni)); if (!ni) return -1; ni->netoff = gar_subfile_baseoffset(sub, "NET");//off; ni->net1_offset = net.net1_offset; ni->net1_length = net.net1_length; ni->net1_addr_shift = net.net1_addr_shift; ni->net2_offset = net.net2_offset; ni->net2_length = net.net2_length; ni->net2_addr_shift = net.net2_addr_shift; ni->net3_offset = net.net3_offset; ni->net3_length = net.net3_length; ni->nod = gar_init_nod(sub);; sub->net = ni; log(11, "off net1=%d, net2=%d, net3=%d\n", ni->net1_offset, ni->net2_offset, ni->net3_offset); log(11, "len net1=%d, net2=%d, net3=%d\n", ni->net1_length, ni->net2_length, ni->net3_length); for (rc=0; rc < ROADS_HASH_TAB_SIZE; rc++) list_init(&ni->lroads[rc]); return 1; } off_t gar_net_get_lbl_offset(struct gar_subfile *sub, off_t offset, int idx) { struct gimg *gimg = sub->gimg; off_t o; char buf[12]; char *cp; int rc; u_int32_t i; if (!sub->net || idx > 3) return 0; o = sub->net->netoff + sub->net->net1_offset + (offset << sub->net->net1_addr_shift); if (glseek(gimg, o, SEEK_SET) != o) { log(1, "NET: Error can not seek to %ld\n", o); return 0; } rc = gread(gimg, buf, sizeof(buf)); if (rc > 3) { cp = buf; i = *(u_int32_t*)cp; if (i&0x400000) { cp+=6; i = *(u_int32_t*)cp; } i &= 0x3FFFFF; return i; } else return 0; } static void gar_free_addr_info(struct street_addr_info *sai) { if (sai->field1) free(sai->field1); if (sai->field2) free(sai->field2); if (sai->field3) free(sai->field3); free(sai); } static void gar_log_sai(struct gar_subfile *sub, struct street_addr_info *sai) { unsigned short i; u_int8_t fl = sai->flags; fl >>=2; if ((fl&3)!=3 && sai->field1) { if ((fl&3)==0) log(11, "Number: size=%d\n", *sai->field1); else { if (sub->lbl_zips < 256) i = *(unsigned char*)sai->field1; else i = *(unsigned short*)sai->field1; if (i < sub->czips && i > 0) log(11, "ZIP: %d[%s]\n", i, sub->zips[i]->code); else log(11, "ZIP: %d[%s]\n", i, sub->czips ? "invalid" : "notloaded"); } } fl >>= 2; if ((fl&3)!=3 && sai->field2) { if ((fl&3)==0) log(11, "Number: size=%d\n", *sai->field2); else { if (sub->lbl_cities < 256) i = *(unsigned char*)sai->field2; else i = *(unsigned short*)sai->field2; if (i < sub->cicount && i > 0) log(11, "City: %d[%s]\n", i, sub->cities[i]->label); else log(11, "City: %d[%s]\n", i, sub->cicount ? "invalid" : "notloaded"); } } fl >>= 2; if ((fl&3)!=3 && sai->field3) { if ((fl&3)==0) log(11, "Number: size=%d\n", *sai->field3); else { if (sub->lbl_regions < 256) i = *(unsigned char*)sai->field3; else i = *(unsigned short*)sai->field3; if (i < sub->rcount && i > 0) log(11, "Region: %d[%s]\n", i, sub->regions[i]->name); else log(1, "Region: %d[%s]\n", i, sub->rcount ? "invalid" : "notloaded"); } } } void gar_sai2searchres(struct street_addr_info *sai, struct gar_search_res *res) { u_int8_t fl = sai->flags; fl >>=2; if ((fl&3)!=3 && sai->field1) { if ((fl&3)==0) { // log(11, "Number: size=%d\n", *sai->field1); } else { res->zipid = *(unsigned short*)sai->field1; } } fl >>= 2; if ((fl&3)!=3 && sai->field2) { if ((fl&3)==0) { log(11, "Number: size=%d\n", *sai->field2); } else { res->cityid = *(unsigned short*)sai->field2; } } fl >>= 2; if ((fl&3)!=3 && sai->field3) { if ((fl&3)==0) { log(11, "Number: size=%d\n", *sai->field3); } else res->regionid = *(unsigned short*)sai->field3; } } int gar_match_sai(struct street_addr_info *sai, unsigned int zipid, unsigned int rid, unsigned int cityid, unsigned int num) { int rc = 0; int i; u_int8_t fl = sai->flags; fl >>=2; if (num) { // TODO } if (zipid) { if ((fl&3)!=3 && sai->field1) { if ((fl&3)==0) { // log(11, "Number: size=%d\n", *sai->field1); } else { i = *(unsigned short*)sai->field1; if (i == zipid) rc = 1; } } } fl >>=2; if (cityid) { if ((fl&3)!=3 && sai->field2) { if ((fl&3)==0) { // log(11, "Number: size=%d\n", *sai->field2); } else { i = *(unsigned short*)sai->field2; if (i == cityid) rc = 1; } } } fl >>= 2; if (rid) { if ((fl&3)!=3 && sai->field3) { if ((fl&3)==0) { log(11, "Number: size=%d\n", *sai->field3); } else if (rid == *(unsigned short*)sai->field3) rc = 1; } } return rc; } static struct street_addr_info* gar_parse_addr_info(struct gar_subfile *sub) { u_int8_t flags, size; u_int8_t fl; u_int8_t *f1 = NULL, *f2 = NULL, *f3 = NULL; struct street_addr_info *sai; struct gimg *gimg = sub->gimg; if (gread(gimg, &flags, sizeof(u_int8_t)) < 0) return NULL; fl = flags >> 2; fl &= 3; if (fl != 3) { if (fl == 0) { if (gread(gimg, &size, sizeof(u_int8_t)) < 0) return NULL; f1 = malloc(size+1); if (!f1) goto out_err; if (gread(gimg, &f1[1], size) != size) goto out_err; f1[0] = size; } else if (fl == 2) { if (sub->lbl_zips < 256) size = 1; else size = 2; f1 = calloc(1,2); if (!f1) goto out_err; if (gread(gimg, f1, size) != size) goto out_err; } else { // unsigned char buf[3]; log(1, "NET: Error f1 type=1\n"); // gread(gimg, buf, 3); // log(1, "Data: [%02X][%02X]\n", // buf[0], buf[1]); } } fl = flags >> 4; fl &= 3; if (fl != 3) { if (fl == 0) { if (gread(gimg, &size, sizeof(u_int8_t)) < 0) return NULL; f2 = malloc(size+1); if (!f2) goto out_err; if (gread(gimg, &f2[1], size) != size) goto out_err; f2[0] = size; } else if (fl == 2) { if (sub->lbl_cities < 256) size = 1; else size = 2; f2 = calloc(1,2); if (!f2) goto out_err; if (gread(gimg, f2, size) != size) goto out_err; } else if (fl == 1) { log(1, "NET: Error f2 type=1\n"); /* Not in the PDF, the guess is that its idx/sdidx */ // f2 = malloc(3); // gread(gimg, f2, 3); } } fl = flags >> 6; fl &= 3; if (fl != 3) { if (fl == 0) { if (gread(gimg, &size, sizeof(u_int8_t)) < 0) return NULL; f3 = malloc(size+1); if (!f3) goto out_err; if (gread(gimg, &f3[1], size) != size) goto out_err; f3[0] = size; } else if (fl == 2) { if (sub->lbl_regions < 256) size = 1; else size = 2; f3 = calloc(1,2); if (!f3) goto out_err; if (gread(gimg, f3, size) != size) goto out_err; } else { // unsigned char buf[3]; log(1, "NET: Error f3 type=%d\n", fl); // gread(gimg, buf, 3); // log(1, "Data: [%02X][%02X][%02X]\n", // buf[0], buf[1], buf[2]); } } sai = malloc(sizeof(*sai)); if (!sai) goto out_err; sai->flags = flags; sai->field1 = f1; sai->field2 = f2; sai->field3 = f3; return sai; out_err: if (f1) free(f1); if (f2) free(f2); if (f3) free(f3); return NULL; } void gar_log_road_info(struct gar_road *ri) { int i,j; int idx; int sdidx; char buf[2048]; int sz; struct gobject *o; struct gpoly *gp; struct gar_subfile *sub = ri->sub; log(11, "Labels at %ld %ld %ld %ld\n", ri->labels[0],ri->labels[1],ri->labels[2],ri->labels[3]); if (ri->labels[0]) { gar_get_lbl(sub, ri->labels[0], L_LBL, (unsigned char*)buf, 1024); log(1, "L[0]=%s\n", buf); } if (ri->labels[1]) { gar_get_lbl(sub, ri->labels[1], L_LBL, (unsigned char*)buf, 1024); log(1, "L[1]=%s\n", buf); } if (ri->labels[2]) { gar_get_lbl(sub, ri->labels[2], L_LBL, (unsigned char*)buf, 1024); log(1, "L[2]=%s\n", buf); } if (ri->labels[3]) { gar_get_lbl(sub, ri->labels[3], L_LBL, (unsigned char*)buf, 1024); log(1, "L[3]=%s\n", buf); } if (ri->sr_cnt) { if (!sub->net->net2_length) log(1, "Error have segmented offsets but segments section is empty\n"); log(1, "Segmented roads offsets:\n"); for (i=0; i < ri->sr_cnt; i++) log(11, "Seg at:%d\n", ri->sr_offset[i]); } log(1, "road_flags=%d road_len=%d hnb=%d " "unk0:%d, oneway:%d, lock:%d, unk3:%d, ar:%d, mhw:%d\n", ri->road_flags, ri->road_len, ri->hnb, !!(ri->road_flags&RFL_UNKNOWN0), !!(ri->road_flags&RFL_ONEWAY), !!(ri->road_flags&RFL_LOCKTOROAD), !!(ri->road_flags&RFL_UNKNOWN3), !!(ri->road_flags&RFL_ADDRONRIGHT), !!(ri->road_flags&RFL_MAJORHW)); sz = 0; for (i=0; i < ri->rio_cnt; i++) { sz += sprintf(buf + sz, "%d %d ", i, ri->rio[i]); } log(1, "segments per level: %s\n", buf); sz = 0; for (i=0; i < ri->ri_cnt; i++) { idx = ri->ri[i] & 0xff; sdidx = ri->ri[i] >> 8; sdidx &= 0xFFFF; // 8 bits idx, 16 bits subdiv sz += snprintf(buf + sz, sizeof(buf) - sz, "%d i:%d sd:%d ", i, idx, sdidx); /* this is the road on the differnet map levels */ o = gar_get_subfile_object_byidx(sub, sdidx, idx, GO_POLYLINE); if (o) { if (1||i==0) { char *cp = gar_object_debug_str(o); if (cp) { log(1, "%s\n", cp); free(cp); } } { gp = o->gptr; struct gcoord dc; int ebset =0; dc = gp->c; if (gp->nodemap) { ebset = bm_is_set(gp->nodemap, 0); } log(1, "%f/%f (%x/%x) e=%d\n", GARDEG(dc.x), GARDEG(dc.y),dc.x, dc.y, ebset); for (j = 0; j < gp->npoints; j++) { if (gp->nodemap) { ebset = bm_is_set(gp->nodemap, j+1); } dc.x += gp->deltas[j].x; dc.y += gp->deltas[j].y; log(1, "%f/%f (%x/%x) e=%d\n", GARDEG(dc.x), GARDEG(dc.y),dc.x, dc.y, ebset); } } #if 0 cp = gar_get_object_lbl(o); if (cp) { log(1, "LBL=%s\n", cp); free(cp); } #endif gar_free_objects(o); } else { log(1, "NET: Error can not find object\n"); } } log(1, "segments:%s\n", buf); if (ri->sai) { log(1, "Have street address info:%x\n", ri->sai->flags); gar_log_sai(sub, ri->sai); } if (ri->road_flags & RFL_NODINFO) { log(1, "NOD info at %d\n",ri->nod_offset); if (ri->nod) { int i, l = (ri->nod->bmlen+7)/8; log(1, "NOD1 at %d bmlen=%d fb=%d\n", ri->nod->nodesoff, ri->nod->bmlen, ri->nod->bitmap[0]&1); for (i = 0; i < l; i++) { log(11, "BITMAP: %x\n", ri->nod->bitmap[i]); } } { struct gar_graph *graph; struct node *node; struct roadptr *rp; int rpoff; graph = gar_alloc_graph(sub); node = gar_get_node(graph, ri->nod->nodesoff); if (!gar_read_node(graph, NULL, node)) log(1, "Failed to read node:%d\n",ri->nod->nodesoff); log(1, "NODE at %f/%f\n", GARDEG(node->c.x),GARDEG(node->c.y)); for (j=0; j < node->narcs; j++) { rp = gar_cp_idx2road(node->cpoint, node->arcs[j].roadidx); if (!rp) { log(1, "No roadptr ERROR\n"); } else { rpoff = get_u24(rp->off); log(1, "Road (%x) cl=%d %sat %d b1=%x b2=%x dest %d\n", node->arcs[j].roadidx, node->arcs[j].roadclass, node->arcs[j].islink ? "link ": "", rpoff, rp->b1, rp->b2, node->arcs[j].dest->offset); if (rpoff == ri->offset) { log(1, "Own road\n"); } } } gar_free_graph(graph); } // gar_read_nod2(sub, ri->nod_offset); // log(11, "nod data at %u\n", ri->nod_offset); } } void gar_free_road(struct gar_road *ri) { if (ri->sr_offset) free(ri->sr_offset); if (ri->rio) free(ri->rio); if (ri->ri) free(ri->ri); if (ri->sai) gar_free_addr_info(ri->sai); if (ri->nod) gar_free_road_nod(ri->nod); free(ri); } static void gar_add_road(struct gar_net_info *net, struct gar_road *road) { unsigned hash = ROAD_HASH(road->offset); list_append(&road->l, &net->lroads[hash]); } struct gar_road *gar_get_road(struct gar_subfile *sub, off_t offset) { struct gar_road *r; unsigned hash = ROAD_HASH(offset); list_for_entry(r, &sub->net->lroads[hash], l) if (r->offset == offset) return r; return NULL; } void gar_load_roads(struct gar_subfile *sub); struct gar_road *gar_get_road_by_id(struct gar_subfile *sub, int sidx, int idx) { struct gar_road *ri; int i,j; int ridx, rsdidx; gar_load_roads(sub); for (i=0; i < ROADS_HASH_TAB_SIZE; i++) { list_for_entry(ri, &sub->net->lroads[i], l) { for (j=0; j < ri->ri_cnt; j++) { ridx = ri->ri[j] & 0xff; rsdidx = ri->ri[j] >> 8; rsdidx &= 0xFFFF; if (rsdidx == sidx && ridx == idx) { return ri; } } } } return NULL; } static void gar_free_roads(struct gar_net_info *net) { struct gar_road *r, *rs; int i; for (i=0; i < ROADS_HASH_TAB_SIZE; i++) { list_for_entry_safe(r, rs, &net->lroads[i], l) { list_remove(&r->l); gar_free_road(r); } } } static struct gar_road *gar_parse_road(struct gar_subfile *sub, off_t offset) { struct gar_road *rd; struct gimg *gimg = sub->gimg; off_t o,o1; int lblidx = 0; off_t labels[4]; char buf[4]; u_int32_t segs[101]; int segidx = 0; int rc; u_int32_t i,j; char seg = 0; u_int8_t flags; u_int32_t road_len; u_int8_t rio[25]; unsigned ri_cnt = 0; unsigned rio_cnt = 0; u_int32_t *ri; u_int8_t tmp; u_int8_t hnb = 0; struct street_addr_info *sai = NULL; u_int32_t nodptr = 0; o = sub->net->netoff + sub->net->net1_offset + (offset << sub->net->net1_addr_shift); if (glseek(gimg, o, SEEK_SET) != o) { log(1, "NET: Error can not seek to %ld\n", o); return NULL; } while (42) { buf[0] = buf[1] = buf[2] = buf[3] = 0; rc = gread(gimg, buf, 3); if (rc != 3) return NULL; i = *(u_int32_t*)buf; if (seg) { if (segidx < 100) segs[segidx++] = i & 0x7FFFFF; else { log(1, "NET: Error to many segments!\n"); return NULL; } } else { if (i&(1<<22)) { seg = 1; } if (i & 0x3FFFFF) { labels[lblidx++] = i & 0x3FFFFF; if (lblidx == 4) { log(1, "NET: Error to many labels!\n"); return NULL; } } } if (i&(1<<23)) break; } rc = gread(gimg, &flags, sizeof(u_int8_t)); if (rc!=1) return NULL; rc = gread(gimg, buf, 3); if (rc != 3) return NULL; road_len = *(u_int32_t*)buf; while (42) { if (gread(gimg, &tmp, 1) < 0) return NULL; rio[rio_cnt] = tmp & 0x3f; ri_cnt += rio[rio_cnt]; rio_cnt++; if (tmp & (1<<7)) break; if (rio_cnt == 25) { log(1, "NET: Too many rios\n"); break; } } ri = malloc(ri_cnt * sizeof(u_int32_t)); if (!ri) return NULL; for (j=0; j < ri_cnt; j++) { rc = gread(gimg, buf, 3); if (rc != 3) return NULL; i = *(u_int32_t*)buf; ri[j] = i; } if (flags & RFL_STREETADDRINFO) { if (gread(gimg, &hnb, sizeof(u_int8_t)) < 0) return NULL; sai = gar_parse_addr_info(sub); if (!sai) return NULL; } if (flags & RFL_NODINFO) { if (gread(gimg, &tmp, sizeof(u_int8_t)) < 0) return NULL; if (tmp > 2) log(11, "NET: FIXME nod info:%d\n", tmp); if ((tmp & 3) == 1) { tmp = 2; } else if ((tmp & 3) == 2) { tmp = 3; } else if ((tmp & 3) == 3) { tmp = 1; } else { log(1, "NET: Unknow nod info:%d\n", tmp); tmp = 0; } if (tmp) { buf[0] = buf[1] = buf[2] = buf[3] = 0; if (gread(gimg, buf, tmp) < 0) return NULL; if (tmp == 3) nodptr = *(u_int32_t*)buf & 0xffffff; else if (tmp == 2) nodptr = *(u_int16_t*)buf & 0xffff; else if (tmp == 1) nodptr = *(u_int8_t*)buf & 0xff; } } rd = calloc(1,sizeof(*rd)); if (!rd) return NULL; rd->offset = offset; if (lblidx > 4) { for (i=0; i < lblidx; i++) log(11, "LBL:%d %ld\n", i, labels[i]); } for (i=0; i < lblidx; i++) rd->labels[i] = labels[i]; if (segidx) { rd->sr_cnt = segidx; rd->sr_offset = malloc(segidx * sizeof(rd->sr_offset)); if (!rd->sr_offset) { free(rd); return NULL; } for (i=0; i < segidx; i++) rd->sr_offset[i] = segs[i]; } rd->road_flags = flags; rd->road_len = road_len * 10; // from mkgmap rd->rio_cnt = rio_cnt; rd->rio = malloc(rio_cnt * sizeof(u_int8_t)); rd->ri_cnt = ri_cnt; rd->ri = ri; if (!rd->ri || !rd->rio) { free(rd->sr_offset); free(rd->ri); free(rd->rio); free(rd); return NULL; } for (i=0; i < rio_cnt; i++) { rd->rio[i] = rio[i]; } for (i=0; i < ri_cnt; i++) { rd->ri[i] = ri[i]; } rd->hnb = hnb; rd->sai = sai; rd->nod_offset = nodptr; if (gar_debug_level > 10) { o1 = glseek(gimg, 0, SEEK_CUR); log(11, "read %ld roadptr %ld\n", o1-o, offset); } rd->sub = sub; if (flags & RFL_NODINFO) rd->nod = gar_read_nod2(sub,rd->nod_offset); return rd; } int gar_load_roadnetwork(struct gar_subfile *sub) { unsigned char buf[4]; int i, rc; unsigned int val; int lblidx, c = 0, p = 0; unsigned int roadptr; struct gar_road *ri; off_t o; if (!sub->net->net3_offset) { log(1, "NET: No sorted roads defined\n"); return 0; } gar_subfile_ref(sub); o = sub->net->netoff + sub->net->net3_offset; if (glseek(sub->gimg, o, SEEK_SET) != o) { log(1, "NET: Error can not seek to %ld\n", o); return 0; } for (i=0; i < sub->net->net3_length/3; i++) { glseek(sub->gimg, o, SEEK_SET); rc = gread(sub->gimg, buf, 3); if (rc < 0) break; o = glseek(sub->gimg, 0, SEEK_CUR); val = *(unsigned int *)buf; lblidx = val >> 21; lblidx &= 3; roadptr = val & 0x003FFFFF; log(11, "lblidx %d roadptr %d\n", lblidx, roadptr); ri = gar_parse_road(sub, roadptr); if (ri) { if (gar_debug_level > 10) gar_log_road_info(ri); gar_add_road(sub->net, ri); p++; } else { log(1, "NET: Error parsing road info\n"); } c++; } log(11, "Total %d roads, %d parsed\n", c, p); sub->net->roads_loaded = 1; gar_subfile_unref(sub); return c; } void gar_load_roads(struct gar_subfile *sub) { if (!sub->net) return; if (sub->net->roads_loaded) return; gar_load_roadnetwork(sub); } void gar_free_net(struct gar_subfile *sub) { if (!sub->net) return; if (sub->net->nod) gar_free_nod(sub->net->nod); gar_free_roads(sub->net); free(sub->net); sub->net = NULL; } libgarmin-0~svn320/src/garmin_net.h000066400000000000000000000034441112544465000174230ustar00rootroot00000000000000#define RFL_UNKNOWN0 (1<<0) #define RFL_ONEWAY (1<<1) #define RFL_LOCKTOROAD (1<<2) #define RFL_UNKNOWN3 (1<<3) #define RFL_STREETADDRINFO (1<<4) #define RFL_ADDRONRIGHT (1<<5) #define RFL_NODINFO (1<<6) /* This or some of the unknow flags is high congestion probability */ #define RFL_MAJORHW (1<<7) #define ROADS_HASH_TAB_SIZE 128 /* must be power of 2 */ #define ROAD_HASH(offset) (((offset) * 40503)& (ROADS_HASH_TAB_SIZE-1)) struct gar_net_info { off_t netoff; u_int32_t net1_offset; u_int32_t net1_length; u_int8_t net1_addr_shift; u_int32_t net2_offset; u_int32_t net2_length; u_int16_t net2_addr_shift; u_int32_t net3_offset; u_int32_t net3_length; struct gar_nod_info *nod; int roads_loaded; list_t lroads[ROADS_HASH_TAB_SIZE]; }; struct gar_subfile; struct gar_road { list_t l; struct gar_subfile *sub; off_t offset; u_int32_t nod_offset; off_t labels[4]; int sr_cnt; u_int32_t *sr_offset; u_int8_t road_flags; u_int8_t road_len; int rio_cnt; u_int8_t *rio; int ri_cnt; u_int32_t *ri; u_int8_t hnb; struct street_addr_info *sai; struct gar_road_nod *nod; }; int gar_init_net(struct gar_subfile *sub); void gar_free_net(struct gar_subfile *sub); off_t gar_net_get_lbl_offset(struct gar_subfile *sub, off_t offset, int idx); // int gar_net_parse_sorted(struct gar_subfile *sub); int gar_load_roadnetwork(struct gar_subfile *sub); struct gar_road *gar_get_road(struct gar_subfile *sub, off_t offset); void gar_free_road(struct gar_road *ri); int gar_match_sai(struct street_addr_info *sai, unsigned int zipid, unsigned int rid, unsigned int cid, unsigned int num); void gar_sai2searchres(struct street_addr_info *sai, struct gar_search_res *res); struct gar_road *gar_get_road_by_id(struct gar_subfile *sub, int sidx, int idx); void gar_log_road_info(struct gar_road *ri); libgarmin-0~svn320/src/garmin_nod.c000066400000000000000000000474051112544465000174150ustar00rootroot00000000000000/* Copyright (C) 2008 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "GarminTypedef.h" #include "garmin_fat.h" #include "garmin_rgn.h" #include "garmin_net.h" #include "garmin_nod.h" /* Node flags */ #define NF_ARCS 0x40 // have arcs and links #define NF_16BITDELTAS 0x20 // 16 bit coordinate deltas #define NF_RESTRICTIONS 0x10 // have restrictions #define NF_BOUND 0x08 // bound/exit node /* Last 3 bits - coding? */ #define NF_C1 0x04 #define NF_C2 0x02 #define NF_C3 0x01 /* Arcs/Links flags */ #define LF_END 0x8000 #define LF_IDXPTR 0x4000 #define LF_NEWROAD 0x0080 #define LF_FLAG 0x0040 #define LF_CURVE 0x0020 #define LF_RC_MASK 0x0007 // road class struct nod_roadptr { u_int24_t off; u_int8_t b1; u_int8_t b2; } __attribute((packed)); /* central point */ struct central_point { u_int8_t crestr; u_int24_t lng; u_int24_t lat; u_int8_t croads; u_int8_t cidxs; } __attribute((packed)); static void gar_put_cpoint(struct cpoint *p); #define DEBUGNODES // #define DEBUG #ifdef DEBUG static void print_buf(char *pref, unsigned char *a, int s) { char buf[4096]; int i,sz = 0; for (i=0; i < s; i++) { sz += sprintf(buf+sz, "%02X ",a[i]); } log(11, "%s :%s\n", pref, buf); } #else static void print_buf(char *pref, unsigned char *a, int s) {} #endif #ifdef DEBUGNODES static void nodelogseq(struct node *node) { FILE *fp; char buf[512]; sprintf(buf, "nodes/path.txt"); if (node->nodeid == 0) fp = fopen(buf, "w+"); else fp = fopen(buf, "a+"); if (!fp) return; fprintf(fp, "%d\n", node->offset); fclose(fp); } static void nodetrunklog(struct node *node) { FILE *fp; char buf[512]; sprintf(buf, "nodes/%d-%d.txt", node->offset,node->nodeid); fp = fopen(buf, "w"); if (!fp) return; fclose(fp); } static void nodelogsource(struct node *node, unsigned char *cp, int l) { FILE *fp; char buf[512]; int i; int m = l < 40 ? l : 40; nodelogseq(node); sprintf(buf, "nodes/%d-%d.txt", node->offset,node->nodeid); fp = fopen(buf, "a+"); if (!fp) return; for (i = 0; i < m; i++) { fprintf(fp, "%02X ", *cp++); } fprintf(fp, "\n"); fclose(fp); } static void nodelog(struct node *node, char *fmt, ...) { FILE *fp; char buf[512]; va_list ap; sprintf(buf, "nodes/%d-%d.txt", node->offset, node->nodeid); fp = fopen(buf, "a+"); if (!fp) return; va_start(ap, fmt); vfprintf(fp, fmt, ap); va_end(ap); fclose(fp); } #define LN(y...) nodelog(node, ## y) #define LB(x, y) log(11, "NOD data %s:%x\n", y, x) #else static void nodelogsource(struct node *node, unsigned char *cp, int l) {} static void nodetrunklog(struct node *node) {} #define LN(y...) do {} while(0) #define LB(x, y) do {} while(0) #endif static struct grapharc* gar_alloc_grapharc(struct node *dst, unsigned char ridx, unsigned char rc) { struct grapharc *arc; arc = calloc(1, sizeof(*arc)); if (!arc) return NULL; arc->dest = dst; arc->roadidx = ridx; arc->roadclass = rc; arc->islink = 1; return arc; } static void gar_update_grapharc(struct grapharc *arc, unsigned link, unsigned len, unsigned heading, char curve, char headout) { arc->len = len; arc->heading = heading; arc->curve = curve; arc->headout = headout; arc->islink = link; } static void gar_free_grapharc(struct grapharc *arc) { free(arc); } static struct node * gar_alloc_node(u_int32_t offset) { struct node *n; n = calloc(1, sizeof(*n)); if (!n) return NULL; list_init(&n->l); list_init(&n->lc); n->offset = offset; n->value = ~0; nodetrunklog(n); return n; } static struct node * gar_graph_add_node(struct gar_graph *graph, struct node *node) { unsigned hash = NODE_HASH(node->offset); list_append(&node->l, &graph->lnodes[hash]); node->nodeid = graph->totalnodes; graph->totalnodes++; return node; } static struct node * gar_find_node(struct gar_graph *graph, u_int32_t offset) { struct node *n; unsigned hash = NODE_HASH(offset); list_t *list = &graph->lnodes[hash]; list_for_entry(n, list, l) { if (n->offset == offset) return n; } return NULL; } struct node* gar_get_node(struct gar_graph *graph, u_int32_t offset) { struct node *node; node = gar_find_node(graph, offset); if (node) { // log(11, "NOD Already read: %d\n", offset); return node; } node = gar_alloc_node(offset); if (node) gar_graph_add_node(graph, node); return node; } static void gar_free_node(struct node *n) { if (n->arcs) free(n->arcs); if (n->cpoint) gar_put_cpoint(n->cpoint); list_remove_init(&n->l); list_remove_init(&n->lc); free(n); } void gar_free_nod(struct gar_nod_info *nod) { free(nod); } struct gar_nod_info *gar_init_nod(struct gar_subfile *sub) { off_t off; int rc; struct gimg *gimg = sub->gimg; struct gar_nod_info *n; struct hdr_nod_t nod; off = gar_subfile_offset(sub, "NOD"); if (!off) { log(11,"No NOD file\n"); return NULL; } if (glseek(gimg, off, SEEK_SET) != off) { log(1, "NOD: Error can not seek to %ld\n", off); return NULL; } rc = gread(gimg, &nod, sizeof(struct hdr_nod_t)); if (rc != sizeof(struct hdr_nod_t)) { log(1, "NOD: Can not read header\n"); return NULL; } if (strncmp("GARMIN NOD", nod.hsub.type,10)) { log(1, "NOD: Invalid header type: [%s]\n", nod.hsub.type); return NULL; } n = malloc(sizeof(*n)); if (!n) return n; n->nodoff = gar_subfile_baseoffset(sub, "NOD");//off; n->nod1_offset = nod.nod1offset; n->nod1_length = nod.nod1length; n->cpalign = nod.cpalign; n->roadptrsize = nod.roadptrsize; n->nodbits = nod.nodbits; n->nod2_offset = nod.nod2offset; n->nod2_length = nod.nod2length; n->nod3_offset = nod.bondoffset; n->nod3_length = nod.bondlength; n->nod3_recsize = nod.bondrecsize; log(11, "nod hdrlen=%d\n", nod.hsub.length); log(11, "len nod1=%d, nod2=%d, nod3=%d\n", nod.nod1length, nod.nod2length, nod.bondlength); log(11, "off nod1=%d, nod2=%d, nod3=%d\n", nod.nod1offset, nod.nod2offset, nod.bondoffset); log(11, "hdr cpal %d b1 %0x b2 %0x 3 %0x 4 %0x, unk3=%0x, roadptrsize=%0x unk5=%0x zterm1=%x\n", nod.cpalign, nod.nodbits, nod.b2, nod.b3, nod.unknown3, nod.unknown3, nod.roadptrsize, nod.unknown5, nod.zeroterm1); if (nod.hsub.length > 63) { log(11, "nod bond2offset=%d len=%d u1off=%d len=%d u2off=%d len=%d\n", nod.bond2offset, nod.bond2lenght, nod.u1offset, nod.u1lenght, nod.u2offset, nod.u2lenght); } return n; } struct nod1_data { u_int8_t b[12]; // pointer to other nod1 data } __attribute((packed)); struct nod_node { u_int8_t b1; u_int24_t c1; u_int24_t c2; u_int8_t b2; u_int8_t b3; }; static void *gar_read_nod1node(struct gar_subfile *sub, off_t offset, unsigned char idx) { off_t off; struct nod_node n; u_int32_t lng; u_int32_t lat; off = 1 + idx + (offset >> sub->net->nod->cpalign); off <<= sub->net->nod->cpalign; if (glseek(sub->gimg, off, SEEK_SET) != off) { log(1, "NET: Error can not seek to %ld\n", off); return NULL; } if (gread(sub->gimg, &n, sizeof(n)) < 0) return NULL; lng = get_u24(&n.c1); lat = get_u24(&n.c2); log(11, "nod1 off %ld 1 %x c1 %f[%x] c2 %f[%x] 2 %x 3 %x\n", off, n.b1, GARDEG(lng), lng, GARDEG(lat), lat, n.b2, n.b3); return NULL; } static void * gar_read_nod1(struct gar_subfile *sub, off_t offset, int flag) { struct gimg *gimg = sub->gimg; struct nod1_data nd; unsigned int x,y; int ci= 2; char buf[128]; off_t o = sub->net->nod->nodoff + sub->net->nod->nod1_offset + offset; if (glseek(gimg, o, SEEK_SET) != o) { log(1, "NET: Error can not seek to %ld\n", o); return NULL; } if (gread(gimg, &nd, sizeof(nd)) < 0) return NULL; sprintf(buf, "nod1 %ld", offset); print_buf(buf, (unsigned char *)&nd, sizeof(nd)); x = *(u_int16_t *)&nd.b[ci] & 0xffff; x <<= 16; x >>= 8; x = SIGN3B(x); y = *(u_int16_t *)&nd.b[ci+2] & 0xffff; y <<= 16; y >>= 8; y = SIGN3B(y); log(11, "nod1: %ld x=%d(%f) y=%d(%f)\n", offset, x, GARDEG(x), y, GARDEG(y)); gar_read_nod1node(sub, offset+1, nd.b[0]); return NULL; } // the bitstream at the end // if nodptr // and next != 0 // bit count // bitmap which deltas from the sd:idx are covered struct nod_road_data { u_int8_t flags; u_int24_t nod1off; u_int16_t bmlen; } __attribute((packed)); void gar_free_road_nod(struct gar_road_nod *nod) { free(nod); } struct gar_road_nod *gar_read_nod2(struct gar_subfile *sub, u_int32_t offset) { struct gimg *gimg = sub->gimg; struct nod_road_data nrd; struct gar_road_nod *nr = NULL; u_int32_t n1 = -1; off_t o = sub->net->nod->nodoff + sub->net->nod->nod2_offset + offset; if (glseek(gimg, o, SEEK_SET) != o) { log(1, "NET: Error can not seek to %ld\n", o); return NULL; } if (gread(gimg, &nrd, sizeof(struct nod_road_data)) < 0) return NULL; if (HAVENODES(nrd.flags)) { int len = 0; n1 = get_u24(&nrd.nod1off); if (nrd.bmlen) len = (7+nrd.bmlen)/8; nr = calloc(1, sizeof(*nr)+len); if (!nr) return NULL; nr->nodesoff = n1; nr->flags = nrd.flags; nr->bmlen = nrd.bmlen; gread(gimg, &nr->bitmap[0], len); } else { nr = calloc(1, sizeof(*nr)); if (!nr) return NULL; nr->flags = nrd.flags; } log(11, "n2: %d sc %d rc %d havenodes:%d 7:%d nodes at %d bmlen %d bits\n", offset, SPEEDCLASS(nrd.flags), ROADTYPE(nrd.flags), HAVENODES(nrd.flags), CHARINFO(nrd.flags), n1, nrd.bmlen); return nr; } int gar_nod_parse_nod3(struct gar_subfile *sub) { int i, rc; off_t o; int x,y,p; struct nod_bond nb; if (!sub->net || !sub->net->nod) { return -1; } if (!sub->net->nod->nod3_offset || !sub->net->nod->nod3_length) { log(1, "NOD: No boundary nodes defined\n"); return 0; } log(11, "nod3recsize=%d nodbond=%d\n", sub->net->nod->nod3_recsize, sizeof(struct nod_bond)); o = sub->net->nod->nodoff + sub->net->nod->nod3_offset; if (glseek(sub->gimg, o, SEEK_SET) != o) { log(1, "NOD: Error can not seek to %ld\n", o); return 0; } log(11, "Boundary nodes %d\n", sub->net->nod->nod3_length/sub->net->nod->nod3_recsize); for (i=0; i < sub->net->nod->nod3_length/sub->net->nod->nod3_recsize; i++) { rc = gread(sub->gimg, &nb, sizeof(struct nod_bond)); if (rc != sizeof(struct nod_bond)) { log(1, "NOD: Can not read node\n"); return 0; } x = get_u24(&nb.east); x = SIGN3B(x); y = get_u24(&nb.north); y = SIGN3B(y); p = get_u24(&nb.offset); log(11, "%d %f %f %x\n", i, GARDEG(x), GARDEG(y), p); } return 0; } static void gar_enqueue_node(struct gar_graph *graph, struct node *node) { log(12, "NOD enqueue:%d %d\n", node->offset, node->complete); list_remove_init(&node->lc); list_append(&node->lc, &graph->lqueue); } #ifndef EXTRAS static int gar_do_read_node(struct gar_graph *graph, struct node *from, struct node *node) { // This will be filled soon i hope return 0; } #endif int gar_read_node(struct gar_graph *graph, struct node *from, struct node *node) { if (node->complete) return 1; return gar_do_read_node(graph, from, node); } static int gar_process_queue(struct gar_graph *graph, int pos, int class) { struct node *n; unsigned nread = 0; int reach = 0; while (!list_empty(&graph->lqueue)) { n = list_entry(graph->lqueue.n, struct node, lc); list_remove_init(&n->lc); if (n->class == class) { if (gar_read_node(graph, NULL, n) < 0) { // error log(1, "NOD Error reading node %d\n", n->offset); return -1; } if (pos) { n->posreach = 1; } else { n->dstreach = 1; } list_append(&n->lc, &graph->lnclass[class]); reach += (n->posreach&&n->dstreach); nread ++; } else if (n->class > class) { if (pos) { n->posreach = 1; list_append(&n->lc, &graph->lnposclassup[class]); } else { n->dstreach = 1; list_append(&n->lc, &graph->lndestclassup[class]); } } else if (n->class < class) { if (pos) { n->posreach = 1; list_append(&n->lc, &graph->lnposclassdown[class]); } else { n->dstreach = 1; list_append(&n->lc, &graph->lndestclassdown[class]); } } } return reach; } static int gar_load_pos_class(struct gar_graph *graph, int class) { if (graph->pos->class == class) { list_append(&graph->pos->lc, &graph->lqueue); } else { struct node *n, *ns; list_for_entry_safe(n, ns, &graph->lnposclassup[class - 1], lc) { list_remove_init(&n->lc); list_append(&n->lc, &graph->lqueue); } } return gar_process_queue(graph, 1, class); } static int gar_load_dest_class(struct gar_graph *graph, int class) { if (graph->dest->class == class) { list_append(&graph->dest->lc, &graph->lqueue); } else { struct node *n, *ns; list_for_entry_safe(n, ns, &graph->lndestclassup[class - 1], lc) { list_remove_init(&n->lc); list_append(&n->lc, &graph->lqueue); } } return gar_process_queue(graph, 0, class); } static int gar_load_next_class(struct gar_graph *graph) { int connected = 0; int curclass; struct node *pos = graph->pos, *dest = graph->dest; curclass = pos->class; if (graph->dest) { if (pos->class < dest->class) { curclass = pos->class; while(curclass < dest->class) { connected = gar_load_pos_class(graph, curclass); if (connected) goto done; curclass++; if (curclass > 7) break; } } else if (pos->class > dest->class) { curclass = dest->class; while(curclass < pos->class) { connected = gar_load_dest_class(graph, curclass); if (connected) goto done; curclass++; if (curclass > 7) break; } } } while (!connected) { connected = gar_load_pos_class(graph, curclass); if (connected) goto done; if (graph->dest) { connected = gar_load_dest_class(graph, curclass); if (connected) goto done; } curclass++; if (curclass > 7) break; } connected = 0; done: if (connected <=0) { // failed to build the graph } return connected; } void gar_free_graph(struct gar_graph *g) { int i; struct node *n, *ns; for (i = 0; i < NODE_HASH_TAB_SIZE; i++) { list_for_entry_safe(n, ns,&g->lnodes[i],l) { gar_free_node(n); } } if (!list_empty(&g->lqueue)) { log(1, "NOD error read queue not empty\n"); } if (!list_empty(&g->lcpoints)) { log(1, "NOD error still have central points\n"); } free(g); } struct gar_graph *gar_alloc_graph(struct gar_subfile *sub) { struct gar_graph *g; int i; g = calloc(1, sizeof(*g)); if (!g) return g; g->sub = sub; // All central points list_init(&g->lcpoints); // All nodes for (i = 0; i < NODE_HASH_TAB_SIZE; i++) list_init(&g->lnodes[i]); list_init(&g->lqueue); for (i = 0; i < 8; i++) { list_init(&g->lnclass[i]); list_init(&g->lnposclassup[i]); list_init(&g->lnposclassdown[i]); list_init(&g->lndestclassup[i]); list_init(&g->lndestclassdown[i]); } return g; }; struct gar_graph * gar_read_graph(struct gar_subfile *sub, int frclass, u_int32_t from, int dstclass, u_int32_t to) { struct gar_graph *g; struct node *pos, *dest; g = gar_alloc_graph(sub); if (!g) return NULL; pos = gar_get_node(g, from); pos->class = frclass; g->pos = pos; if (dstclass != 1000) { dest = gar_get_node(g, to); dest->class = dstclass; g->dest = dest; } g->valid = gar_load_next_class(g); return g; } int gar_update_graph(struct gar_graph *g , int frclass, u_int32_t from) { // TBD // walk all nodes and reset pos/dst reachable // or use grpah version update when visiting // then reload what's needed // move freeing of unused(not pos and not dst reachable) to another function return 0; } int gar_graph2tfmap(struct gar_graph *g, char *filename) { struct node *n; FILE *tfmap; int i,h,j=0; tfmap = fopen(filename, "w"); if (!tfmap) return -1; for (h=0; h < NODE_HASH_TAB_SIZE; h++) { list_for_entry(n, &g->lnodes[h], l) { // FIXME if (!n->complete) continue; fprintf(tfmap, "garmin:0x%x 0x%x type=rg_point debug=\"%d arcs\" label=\"%d-%d\"\n\n", n->c.x , n->c.y, n->narcs, n->nodeid, n->offset); for (i=0; i < n->narcs; i++) { struct grapharc *arc = &n->arcs[i]; if (arc->islink){ log(15, "NOD link to %d\n", arc->dest->offset); continue; } if (!arc->dest->complete) continue; fprintf(tfmap, "type=rg_segment debug=\"l=%d h=%.2f %.2f %.2f \" label=\"%d->%d\"\n", arc->len, arc->heading*1.4173228, arc->curve*1.4173228, arc->headout*1.4173228, n->offset, arc->dest->offset); fprintf(tfmap, "garmin:0x%x 0x%x\n", n->c.x, n->c.y); fprintf(tfmap, "garmin:0x%x 0x%x\n", arc->dest->c.x, arc->dest->c.y); fprintf(tfmap, "\n"); } fprintf(tfmap, "\n"); j++; } } fclose(tfmap); log(1, "NOD Total nodes written: %d\n", j); return j; } static struct cpoint *gar_alloc_cp(void) { struct cpoint *p; p = calloc(1, sizeof(*p)); if (!p) return NULL; list_init(&p->l); return p; } static void gar_free_cpoint(struct cpoint *p) { list_remove(&p->l); if (p->roads) free(p->roads); if (p->idx) free(p->idx); if (p->restr) free(p->restr); free(p); } static struct cpoint *gar_read_cp(struct gar_graph *graph, u_int32_t offset) { struct gimg *gimg = graph->sub->gimg; struct cpoint *p; struct central_point n; int rc; unsigned i; glseek(gimg, offset, SEEK_SET); rc = gread(gimg, &n, sizeof(struct central_point)); if (rc != sizeof(struct nod_node)) { log(1, "NOD: Error reading cpoint\n"); return NULL; } p = gar_alloc_cp(); if (!p) return NULL; if (n.croads) { i = n.croads*graph->sub->net->nod->roadptrsize; p->roads = malloc(i); if (!p->roads) goto out_err; p->rpsize = graph->sub->net->nod->roadptrsize; p->croads = n.croads; rc = gread(gimg, p->roads,i); if (rc != i) goto out_err; i = (n.cidxs) * 3; p->cidxs = n.cidxs; p->idx = malloc(i); if (!p->idx) goto out_err; rc = gread(gimg, p->idx,i); if (rc != i) goto out_err; } p->crestr = n.crestr; if (p->crestr) { p->restr = malloc(p->crestr); if (!p->restr) goto out_err; rc = gread(gimg, p->restr,p->crestr); if (rc != p->crestr) goto out_err; } p->lng = *(u_int32_t *) n.lng & 0xffffff; p->lat = *(u_int32_t *) n.lat & 0xffffff; p->offset = offset; log(11, "CPNT: %d at %f/%f\n", p->offset, GARDEG(p->lng), GARDEG(p->lat)); return p; out_err: gar_free_cpoint(p); return NULL; } static struct cpoint *gar_lookup_cpoint(struct gar_graph *graph, u_int32_t offset) { struct cpoint *p; list_for_entry(p, &graph->lcpoints, l) { if (p->offset == offset) return p; } return NULL; } struct cpoint *gar_get_cpoint(struct gar_graph *graph, u_int32_t offset, int8_t idx) { struct cpoint *p; u_int32_t off = 1 + idx + (offset >> graph->sub->net->nod->cpalign); off <<= graph->sub->net->nod->cpalign; off += graph->sub->net->nod->nod1_offset + graph->sub->net->nod->nodoff; p = gar_lookup_cpoint(graph, off); if (!p) { p = gar_read_cp(graph, off); if (!p) return NULL; list_append(&p->l, &graph->lcpoints); } log(15, "CPNT:%d\n", p->offset); p->refcnt++; return p; } static void gar_put_cpoint(struct cpoint *p) { p->refcnt --; if (p->refcnt == 0) { gar_free_cpoint(p); } } u_int32_t gar_cp_idx2off(struct cpoint *p, u_int8_t idx) { #ifdef DEBUG if (idx >= p->cidxs) { log(1, "NOD Error idx %d not valid max %d\n", idx, p->cidxs); } #endif return get_u24(p->idx+3*idx); } struct roadptr *gar_cp_idx2road(struct cpoint *p, u_int8_t idx) { int i; i = idx*p->rpsize; #ifdef DEBUG if (i > p->croads*p->rpsize) { log(1, "NOD Error roadidx %d not valid max %d\n", idx, p->croads*p->rpsize); } #endif return (struct roadptr *)&p->roads[idx*p->rpsize]; } libgarmin-0~svn320/src/garmin_nod.h000066400000000000000000000071031112544465000174110ustar00rootroot00000000000000/* Copyright (C) 2008 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define NODE_HASH_TAB_SIZE 256 /* must be power of 2 */ #define NODE_HASH(offset) (((offset) *2654435769UL)& (NODE_HASH_TAB_SIZE-1)) struct gar_graph { struct gar_subfile *sub; struct node *pos; struct node *dest; // All nodes unsigned int totalnodes; unsigned valid; list_t lcpoints; list_t lnodes[NODE_HASH_TAB_SIZE]; list_t lqueue; list_t lnclass[8]; /* Links to upper lower classes */ list_t lnposclassup[8]; list_t lndestclassup[8]; list_t lnposclassdown[8]; list_t lndestclassdown[8]; }; struct grapharc; struct node { list_t l; list_t lc; struct node *from; unsigned int value; unsigned nodeid; u_int32_t offset; struct cpoint *cpoint; struct gcoord c; u_int8_t complete:1, posreach:1, dstreach:1, class:3; u_int8_t roadidx; u_int8_t narcs; struct grapharc *arcs; }; struct grapharc { struct node *dest; unsigned int len; unsigned char roadidx; unsigned char roadclass; unsigned char heading; unsigned char curve; // ?? unsigned char headout; unsigned islink:1, have_curve:1; }; struct gar_nod_info { off_t nodoff; u_int32_t nod1_offset; u_int32_t nod1_length; u_int32_t nod2_offset; u_int32_t nod2_length; u_int32_t nod3_offset; u_int32_t nod3_length; u_int8_t nod3_recsize; u_int8_t cpalign; u_int8_t roadptrsize; u_int8_t nodbits; }; struct gar_road_nod { u_int32_t nodesoff; unsigned short bmlen; unsigned char flags; unsigned char _pad; unsigned char bitmap[0]; }; struct cpoint { list_t l; // FIXME need to add sub file if graph is shared u_int32_t offset; unsigned refcnt; u_int8_t crestr; u_int32_t lng; u_int32_t lat; u_int8_t croads; // roads count of unknown4=size records u_int8_t cidxs; // indexes ? u_int8_t rpsize; u_int8_t *roads; u_int8_t *idx; u_int8_t *restr; }; struct roadptr { u_int24_t off; // check size when accessing b1/b2 u_int8_t b1; u_int8_t b2; } __attribute((packed)); struct gar_nod_info *gar_init_nod(struct gar_subfile *sub); void gar_free_nod(struct gar_nod_info *nod); struct gar_graph *gar_read_graph(struct gar_subfile *sub, int fromclass, u_int32_t from, int toclass, u_int32_t to); int gar_update_graph(struct gar_graph *g , int frclass, u_int32_t from); struct node* gar_get_node(struct gar_graph *graph, u_int32_t offset); int gar_graph2tfmap(struct gar_graph *g, char *filename); struct gar_road_nod *gar_read_nod2(struct gar_subfile *sub, u_int32_t offset); void gar_free_road_nod(struct gar_road_nod *nod); struct gar_graph *gar_alloc_graph(struct gar_subfile *sub); void gar_free_graph(struct gar_graph *g); struct cpoint *gar_get_cpoint(struct gar_graph *graph, u_int32_t offset, int8_t idx); u_int32_t gar_cp_idx2off(struct cpoint *p, u_int8_t idx); struct roadptr *gar_cp_idx2road(struct cpoint *p, u_int8_t idx); int gar_read_node(struct gar_graph *graph, struct node *from, struct node *node); int gar_nod_parse_nod3(struct gar_subfile *sub); libgarmin-0~svn320/src/garmin_obj.c000066400000000000000000001035601112544465000174020ustar00rootroot00000000000000/* Copyright (C) 2007,2008 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "list.h" #include "libgarmin.h" #include "libgarmin_priv.h" #include "garmin_rgn.h" #include "garmin_lbl.h" #include "garmin_net.h" #include "garmin_order.h" #include "garmin_subdiv.h" #include "geoutils.h" #include "array.h" static void gar_ref_subdiv(struct gobject *o) { struct gpoint *gp; struct gpoly *gl; struct gar_subdiv *sd = NULL; switch (o->type) { case GO_POINT: gp = o->gptr; sd = gp->subdiv; break; case GO_POLYLINE: case GO_POLYGON: gl = o->gptr; sd = gl->subdiv; break; default: break; }; if (sd) gar_subdiv_ref(sd); } static void gar_unref_subdiv(struct gobject *o) { struct gpoint *gp; struct gpoly *gl; struct gar_subdiv *sd = NULL; switch (o->type) { case GO_POINT: gp = o->gptr; sd = gp->subdiv; break; case GO_POLYLINE: case GO_POLYGON: gl = o->gptr; sd = gl->subdiv; default: break; }; if (sd) gar_subdiv_unref(sd); } static void gar_free_search_obj(struct gar_search_res *s) { gar_subfile_unref(s->sub); free(s); } static struct gar_search_res *gar_alloc_search_obj(struct gar_subfile *sub, struct gar_search_res *from) { struct gar_search_res *s; s = calloc(1, sizeof(*s)); if (!s) return s; if (from) *s = *from; s->sub = sub; s->fileid = sub->id; gar_subfile_ref(sub); return s; } static struct gobject *gar_alloc_object(int type, void *obj) { struct gobject *o; o = calloc(1, sizeof(*o)); if (!o) return o; o->type = type; o->gptr = obj; gar_ref_subdiv(o); return o; } void gar_free_objects(struct gobject *g) { struct gobject *gn; while (g) { gn = g->next; gar_unref_subdiv(g); if (g->type == GO_SEARCH) gar_free_search_obj(g->gptr); free(g); g = gn; } } static int gar_is_point_visible(struct gar_subfile *gsub, int level, struct gpoint *gp) { int i; int type; if (!gsub->fpoint) return 1; // no filter all is visible type = (gp->type << 8 ) || gp->subtype; for (i=0; i < gsub->nfpoint; i++) { if (gsub->fpoint[i].type == type) { if (gsub->fpoint[i].maxlevel >= level) return 1; else return 0; } } return 1; } static int gar_is_line_visible(struct gar_subfile *gsub, int level, struct gpoly *gp) { int i; int type = gp->type; if (!gsub->fpolyline) return 1; // no filter all is visible for (i=0; i < gsub->nfpolyline; i++) { if (gsub->fpolyline[i].type == type) { if (gsub->fpolyline[i].maxlevel >= level) return 1; else return 0; } } return 1; } static int gar_is_pgone_visible(struct gar_subfile *gsub, int level, struct gpoly *gp) { int i; int type = gp->type; if (!gsub->fpolygone) return 1; // no filter all is visible for (i=0; i < gsub->nfpolygone; i++) { if (gsub->fpolygone[i].type == type) { if (gsub->fpolygone[i].maxlevel >= level) return 1; else return 0; } } return 1; } struct gar_subdiv *gar_find_subdiv_by_idx(struct gar_subfile *gsub, int fromlevel, int idx) { int i = fromlevel; struct gar_subdiv *sd; for (; i < gsub->nlevels; i++) { sd = ga_get_abs(&gsub->maplevels[i]->subdivs, idx); if (sd) { if (idx != sd->n) log(1, "Error subdiv found as idx:%d real is:%d\n", idx, sd->n); log(19, "Found in level %d\n", i); return sd; } } return NULL; } // FIXME hack set to 1 to enable map layout checking // 0 to leave to the callers layout #define CHECKVIS 1 static struct gobject *gar_get_subdiv_objs(struct gar_subdiv *gsd, int *count, int level, int start, int routable) { struct gobject *first = NULL, *o = NULL, *p; struct gpoint *gp; struct gpoly *gpoly; struct gar_subfile *gsub = gsd->subfile; int objs = 0; int cnt, i; log(15, "subdiv:%d cx=%d cy=%d north=%d west=%d south=%d east=%d\n", gsd->n, gsd->icenterlng, gsd->icenterlat, gsd->north, gsd->west, gsd->south, gsd->east); if (!gsd->loaded) { if (gar_load_subdiv_data(gsub, gsd) < 0) goto out_err; } if (start) { if (!routable) { cnt = ga_get_count(&gsd->polygons); for (i=0; i < cnt; i++) { gpoly = ga_get(&gsd->polygons, i); /* Do not return definition areas and backgrounds */ if (gpoly->type == 0x4a || gpoly->type == 0x4b) continue; if (CHECKVIS && !gar_is_pgone_visible(gsub, level, gpoly)) continue; p = gar_alloc_object(GO_POLYGON, gpoly); if (!p) goto out_err; if (first) { o->next = p; o = p; } else o = first = p; objs++; } } cnt = ga_get_count(&gsd->polylines); for (i=0; i < cnt; i++) { gpoly = ga_get(&gsd->polylines, i); if (CHECKVIS && !gar_is_line_visible(gsub, level, gpoly)) continue; p = gar_alloc_object(GO_POLYLINE, gpoly); if (!p) goto out_err; if (first) { o->next = p; o = p; } else o = first = p; objs++; } if (!routable) { cnt = ga_get_count(&gsd->points); for (i=0; i < cnt; i++) { gp = ga_get(&gsd->points, i); if (CHECKVIS&& !gar_is_point_visible(gsub, level, gp)) continue; p = gar_alloc_object(GO_POINT, gp); if (!p) goto out_err; if (first) { o->next = p; o = p; } else o = first = p; objs++; } } } // Fixme we can go down to get more POIs // This code is dissabled #if 0 if (0 && gsd->next) { struct gar_subdiv *gss; struct gar_subdiv *gs; int i; log(15, "Must load %d subdiv\n", gsd->next); if (gsd->next == gsd->n) { log(1, "%d points to itself\n", gsd->next); goto done; } if (gsd->nextptr) gss = gsd->nextptr; else { gss = gar_find_subdiv_by_idx(gsub, level, gsd->next); gsd->nextptr = gss; } if (gss) { list_for_entry(gs, gss->l.p, l) { log(15, "Loading subdiv: %d\n", gs->n); p = gar_get_subdiv_objs(gs, &i, level, 0, routable); if (p) { objs += i; if (first) { o = p; while (o->next) o = o->next; o->next = first; } first = p; } if (gs->terminate) break; } } } done: #endif *count = objs; return first; out_err: if (first) gar_free_objects(first); *count = 0; return NULL; } static int gar_subdiv_visible(struct gar_subdiv *sd, struct gar_rect *rect) { struct gar_rect sr; sr.lulat = sd->north; sr.lulong = sd->west; sr.rllat = sd->south; sr.rllong = sd->east; return gar_rects_intersectboth(&sr, rect); } static void *gar_subfile_get_byidx(struct gar_subfile *sub, int sdidx, int oidx, int otype) { int i,j; struct gar_subdiv *sd; struct gar_maplevel *ml; void *obj = NULL; /* FIXME: This can be improved */ for(i=0; i < sub->nlevels; i++) { ml = sub->maplevels[i]; sd = ga_get_abs(&ml->subdivs, sdidx); if (sd) { if (!sd->loaded) { if (gar_load_subdiv_data(sub, sd) < 0) goto out; } switch(otype) { case GO_POINT: obj = ga_get_abs(&sd->points, oidx); goto out; case GO_POLYLINE: obj = ga_get_abs(&sd->polylines, oidx); goto out; case GO_POLYGON: obj = ga_get_abs(&sd->polygons, oidx); goto out; default: log(1, "Unknown object type: %d mapid:%s\n", otype, sub->mapid); } break; } } j = 0; for(i=0; i < sub->nlevels; i++) j += sub->maplevels[i]->ml.nsubdiv; log(1, "Can not find subdiv: %d have %d\n", sdidx, j); return NULL; out: if (obj) return obj; else { if (otype == GO_POLYLINE) { int size = ga_get_count(&sd->polylines); log(1, "Can not find idx:%d sdidx:%d, have maxidx:%d\n", oidx, sdidx, size); } if (otype == GO_POINT) { int size = ga_get_count(&sd->points); log(1, "Can not find idx:%d sdidx:%d, have maxidx:%d\n", oidx, sdidx, size); } } return NULL; } struct gobject *gar_get_subfile_object_byidx(struct gar_subfile *sub, int sdidx, int oidx, int otype) { int i,j; struct gar_subdiv *sd; struct gar_maplevel *ml; void *obj = NULL; /* FIXME: This can be improved */ for(i=0; i < sub->nlevels; i++) { ml = sub->maplevels[i]; sd = ga_get_abs(&ml->subdivs, sdidx); if (sd) { if (!sd->loaded) { if (gar_load_subdiv_data(sub, sd) < 0) goto out; } switch(otype) { case GO_POINT: obj = ga_get_abs(&sd->points, oidx); goto out; case GO_POLYLINE: obj = ga_get_abs(&sd->polylines, oidx); goto out; case GO_POLYGON: obj = ga_get_abs(&sd->polygons, oidx); goto out; default: log(1, "Unknown object type: %d mapid:%s\n", otype, sub->mapid); } break; } } j = 0; for(i=0; i < sub->nlevels; i++) j += sub->maplevels[i]->ml.nsubdiv; log(1, "Can not find subdiv: %d have %d\n", sdidx, j); return NULL; out: if (obj) return gar_alloc_object(otype, obj); else { if (otype == GO_POLYLINE) { int size = ga_get_count(&sd->polylines); log(1, "Can not find idx:%d sdidx:%d, have maxidx:%d\n", oidx, sdidx, size); } if (otype == GO_POINT) { int size = ga_get_count(&sd->points); log(1, "Can not find idx:%d sdidx:%d, have maxidx:%d\n", oidx, sdidx, size); } } return NULL; } struct gar_subfile *gar_subfile_get_by_mapid(struct gar *gar, unsigned int mapid) { struct gimg *g; struct gar_subfile *sub; list_for_entry(g, &gar->limgs,l) { list_for_entry(sub, &g->lsubfiles, l) { if (sub->id == mapid) return sub; } } return NULL; } struct gobject *gar_get_object_by_id(struct gar *gar, unsigned int mapid, unsigned int objid) { unsigned int sdidx; unsigned int otype; unsigned int oidx; struct gimg *g; struct gar_subfile *sub; struct gobject *go = NULL; sdidx = objid >> 16; otype = objid & 0xFF; oidx = (objid >> 8) & 0xFF; log(1, "Looking for sdidx: %d otype:%d oidx: %d in %d\n", sdidx, otype, oidx, mapid); list_for_entry(g, &gar->limgs,l) { list_for_entry(sub, &g->lsubfiles, l) { if (sub->id == mapid) { if (!sub->loaded) { if (gar_load_subfile_data(sub)<0) return NULL; } go = gar_get_subfile_object_byidx(sub, sdidx, oidx, otype); break; } } } return go; } // FIXME: This is very very slow // This function is obsolete now by gar_get_object_by_id struct gobject *gar_get_object(struct gar *gar, void *ptr) { struct gimg *g; struct gar_subfile *sub; struct gar_subdiv *gsd; struct gar_maplevel *ml; struct gpoint *gp; struct gpoly *gpoly; int c, i, j; int cnt, k; list_for_entry(g, &gar->limgs,l) { list_for_entry(sub, &g->lsubfiles, l) { for (i=0; i < sub->nlevels; i++) { ml = sub->maplevels[i]; c = ga_get_count(&ml->subdivs); for (j = 0; j < c; j++) { gsd = ga_get(&ml->subdivs, j); cnt = ga_get_count(&gsd->polygons); for (k=0; k < cnt; k++) { gpoly = ga_get(&gsd->polygons, k); if (gpoly == ptr) { return gar_alloc_object(GO_POLYGON, gpoly); } } cnt = ga_get_count(&gsd->polylines); for (k=0; k < cnt; k++) { gpoly = ga_get(&gsd->polylines, k); if (gpoly == ptr) { return gar_alloc_object(GO_POLYLINE, gpoly); } } cnt = ga_get_count(&gsd->points); for (k=0; k < cnt; k++) { gp = ga_get(&gsd->points, k); if (gp == ptr) { return gar_alloc_object(GO_POINT, gp); } } } } } } return NULL; } static void gar_debug_objects(struct gobject *o); /* TODO: Handle special chars */ static int gar_match(char *needle, char *str, int type) { switch (type) { case GM_EXACT: return !strcasecmp(str, needle); case GM_START: return !strncasecmp(str, needle, strlen(needle)); case GM_ANY: return !!strstr(str, needle); } return 0; } static int gar_get_search_objects(struct gmap *gm, struct gobject **ret, struct gar_search *s) { int i, rc = 0; int nsub; struct gar_search_res *so; struct gar_search_res *from = NULL; struct gar_subfile *gsub; struct gobject *first = NULL, *o = NULL, *ot; from = &s->fromres; if (from) { log(1, "Search from cid: %d rid: %d cid:%d\n", from->countryid, from->regionid, from->cityid); } switch (s->type) { case GS_COUNTRY: break; case GS_REGION: break; case GS_CITY: break; case GS_ZIP: break; case GS_ROAD: break; case GS_INTERSECT: log(1, "Intersection search not implemented\n"); return 0; break; case GS_HOUSENUMBER: log(1, "House Number search not implemented\n"); return 0; break; case GS_POI: log(1, "POI search not implemented\n"); return 0; break; default: log(1, "Error unknow search type:%d\n", s->type); return 0; } for (nsub = 0; nsub < gm->lastsub; nsub++) { gsub = gm->subs[nsub]; if (!gsub->loaded) { // FIXME: error handle // FIXME: Load only the sd-s that are in the selected level // FIXME: Load only if have enough bits gar_load_subfile_data(gsub); } gar_init_srch(gsub, 0); gar_init_srch(gsub, 1); switch (s->type) { case GS_COUNTRY: for (i = 1; i < gsub->ccount; i++) { if (gar_match(s->needle, gsub->countries[i], s->match)) { log(1, "Match: %s(%d)\n", gsub->countries[i],i); so = gar_alloc_search_obj(gsub, from); if (so) { so->countryid = i; o = gar_alloc_object(GO_SEARCH, so); if (o) { rc ++; if (first) { o->next = first; first = o; } else first = o; } } } } break; case GS_REGION: for (i = 1; i < gsub->rcount; i++) { if ((!from->countryid || from->countryid == gsub->regions[i]->country) && gar_match(s->needle, gsub->regions[i]->name, s->match)) { log(1, "Match: %s(%d)\n", gsub->regions[i]->name, i); so = gar_alloc_search_obj(gsub, from); if (so) { so->countryid = gsub->regions[i]->country; so->regionid = i; o = gar_alloc_object(GO_SEARCH, so); if (o) { rc ++; if (first) { o->next = first; first = o; } else first = o; } } } } break; case GS_CITY: for (i = 1; i < gsub->cicount; i++) { char *lbl = gsub->cities[i]->label; if (from->regionid && gsub->cities[i]->region_idx != from->regionid) continue; ot = NULL; if (!lbl) { ot = gar_get_subfile_object_byidx(gsub, gsub->cities[i]->subdiv_idx, gsub->cities[i]->point_idx, GO_POINT); if (ot) lbl = gar_get_object_lbl(ot); } log(15, "Match: %s %s\n", s->needle, lbl); if (lbl && gar_match(s->needle, lbl, s->match)) { log(1, "Match: %s(%d)\n", lbl, i); so = gar_alloc_search_obj(gsub, from); if (so) { so->countryid = gsub->regions[gsub->cities[i]->region_idx]->country; so->regionid = gsub->cities[i]->region_idx; so->cityid = i; if (ot) { struct gar_poi_properties *pr; pr = gar_get_poi_properties(ot->gptr); if (pr) { so->zipid = pr->zipidx; gar_free_poi_properties(pr); } } o = gar_alloc_object(GO_SEARCH, so); if (o) { rc ++; if (first) { o->next = first; first = o; } else first = o; } } } else { if (ot) gar_free_objects(ot); } if (!gsub->cities[i]->label && lbl) free(lbl); } break; case GS_ROAD: if (gsub->net) { struct gar_road *r; char buf[256]; int i,j; gar_load_roadnetwork(gsub); for (i=0; i < ROADS_HASH_TAB_SIZE; i++) { list_for_entry(r, &gsub->net->lroads[i], l) { if (!r->sai || (from->cityid == 0 && from->regionid == 0 && from->zipid == 0) || gar_match_sai(r->sai, from->zipid, from->regionid, from->cityid, 0)) { for(j = 0; j < 4; j++) { if (r->labels[j]) { if (gar_get_lbl(gsub, r->labels[j], L_LBL, (unsigned char *)buf, sizeof(buf))) { if (gar_match(s->needle, buf, s->match)) { so = gar_alloc_search_obj(gsub, from); if (so) { log(10, "Found road: %s\n", buf); if (r->sai) { gar_sai2searchres(r->sai, so); if (!so->regionid) { if (so->cityid) { so->regionid = gsub->cities[so->cityid]->region_idx; } } if (!so->countryid) { if (so->regionid) { so->countryid = gsub->regions[so->regionid]->country; } } } else { so->cityid = 0; so->regionid = 0; so->zipid = 0; } // FIXME: if we have only region // we can get the country // if we have city, we can get region // and country so->roadid = r->offset; o = gar_alloc_object(GO_SEARCH, so); if (o) { rc++; if (first) { o->next = first; first = o; } else first = o; } } } } } } } } } } break; } // gar_free_srch(gsub); } *ret = first; log(1, "Returning %d matches\n", rc); return rc; } /* XXX Make gar_get_objects_zoom and gar_get_objects_level XXX to work with zoom(bits) and with levels */ int gar_get_objects(struct gmap *gm, int level, void *select, struct gobject **ret, int flags) { struct gobject *first = NULL, *o = NULL, *p; struct gar_maplevel *ml; struct gar_subdiv *gsd; struct gar_subfile *gsub; int objs = 0; int bits,i,j, lvlobjs,k; int nsub = 0; int basebits = 6; int baselevel = 0; int sdcount; int routable = flags&GO_GET_ROUTABLE; int prio = -1; struct gar_rect *rect = select; gsub = gm->subs[0]; if (!gsub) return -1; if (routable) { bits = gm->basebits+gm->zoomlevels; log(7, "Looking for roads at last level: %d bits\n", gm->basebits+gm->zoomlevels); // rect = NULL; } else if (flags&GO_GET_SEARCH) { return gar_get_search_objects(gm, ret, select); } else { bits = level; log(7, "Level =%d bits = %d subfiles:%d\n", level, bits, gm->lastsub); } if (rect) { log(15, "Rect: lulong=%f lulat=%f rllong=%f rllat=%f\n", rect->lulong, rect->lulat, rect->rllong, rect->rllat); } basebits = gm->basebits; baselevel = gm->minlevel; log(3, "Basemap bits:%d level = %d\n", basebits, baselevel); if (gm->lastsub == 1 && gm->subs[0]->basemap) { // Check for images where no detail is available if (bits > gsub->maplevels[gsub->nlevels-1]->ml.bits) bits = gsub->maplevels[gsub->nlevels-1]->ml.bits; } for (nsub = gm->lastsub - 1; nsub >=0 ; nsub--) { gsub = gm->subs[nsub]; if (prio != -1 && prio != gsub->drawprio) { break; } if (routable) { if (!gsub->have_net) continue; } log(3, "Loading %s basemap:%s\n", gsub->mapid, gsub->basemap ? "yes" : "no"); if (!gsub->loaded) { // FIXME: error handle // FIXME: Load only the sd-s that are in the selected level // FIXME: Load only if have enough bits if (gsub->maplevels[0]->ml.inherited && gsub->maplevels[0]->ml.bits <= bits) gar_load_subfile_data(gsub); } for (i = 0; i < gsub->nlevels; i++) { nextlvl: ml = gsub->maplevels[i]; if (ml->ml.inherited) { continue; if (gsub->basemap) { // if it's a basemap give what we have continue; } else { if (bits <= ml->ml.bits) // if it's detail and we are not reached // inheritance level skip it break; else continue; } } // if (ml->ml.level < baselevel) // continue; if (ml->ml.bits < bits) { continue; } log(3, "Loading level:%d bits:%d\n", ml->ml.level, ml->ml.bits); lvlobjs = 0; sdcount = ga_get_count(&ml->subdivs); for (k = 0; k < sdcount; k++) { gsd = ga_get(&ml->subdivs, k); if (rect && !gar_subdiv_visible(gsd, rect)) continue; p = gar_get_subdiv_objs(gsd, &j, ml->ml.level, 1, routable); if (p) { log(15, "%s subdiv:%d gave %d objects\n", gsub->mapid, gsd->n, j); //gar_debug_objects(p); objs += j; lvlobjs += j; if (first) { o = p; while (o->next) o = o->next; o->next = first; } first = p; prio = gsub->drawprio; } } log(10, "Total objects:%d level: %d\n", objs, lvlobjs); if (0 && lvlobjs < 2) { // do this only if submap is transparent if (i+1 < gsub->nlevels) { i++; // FIXME: Free parasit objects goto nextlvl; } } break; } } if (!first) { log(1, "Error no objects found\n"); /* * FIXME: For the case where we have no detailed maps * for all areas, in that case show the last level from * the basemap */ } if ((flags&GO_GET_SORTED) && gm->draworder) *ret = gar_order_objects(first, gm->draworder, 1); else *ret = first; return objs; } unsigned short gar_obj_type(struct gobject *o) { unsigned short ret = 0; switch (o->type) { case GO_POINT: { struct gpoint *point; point = o->gptr; if (point->has_subtype) ret |= point->subtype; ret |= point->type << 8; } break; case GO_POLYLINE: case GO_POLYGON: ret = ((struct gpoly *)o->gptr)->type; break; case GO_ROAD: case GO_SEARCH: ret = 1; break; default: ret = ~0; log(1, "Error unknown object type:%d\n", o->type); } return ret; } int gar_get_object_position(struct gobject *o, struct gcoord *ret) { switch (o->type) { case GO_POINT: ret->x = ((struct gpoint *)o->gptr)->c.x; ret->y = ((struct gpoint *)o->gptr)->c.y; return 1; case GO_POLYLINE: case GO_POLYGON: ret->x = ((struct gpoly *)o->gptr)->c.x; ret->y = ((struct gpoly *)o->gptr)->c.y; return 1; default: log(1, "Error unknown object type:%d\n", o->type); } return 0; } int gar_get_object_deltas(struct gobject *o) { struct gpoly *gp; if (o->type == GO_POINT) return 0; gp = o->gptr; if (gp->valid) return gp->npoints + 1; return 0; } int gar_get_object_coord(struct gmap *gm, struct gobject *o, struct gcoord *ret) { struct gpoint *gp; struct gpoly *gl = NULL; if (o->type == GO_POINT) { gp = o->gptr; ret->x = gp->c.x; ret->y = gp->c.y; return 1; } else if (o->type == GO_SEARCH) { struct gar_search_res *res; struct city_def *cd = NULL; struct gpoint *gp; res = o->gptr; if (res->roadid) { struct gar_road *rd = gar_get_road(res->sub, res->roadid); if (rd) { if (rd->rio_cnt) { struct gar_subdiv *sd; int idx, sdidx; if (!rd->sub->loaded) { if (gar_load_subfile_data(rd->sub) < 0) return 0; } idx = rd->ri[0] & 0xff; sdidx = rd->ri[0] >> 8; sdidx &= 0xFFFF; sd = ga_get_abs(&rd->sub->maplevels[rd->sub->nlevels - 1]->subdivs, sdidx); if (sd) { if (!sd->loaded) { if (gar_load_subdiv_data(rd->sub, sd) < 0) return 0; } gl = ga_get_abs(&sd->polylines, idx); if (gl) { ret->x = gl->c.x; ret->y = gl->c.y; return 1; } } else { log(1, "Error can not find road idx/sd %d %d in level %d roadid:%ld\n", idx, sdidx,rd->rio[0], rd->offset); return 0; } } } return 0; } // give the most precise coord here if (res->cityid) { if (res->cityid < res->sub->cicount) { cd = res->sub->cities[res->cityid]; if (cd->label) { cd = NULL; } } } if (!cd && res->regionid) { int i; struct city_def *cd = NULL; for (i=1; i < res->sub->cicount; i++) { cd = res->sub->cities[i]; if (!cd->label && cd->region_idx == res->regionid) { break; } else cd = NULL; } } if (!cd && res->countryid) { int i; int rid = 0; struct city_def *cd = NULL; for (i=1; i < res->sub->rcount; i++) { if (res->sub->regions[i]->country == res->countryid) { rid = i; break; } } if (rid) { for (i=1; i < res->sub->cicount; i++) { cd = res->sub->cities[i]; if (!cd->label && cd->region_idx == rid) { break; } else cd = NULL; } } } if (cd) { gp = gar_subfile_get_byidx(res->sub, cd->subdiv_idx, cd->point_idx, GO_POINT); if (gp) { ret->x = gp->c.x; ret->y = gp->c.y; return 1; } else { log(1, "Error can not find city object\n"); } } else { log(1, "Error can not any find city\n"); } return 0; } else if (o->type == GO_ROAD) { struct gar_road *rd = o->gptr; if (rd->rio_cnt) { struct gar_subdiv *sd; int idx, sdidx; if (!rd->sub->loaded) { if (gar_load_subfile_data(rd->sub) < 0) return 0; } idx = rd->ri[0] & 0xff; sdidx = rd->ri[0] >> 8; sdidx &= 0xFFFF; sd = ga_get_abs(&rd->sub->maplevels[rd->sub->nlevels - 1]->subdivs, sdidx); if (sd) { if (!sd->loaded) { if (gar_load_subdiv_data(rd->sub, sd) < 0) return 0; } gl = ga_get_abs(&sd->polylines, idx); } else { log(1, "Error can not find road idx/sd %d %d in level %d roadid:%ld\n", idx, sdidx,rd->rio[0], rd->offset); } } } else { gl = o->gptr; } if (!gl) return 0; ret->x = gl->c.x; ret->y = gl->c.y; return 1; } int gar_get_object_dcoord(struct gmap *gm, struct gobject *o, int ndelta, struct gcoord *ret) { struct gpoly *gp; if (o->type == GO_POINT) return 0; gp = o->gptr; if (ndelta < gp->npoints) { *ret = gp->deltas[ndelta]; return 1; } return 0; } int gar_is_object_dcoord_node(struct gmap *gm, struct gobject *o, int ndelta) { struct gpoly *gp; if (o->type == GO_POINT) return 0; gp = o->gptr; if (gp->nodemap && ndelta <= gp->npoints) { return bm_is_set(gp->nodemap, ndelta); } return 0; } char *gar_get_object_lbl(struct gobject *o) { char buf[8192]; off_t off; int type,rc; struct gar_subfile *gs = NULL; struct gpoint *gp; struct gpoly *gpl; struct gar_road *rd; type = L_LBL; switch (o->type) { case GO_POINT: gp = o->gptr; if (gp->is_poi) type = L_POI; gs = gp->subdiv->subfile; off = gp->lbloffset; if (gp->type == 0) return NULL; break; case GO_POLYLINE: case GO_POLYGON: gpl = o->gptr; if (gpl->netlbl) type = L_NET; gs = gpl->subdiv->subfile; off = gpl->lbloffset; break; case GO_ROAD: { int i,sz = 0; rd = o->gptr; for (i=0;i < 4; i++) { if (rd->labels[i]) { sz += gar_get_lbl(rd->sub, rd->labels[i], L_LBL, (unsigned char *)buf+sz, sizeof(buf)-sz); strcat(buf, "/"); } } if (sz) return strdup(buf); else return NULL; } default: log(1, "Error unknown object type:%d\n", o->type); return NULL; } rc = gar_get_lbl(gs, off, type, (unsigned char *)buf, sizeof(buf)); if (rc > 0) { log(15, "LBL: type:%d [%d] offset=%03lX [%s]\n", o->type, type, off, buf); return strdup(buf); } return NULL; } int gar_get_object_intlbl(struct gobject *o) { char *cp; int r = -1; // FIXME don't strdup/free cp = gar_get_object_lbl(o); if (cp) { r = atoi(cp); free(cp); } return r; } int gar_object_subtype(struct gobject *o) { struct gpoint *poi; u_int8_t ret = 0; switch (o->type) { case GO_POINT: poi = o->gptr; if (poi->has_subtype) ret = poi->subtype; break; case GO_POLYLINE: case GO_POLYGON: break; default: log(1, "Error unknown object type:%d\n", o->type); } return ret; } int gar_object_mapid(struct gobject *o) { struct gar_subdiv *sd = NULL; switch (o->type) { case GO_POINT: sd = ((struct gpoint *)o->gptr)->subdiv; break; case GO_POLYLINE: case GO_POLYGON: sd = ((struct gpoly *)o->gptr)->subdiv; break; case GO_ROAD: return ((struct gar_road *)o->gptr)->sub->id; case GO_SEARCH: return ((struct gar_search_res *)o->gptr)->sub->id; default: log(1, "Error unknown object type:%d\n", o->type); } if (sd) return sd->subfile->id; return -1; } int gar_object_flags(struct gobject *o) { int ret = 0; struct gpoly *gp; switch (o->type) { case GO_POINT: case GO_POLYGON: break; case GO_POLYLINE: gp = o->gptr; if (gp->dir) ret |= F_ONEWAY; if (gp->extrabit) ret |= F_SEGMENTED; if (gp->netlbl) { struct gar_road *road; road = gar_get_road(gp->subdiv->subfile, gp->lbloffset); if (road) { if (road->road_flags&RFL_ONEWAY) ret |= F_ONEWAY; if (road->road_flags&RFL_LOCKTOROAD) ret |= F_LOCKONROAD; gar_free_road(road); } } break; default: log(1, "Error unknown object type:%d\n", o->type); } return ret; } int gar_object_index(struct gobject *o) { switch (o->type) { case GO_POINT: { struct gpoint *pt; pt = o->gptr; if (pt->n > 255) { log(1, "Error more than 255 points in a subdiv are not supported\n"); } return (pt->subdiv->n << 16) | (pt->n << 8) | o->type; } case GO_POLYLINE: case GO_POLYGON: { struct gpoly *p; p = o->gptr; if (p->n > 255) { log(1, "Error more than 255 polygons/lines in a subdiv are not supported\n"); } return (p->subdiv->n << 16) | (p->n << 8) | o->type; } case GO_ROAD: return ((struct gar_road *)o->gptr)->offset; case GO_SEARCH: { struct gar_search_res *s = o->gptr; if (s->roadid) return s->roadid; if (s->cityid) return s->cityid; if (s->regionid) return s->regionid; if (s->countryid) return s->countryid; return -1; } default: log(1, "Error unknown object type:%d\n", o->type); } return 0; } int gar_object_group(struct gobject *o) { switch (o->type) { case GO_POINT: return ((struct gpoint *)o->gptr)->is_nt; case GO_POLYLINE: case GO_POLYGON: return ((struct gpoly *)o->gptr)->is_nt; default: return 0; } } static void gar_log_source(u_int8_t *src, int len) { char buf[len*3+1]; int i,sz = 0; for (i=0; i < len; i++) sz += sprintf(buf+sz, "%02X ", src[i]); log(1, "SRC:[%s]\n", buf); } char *gar_object_debug_str(struct gobject *o) { struct gpoint *gp; struct gpoly *gl; struct gar_subdiv *sd = NULL; char buf[1024]; char extra[100]; u_int32_t idx = 0; int type=0; struct gcoord c; unsigned char *src = NULL; int slen = 0; *extra = '\0'; switch (o->type) { case GO_POINT: gp = o->gptr; type = gp->type << 8 | gp->subtype; c = gp->c; idx = gp->n; sd = gp->subdiv; src = gp->source; slen = gp->slen; break; case GO_POLYLINE: case GO_POLYGON: gl = o->gptr; type = gl->type; c = gl->c; idx = gl->n; sd = gl->subdiv; sprintf(extra, " d:%u sc:%u eb:%u dt:%d", gl->dir, gl->scase, gl->extrabit, gl->npoints); src = gl->source; slen = gl->slen; break; default: return NULL; } if (src) { gar_log_source(src, slen); } if (sd) { snprintf(buf, sizeof(buf), "SF:%s SD:%d l=%d ot=%d idx=%d gt=0x%02X lng=%f lat=%f%s", sd->subfile->mapid, sd->n, sd->shift, o->type, idx, type, GARDEG(c.x), GARDEG(c.y), extra); return strdup(buf); } return NULL; } static void gar_debug_objects(struct gobject *o) { char *cp; while(o) { cp = gar_object_debug_str(o); if (cp) { log(1, "%s\n", cp); free(cp); } o = o->next; } } unsigned int gar_srch_get_countryid(struct gobject *o) { struct gar_search_res *s = o->gptr; if (o->type != GO_SEARCH) return 0; return s->countryid; } char *gar_srch_get_country(struct gobject *o) { struct gar_subfile *sub; struct gar_search_res *s = o->gptr; unsigned id; if (o->type != GO_SEARCH) return 0; id = s->countryid; sub = s->sub; if (id < sub->ccount) return sub->countries[id]; return NULL; } unsigned int gar_srch_get_regionid(struct gobject *o) { struct gar_search_res *s = o->gptr; if (o->type != GO_SEARCH) return 0; return s->regionid; } char *gar_srch_get_region(struct gobject *o) { struct gar_subfile *sub; struct gar_search_res *s = o->gptr; unsigned id; if (o->type != GO_SEARCH) return 0; id = s->regionid; sub = s->sub; if (id && id < sub->rcount) return sub->regions[id]->name; return NULL; } unsigned int gar_srch_get_cityid(struct gobject *o) { struct gar_search_res *s = o->gptr; if (o->type != GO_SEARCH) return 0; return s->cityid; } char *gar_srch_get_city(struct gobject *o) { struct gar_search_res *s = o->gptr; struct gobject *ot; unsigned id; char *lbl = NULL; if (o->type != GO_SEARCH) return NULL; id = s->cityid; if (!id) return NULL; if (s->sub->cities[id]->label) return strdup(s->sub->cities[id]->label); ot = gar_get_subfile_object_byidx(s->sub, s->sub->cities[id]->subdiv_idx, s->sub->cities[id]->point_idx, GO_POINT); if (ot) lbl = gar_get_object_lbl(ot); return lbl; } unsigned int gar_srch_get_zipid(struct gobject *o) { struct gar_search_res *s = o->gptr; if (o->type != GO_SEARCH) return 0; return s->zipid; } char *gar_srch_get_zip(struct gobject *o) { struct gar_subfile *sub; struct gar_search_res *s = o->gptr; unsigned id; if (o->type != GO_SEARCH) return 0; id = s->zipid; sub = s->sub; if (id && id < sub->czips) return sub->zips[id]->code; return NULL; } unsigned int gar_srch_get_roadid(struct gobject *o) { struct gar_search_res *s = o->gptr; if (o->type != GO_SEARCH) return 0; return s->roadid; } char *gar_srch_get_roadname(struct gobject *o) { struct gar_search_res *s = o->gptr; struct gar_subfile *sub = s->sub; unsigned id; struct gar_road *rd; if (o->type != GO_SEARCH) return 0; id = s->roadid; rd = gar_get_road(sub, id); if (rd) { char buf[8192]; int i,sz = 0; for (i=0;i < 4; i++) { if (rd->labels[i]) { if (sz) { strcat(buf, "/"); sz++; } sz += gar_get_lbl(rd->sub, rd->labels[i], L_LBL, (unsigned char *)buf+sz, sizeof(buf)-sz); } } if (sz) { log(1, "roadname:[%s]\n", buf); return strdup(buf); } } else { log(1, "Can not find road %d\n", id); } return strdup(""); } char *gar_obj_codepage(struct gobject *o) { struct gar_subdiv *sd = NULL; switch (o->type) { case GO_POINT: sd = ((struct gpoint *)o->gptr)->subdiv; break; case GO_POLYLINE: case GO_POLYGON: sd = ((struct gpoly *)o->gptr)->subdiv; break; case GO_SEARCH: { struct gar_search_res *s = o->gptr; if (s->sub->lbl) return sd->subfile->lbl->codepage; } break; case GO_ROAD: default: ; } if (sd) { if (sd->subfile->lbl) return sd->subfile->lbl->codepage; } return "ascii"; } libgarmin-0~svn320/src/garmin_order.c000066400000000000000000000133101112544465000177340ustar00rootroot00000000000000#include #include #include #include "list.h" #include "libgarmin.h" #include "libgarmin_priv.h" #include "garmin_order.h" #ifdef STANDALONE #undef log #define log(n,x...) fprintf(stdout, ## x) #endif struct gar_objprio_def { unsigned char objid; unsigned char prio; }; /* Default polygon draw order 1 is lowest prio */ static struct gar_objprio_def def_poly_order[] = { { 0x01,1 }, { 0x02,1 }, { 0x03,1 }, { 0x04,1 }, { 0x05,1 }, { 0x06,1 }, { 0x07,1 }, { 0x08,3 }, { 0x09,1 }, { 0x0a,2 }, { 0x0b,2 }, { 0x0c,2 }, { 0x0d,2 }, { 0x0e,2 }, { 0x13,2 }, { 0x14,2 }, { 0x15,2 }, { 0x16,2 }, { 0x17,3 }, { 0x18,3 }, { 0x19,3 }, { 0x1a,4 }, { 0x1e,2 }, { 0x1f,2 }, { 0x20,2 }, { 0x28,1 }, { 0x29,1 }, { 0x32,1 }, { 0x3b,1 }, { 0x3c,7 }, { 0x3d,7 }, { 0x3e,7 }, { 0x3f,7 }, { 0x40,7 }, { 0x41,7 }, { 0x42,7 }, { 0x43,7 }, { 0x44,4 }, { 0x45,2 }, { 0x46,2 }, { 0x47,2 }, { 0x48,3 }, { 0x49,4 }, { 0x4a,8 }, { 0x4b,8 }, { 0x4c,5 }, { 0x4d,5 }, { 0x4e,5 }, { 0x4f,5 }, { 0x50,3 }, { 0x51,6 }, { 0x52,4 }, { 0x53,5 }, }; int gar_init_draworder(struct gar_objdraworder *o, int objtype) { o->maxprio = 0; o->objtype = objtype; return 1; } int gar_free_draworder(struct gar_objdraworder *o) { return 1; } int gar_get_draw_prio(struct gar_objdraworder *d, unsigned char objid) { return d->order[objid]; } int gar_del_draw_prio(struct gar_objdraworder *d, unsigned char objid, unsigned char prio) { d->order[objid] = 0; return 0; } int gar_add_draw_prio(struct gar_objdraworder *d, unsigned char objid, unsigned char prio) { if (prio > d->maxprio) d->maxprio = prio; d->order[objid] = prio; return 1; } int gar_set_default_poly_order(struct gar_objdraworder *od) { int i; for (i = 0; i < sizeof(def_poly_order)/sizeof(def_poly_order[0]); i++) if (gar_add_draw_prio(od, def_poly_order[i].objid, def_poly_order[i].prio) < 0) return -1; return 0; } static int inline gar_get_obj_prio(struct gobject *o, struct gar_objdraworder *od) { int objid = -1; switch (o->type) { case GO_POINT: objid = ((struct gpoint *)o->gptr)->type; break; case GO_POLYLINE: case GO_POLYGON: objid = ((struct gpoly *)o->gptr)->type; break; } if (objid == -1) return 0; return gar_get_draw_prio(od, objid); } static int gar_count_objects(struct gobject *objs) { int c = 0; while (objs) { c++; objs = objs->next; } return c; } static struct gobject *gar_do_order(struct gobject *objs, struct gar_objdraworder *od) { struct gobject *ol, *on = NULL; struct gobject *prios[od->maxprio+1]; struct gobject *last[od->maxprio+1]; int i; for (i=0; i < od->maxprio + 1; i++) { last[i] = prios[i] = NULL; } ol = objs; while (objs) { on = objs->next; i = gar_get_obj_prio(objs, od); if (prios[i]) objs->next = prios[i]; else { objs->next = NULL; last[i] = objs; } prios[i] = objs; objs=on; } if (prios[0]) { log(1, "Unknown order prio[0] = %d\n", gar_count_objects(prios[0])); } ol = last[0]; if (ol) on = prios[0]; for (i=1; i < od->maxprio + 1; i++) { if (ol) ol->next = prios[i]; else if (!on) on = prios[i]; if (last[i]) ol = last[i]; } return on; } /* Objects list to sort, draw order, where to place the sorted objects head = 1, at head, = 0 at tail unknown objects are ordered in front, prio=0 as per pseudo docs they should not be drawn Polygons are sorted in front TODO: Order Polylines after polygons and points after polylines */ struct gobject *gar_order_objects(struct gobject *objs, struct gar_objdraworder *od, int head) { struct gobject *toorder = NULL, *otmp, *ostart, *otmp1; struct gobject *order = NULL, *oprev = NULL; int type = od->objtype; int incnt,outcnt; incnt = gar_count_objects(objs); ostart = otmp = objs; while (otmp) { if (otmp->type == type) { // remove from list if (oprev) { oprev->next = otmp->next; } else { ostart = otmp->next; } // add to order list if (order) { order->next = otmp; order = order->next; } else { order = toorder = otmp; } // oprev stay the same otmp1 = otmp->next; otmp->next = NULL; otmp = otmp1; } else { oprev = otmp; otmp = otmp->next; } } if (!toorder) return ostart; otmp1 = gar_do_order(toorder, od); if (head) { oprev = otmp1; while (oprev->next) oprev = oprev->next; oprev->next = ostart; order = otmp1; } else { oprev = ostart; while (oprev->next) oprev = oprev->next; oprev->next = otmp1; order = ostart; } outcnt = gar_count_objects(order); if (incnt!=outcnt) log(1, "Inobjects:%d outobjects: %d lost:%d\n", incnt, outcnt, incnt-outcnt); return order; } #ifdef STANDALONE static int gar_show_prios(struct gar_objdraworder *d) { int i; for (i=0; i < 256; i++) fprintf(stderr, "%d = %02X\n", d->order[i], i); printf("maxprio=%d\n", d->maxprio); return 0; } void print_dummy(struct gobject *d) { int cnt = 0; while (d) { cnt ++; printf("type=%d objid=%02X\n", d->type, ((struct gpoint *)d->gptr)->type); d = d->next; } printf("Total: %d\n", cnt); } struct gobject *make_dummy(int cnt) { struct gobject *ret = NULL, *go , *prev; while (cnt) { go = calloc(1, sizeof(*go)); go->type = 4; go->gptr = calloc(1, sizeof(struct gpoint)); if (cnt < 10) ((struct gpoint *)go->gptr)->type = 0x32; else ((struct gpoint *)go->gptr)->type = 0x01; if (!ret) prev = ret = go; else { prev->next = go; prev = go; } cnt --; } return ret; } int main(int argc, char **argv) { struct gar_objdraworder od; struct gobject *g; gar_init_draworder(&od,4); gar_set_default_poly_order(&od); gar_show_prios(&od); g = make_dummy(20); printf("input:\n"); print_dummy(g); g = gar_order_objects(g, &od, 1); printf("result:\n"); print_dummy(g); gar_free_draworder(&od); } #endif libgarmin-0~svn320/src/garmin_order.h000066400000000000000000000012101112544465000177350ustar00rootroot00000000000000struct gar_objdraworder { int objtype; int maxprio; unsigned char order[256]; }; struct gobject; int gar_init_draworder(struct gar_objdraworder *o, int objtype); int gar_free_draworder(struct gar_objdraworder *o); int gar_get_draw_prio(struct gar_objdraworder *d, unsigned char objid); int gar_del_draw_prio(struct gar_objdraworder *d, unsigned char objid, unsigned char prio); int gar_add_draw_prio(struct gar_objdraworder *d, unsigned char objid, unsigned char prio); int gar_set_default_poly_order(struct gar_objdraworder *od); struct gobject *gar_order_objects(struct gobject *objs, struct gar_objdraworder *od, int head); libgarmin-0~svn320/src/garmin_rgn.c000066400000000000000000001032171112544465000174150ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #define __USE_GNU #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "garmin_rgn.h" #include "garmin_fat.h" #include "garmin_lbl.h" #include "garmin_net.h" #include "garmin_mdr.h" #include "garmin_subdiv.h" #include "garmin_order.h" #include "geoutils.h" #include "array.h" #include "extras.h" static int gar_load_points_overview(struct gar_subfile *sub, struct hdr_tre_t *tre) { ssize_t off; struct gimg *g = sub->gimg; u_int8_t *prec; u_int8_t *rp; int rc,sz,i; if (!tre->tre6_offset) { log(11, "No polygon overview records\n"); return 0; } off = gar_subfile_baseoffset(sub, "TRE"); off += tre->tre6_offset; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error can not seek to %zd\n", off); return -1; } rc = tre->tre6_size/tre->tre6_rec_size; log(11, "Have %d point overview records recsize=%d\n", rc, tre->tre6_rec_size); if (rc == 0) return 1; sub->fpoint = calloc(rc, sizeof(struct mlfilter)); if (!sub->fpoint) return -1; sub->nfpoint = rc; prec = calloc(rc, (tre->tre6_rec_size)); rc = gread(g, prec, tre->tre6_size); if (rc != tre->tre6_size) { log(1, "Error reading polygon overviews: %d\n", rc); free(prec); return -1; } rp = prec; sz = tre->tre6_size; i = 0; while (sz > 0) { log(15, "type:%02X maxlevel: %d subtype: %02X\n", *rp, *(rp+1), tre->tre6_rec_size > 2 ? *(rp+2) : 0); sub->fpoint[i].type = (*rp << 8) | (tre->tre6_rec_size > 2 ? *(rp+2) : 0); sub->fpoint[i].maxlevel = *(rp+1); i++; rp+= tre->tre6_rec_size; sz-= tre->tre6_rec_size; } free(prec); return 1; } static void gar_free_points_overview(struct gar_subfile *sub) { if (sub->fpoint) free(sub->fpoint); sub->fpoint = NULL; sub->nfpoint = 0; } static int gar_load_polygons_overview(struct gar_subfile *sub, struct hdr_tre_t *tre) { ssize_t off; struct gimg *g = sub->gimg; u_int8_t *prec; u_int8_t *rp; int rc,sz,i; if (!tre->tre5_offset) { log(11, "No polygon overview records\n"); return 0; } off = gar_subfile_baseoffset(sub, "TRE"); off += tre->tre5_offset; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error can not seek to %zd\n", off); return -1; } rc = tre->tre5_size/tre->tre5_rec_size; log(11, "Have %d polygon overview records recsize=%d\n", rc, tre->tre5_rec_size); if (rc == 0) return 1; sub->fpolygone = calloc(rc, sizeof(struct mlfilter)); if (!sub->fpolygone) return -1; sub->nfpolygone = rc; prec = calloc(rc, (tre->tre5_rec_size)); rc = gread(g, prec, tre->tre5_size); if (rc != tre->tre5_size) { log(1, "Error reading polygon overviews: %d\n", rc); free(prec); return -1; } rp = prec; sz = tre->tre5_size; i = 0; while (sz > 0) { log(15, "type:%02X maxlevel: %d unknown: %02X\n", *rp, *(rp+1), tre->tre5_rec_size > 2 ? *(rp+2) : 0); sub->fpolygone[i].type = *rp; sub->fpolygone[i].maxlevel = *(rp+1); i++; rp+= tre->tre5_rec_size; sz-= tre->tre5_rec_size; } free(prec); return 1; } static void gar_free_polygons_overview(struct gar_subfile *sub) { if (sub->fpolygone) free(sub->fpolygone); sub->fpolygone = NULL; sub->nfpolygone = 0; } static int gar_load_polylines_overview(struct gar_subfile *sub, struct hdr_tre_t *tre) { ssize_t off; struct gimg *g = sub->gimg; u_int8_t *prec; u_int8_t *rp; int rc,sz,i; if (!tre->tre4_offset) { log(11, "No polylines overview records\n"); return 0; } off = gar_subfile_baseoffset(sub, "TRE"); off += tre->tre4_offset; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error can not seek to %zd off=%d size=%d\n", off, tre->tre4_offset, tre->tre4_size); return -1; } rc = tre->tre4_size/tre->tre4_rec_size; log(11, "Have %d polylines overview records recsize=%d\n", rc, tre->tre4_rec_size); if (rc == 0) return 1; sub->fpolyline = calloc(rc, sizeof(struct mlfilter)); if (!sub->fpolyline) return -1; sub->nfpolyline = rc; prec = calloc(rc, (tre->tre4_rec_size)); rc = gread(g, prec, tre->tre4_size); if (rc != tre->tre4_size) { log(1, "Error reading polylines overviews: %d\n", rc); free(prec); return -1; } rp = prec; sz = tre->tre4_size; i = 0; while (sz > 0) { log(15, "type:%02X maxlevel: %d unknown: %02X\n", *rp, *(rp+1), tre->tre4_rec_size > 2 ? *(rp+2) : 0); sub->fpolyline[i].type = *rp; sub->fpolyline[i].maxlevel = *(rp+1); rp+= tre->tre4_rec_size; sz-= tre->tre4_rec_size; } free(prec); return 1; } static void gar_free_polylines_overview(struct gar_subfile *sub) { if (sub->fpolyline) free(sub->fpolyline); sub->fpolyline = NULL; sub->nfpolyline = 0; } static int gar_load_ml_subdata(struct gar_subfile *sub, struct gar_maplevel *ml) { struct gar_subdiv *gsub; unsigned int c,p = 0; unsigned int i = ga_get_count(&ml->subdivs); for (c = 0; c < i; c++) { gsub = ga_get(&ml->subdivs, c); if (gar_load_subdiv_data(sub, gsub)<0) return -1; log(13, "Points: %d Lines:%d Polys:%d\n", ga_get_count(&gsub->points), ga_get_count(&gsub->polylines), ga_get_count(&gsub->polygons)); if (sub->gimg->gar->cfg.opm == OPM_PARSE) { gar_free_subdiv_data(gsub); } else if (sub->gimg->gar->cfg.opm == OPM_DUMP) { // for all subdiv objs do a callback gar_free_subdiv_data(gsub); } p++; } log(11,"Loaded %d subdivs\n", p); return 0; } static int gar_load_subdivs_data(struct gar_subfile *sub) { int i; int c = 0; for (i=0; i < sub->nlevels; i++) { if (gar_load_ml_subdata(sub, sub->maplevels[i]) < 0) { return -1; } c++; } log(19,"Loaded %d maplevels\n", c); return 0; } static void gar_parse_subdiv_nt(struct gar_subfile *sub,struct hdr_tre_t *tre) { struct gar_subdiv *sd; u_int32_t rgn2_start = 0; u_int32_t rgn2_end = 0; u_int32_t rgn3_start = 0; u_int32_t rgn3_end = 0; u_int32_t rgn4_start = 0; u_int32_t rgn4_end = 0; u_int32_t rgn5_start = 0; u_int32_t rgn5_end = 0; u_int8_t unk1 = 0; int lpos = 0; int sdidx = 0 ,rc = 0; struct gimg *g = sub->gimg; off_t off = gar_subfile_baseoffset(sub, "TRE") + tre->tre7_offset; int recsize = tre->tre7_rec_size; if (tre->tre7_size == 0) return; { unsigned char rec[recsize]; glseek(g, off, SEEK_SET); if (recsize != 13) { log(1, "Extra data in tre_nt size=%d our=%d\n", recsize, 13); } while (rc < tre->tre7_size) { lpos = 0; rc += gread(g, rec, recsize); if (recsize >= 4) { rgn2_end = *(u_int32_t *)rec; lpos = 4; } if (recsize >= 8) { rgn3_end = *(u_int32_t *)(rec+4); lpos = 8; } if (recsize >= 12) { rgn4_end = *(u_int32_t *)(rec+8); lpos = 12; } if (recsize > lpos) { unk1 = rec[lpos]; } if (sdidx) { sd = gar_find_subdiv_by_idx(sub, 0, sdidx); if (!sd) { log(1, "Error subdiv %d not found aborting\n", sdidx); return; } sd->rgn2_start = rgn2_start; sd->rgn2_end = rgn2_end; sd->rgn3_start = rgn3_start; sd->rgn3_end = rgn3_end; sd->rgn4_start = rgn4_start; sd->rgn4_end = rgn4_end; sd->rgn5_start = rgn5_start; sd->rgn5_end = rgn5_end; sd->unknown1 = unk1; log(11, "SD %d 2s = %x 2e = %x, 3s = %x 3e = %d, 4s = %x 5e = %x unk1=%x\n", sdidx, sd->rgn2_start, sd->rgn2_end, sd->rgn3_start, sd->rgn3_end, sd->rgn4_start, sd->rgn4_end, unk1); } rgn2_start = rgn2_end; rgn3_start = rgn3_end; rgn4_start = rgn4_end; rgn5_start = rgn5_end; sdidx++; } } log(1, "Loaded %d records of NT RGN data\n", sdidx); } static void gar_parse_subdiv(struct gar_subdiv *gsub, struct tre_subdiv_t *sub) { u_int32_t cx,cy; u_int32_t width, height; gsub->terminate = sub->terminate; gsub->rgn_start = get_u24(&sub->rgn_offset); log(14, "rgn_start: %04X terminate=%d elements=%x\n", gsub->rgn_start, gsub->terminate,sub->elements); /* In the imgformat points and POIs are swapped*/ gsub->haspoints = !!(sub->elements & 0x10); gsub->hasidxpoints = !!(sub->elements & 0x20); gsub->haspolylines = !!(sub->elements & 0x40); gsub->haspolygons = !!(sub->elements & 0x80); cx = get_u24(&sub->center_lng); gsub->icenterlng = SIGN3B(cx); cy = get_u24(&sub->center_lat); gsub->icenterlat = SIGN3B(cy); width = sub->width & 0x7fff; height = sub->height; width <<= gsub->shift; height <<= gsub->shift; gsub->north = gsub->icenterlat + height; gsub->south = gsub->icenterlat - height; gsub->east = gsub->icenterlng + width; gsub->west = gsub->icenterlng - width; if (gsub->south > gsub->north || gsub->west > gsub->east) log(1, "Invalid Subdiv North: %fC, East: %fC, South: %fC, West: %fC cx=%d cy=%d\n", GARDEG(gsub->north), GARDEG(gsub->east), GARDEG(gsub->south), GARDEG(gsub->west), gsub->icenterlng, gsub->icenterlat); log(13, "Subdiv North: %fC, East: %fC, South: %fC, West: %fC cx=%d cy=%d\n", GARDEG(gsub->north), GARDEG(gsub->east), GARDEG(gsub->south), GARDEG(gsub->west), gsub->icenterlng, gsub->icenterlat); } static struct gar_subdiv *gar_subdiv_alloc(struct gar_subfile *subf) { struct gar_subdiv *gsub = calloc(1, sizeof(*gsub)); if (gsub) { ga_init(&gsub->points, 1, 32); ga_init(&gsub->polylines, 1, 32); ga_init(&gsub->polygons, 1, 32); gsub->subfile = subf; } return gsub; } static void gar_subdiv_free(struct gar_subdiv *sd) { if (sd->loaded) { if (sd->refcnt !=0) { log(1, "Trying to free subdiv with refcnt:%d\n", sd->refcnt); return; } gar_free_subdiv_data(sd); } ga_free(&sd->points); ga_free(&sd->polylines); ga_free(&sd->polygons); free(sd); } static ssize_t gar_get_rgnoff(struct gar_subfile *sub, ssize_t *l) { ssize_t rgnoff = gar_subfile_offset(sub, "RGN"); struct hdr_rgn_t rgnhdr; int rc; struct gimg *g = sub->gimg; if (glseek(g, rgnoff, SEEK_SET) != rgnoff) { log(1, "Error can not seek to %zd\n", rgnoff); return 0; } rc = gread(g, &rgnhdr, sizeof(struct hdr_rgn_t)); if (rc == sizeof(struct hdr_rgn_t)) { if (strncmp("GARMIN RGN", rgnhdr.hsub.type, 10)) { log(1, "RGN: Invalid header type: [%s]\n", rgnhdr.hsub.type); return 0; } *l = rgnhdr.length; log(11, "rgn header len: %d offset:%d\n",rgnhdr.hsub.length, rgnhdr.offset); rgnoff = gar_subfile_baseoffset(sub, "RGN"); sub->rgnbase = rgnoff; if (rgnhdr.hsub.length > 8 + sizeof(rgnhdr.hsub)) { sub->rgnoffset2 = rgnhdr.offset2; sub->rgnlen2 = rgnhdr.length2; sub->rgnoffset3 = rgnhdr.offset3; sub->rgnlen3 = rgnhdr.length3; sub->rgnoffset4 = rgnhdr.offset4; sub->rgnlen4 = rgnhdr.length4; sub->rgnoffset5 = rgnhdr.offset5; sub->rgnlen5 = rgnhdr.length5; log(11, "o1:%x %x\n",rgnhdr.offset, rgnhdr.length); log(11, "o2:%x %x\n",rgnhdr.offset2, rgnhdr.length2); log(11, "o3:%x %x\n",rgnhdr.offset3, rgnhdr.length3); log(11, "o4:%x %x\n",rgnhdr.offset4, rgnhdr.length4); log(11, "o5:%x %x\n",rgnhdr.offset5, rgnhdr.length5); } return rgnoff+rgnhdr.offset; } return 0; } static int gar_load_ml_subdivs(struct gar_subfile *subf, struct gar_maplevel *ml, struct hdr_tre_t *tre, struct gar_subdiv **gsub_prev, ssize_t rgnoff, int last) { int i; struct gimg *g = subf->gimg; struct tre_subdiv_next_t subn; struct tre_subdiv_t subl; int s = sizeof(struct tre_subdiv_next_t); int s1 = sizeof(struct tre_subdiv_t); struct gar_subdiv *gsub = NULL; if (!last) { log(11, "Reading level:%d reading:%d\n", ml->ml.level, ml->ml.nsubdiv); for (i=0; i < ml->ml.nsubdiv; i++) { if (gread(g, &subn, s) != s) { log(1, "Error reading subdiv %d of maplevel:%d\n", i, ml->ml.level); return -1; } gsub = gar_subdiv_alloc(subf); if (!gsub) { log(1, "Can not allocate subdivision!\n"); return -1; } gsub->n = subf->subdividx++; // index in all subdivs gsub->next = subn.next; if (ml->ml.bits < 24) gsub->shift = 24 - ml->ml.bits; gar_parse_subdiv(gsub, &subn.tresub); log(15, "idx: %d start: %04X next_rgn: %04X(%d)\n", gsub->n, gsub->rgn_start,gsub->next,gsub->next); gsub->rgn_start += rgnoff; // skip if this is the first entry if (*gsub_prev){ (*gsub_prev)->rgn_end = gsub->rgn_start; log(15,"prev start:%04X end: %04X size: %d\n", (*gsub_prev)->rgn_start, (*gsub_prev)->rgn_end, (*gsub_prev)->rgn_end - (*gsub_prev)->rgn_start); if ((*gsub_prev)->rgn_start > (*gsub_prev)->rgn_end) { log(10,"invalid start and end\n"); } } ga_append(&ml->subdivs, gsub); *gsub_prev = gsub; gsub->rgn_end = 0; } } else { // level 0 are shorter log(11, "Reading level:%d reading:%d\n", ml->ml.level, ml->ml.nsubdiv); for (i=0; i < ml->ml.nsubdiv; i++) { if (gread(g, &subl, s1) != s1) { log(1, "Error reading subdiv %d of maplevel:%d\n", i, ml->ml.level); return -1; } gsub = gar_subdiv_alloc(subf); if (!gsub) { log(1, "Can not allocate subdivision!\n"); return -1; } gsub->n = subf->subdividx++; // index in the level not in all gsub->next = 0; if (ml->ml.bits < 24) gsub->shift = 24 - ml->ml.bits; gar_parse_subdiv(gsub, &subl); gsub->rgn_start += rgnoff; gsub->rgn_end = 0; // skip if this is the first entry if (*gsub_prev){ (*gsub_prev)->rgn_end = gsub->rgn_start; } ga_append(&ml->subdivs, gsub); *gsub_prev = gsub; } } return 0; } static int gar_load_subdivs(struct gar_subfile *sub, struct hdr_tre_t *tre) { int i; ssize_t off; struct gar_subdiv *gsub_prev = NULL; ssize_t rgnlen = sub->rgnlen; ssize_t rgnoff = sub->rgnoffset; int last = 0; struct gimg *g = sub->gimg; off = gar_subfile_baseoffset(sub, "TRE"); off += tre->tre2_offset; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error can not seek to %zd\n", off); return -1; } sub->subdividx = 1; for (i=0; i < sub->nlevels; i++) { if (i == sub->nlevels - 1) last = 1; if (gar_load_ml_subdivs(sub, sub->maplevels[i], tre, &gsub_prev, rgnoff, last) < 0) { // return -1; } ga_trim(&sub->maplevels[i]->subdivs); } if (gsub_prev) { gsub_prev->rgn_end = rgnoff + rgnlen; // log(10, "RGNEND: %04X\n",gsub_prev->rgn_end); } if (sub->gimg->gar->cfg.debugmask&DBGM_NTMAP) gar_parse_subdiv_nt(sub, tre); return sub->nlevels; } static struct gar_maplevel *gar_alloc_maplevel(int base) { struct gar_maplevel *ml; ml = calloc(1, sizeof(*ml)); if (!ml) return NULL; ga_init(&ml->subdivs, base, 1024); return ml; } #define LOCKEDMSG \ "\n\n\n===================================================\n" \ "Sorry, map contains locked / encypted data.\n" \ "And probably its license do NOT allow you to use it\n" \ "with any compatible software, only Garmin's\n" \ "Unlocking maps in MapSource do not unlock them for\n" \ "use with different products.\n" \ "===================================================\n\n" static int gar_load_maplevels(struct gar_subfile *sub, struct hdr_tre_t *tre) { ssize_t off; struct gar_maplevel *ml; int s = sizeof(struct tre_map_level_t); u_int32_t nlevels; struct gimg *g = sub->gimg; int i; unsigned char buf[tre->tre1_size]; unsigned char *cp = buf; int totalsubdivs = 0; int base = 1; off = gar_subfile_baseoffset(sub, "TRE"); off += tre->tre1_offset; if (glseek(g, off, SEEK_SET) != off) { log(1, "Error can not seek to %zd\n", off); return -1; } if (gread(g, buf, tre->tre1_size) != tre->tre1_size) { log(1, "Error reading map levels\n"); return -1; } fixup_tre(tre, buf); if (tre->hsub.flag & 0x80) { log(1, "%s", LOCKEDMSG); return -1; } nlevels = tre->tre1_size / s; log(10, "Have %d levels\n", nlevels); sub->maplevels = calloc(nlevels, sizeof(struct tre_map_level_t *)); if (!sub->maplevels) { log(1, "Error can not allocate map levels!\n"); return -1; } sub->nlevels = nlevels; for (i = 0; i < nlevels; i++) { ml = gar_alloc_maplevel(base); if (!ml) { log(1, "Error can not allocate map level!\n"); return -1; } memcpy(&ml->ml, cp, s); cp+=s; log(10, "ML[%d] level=%d inherited=%d bits:%d nsubdiv=%d unkn=[%d %d %d]\n", i, ml->ml.level, ml->ml.inherited, ml->ml.bits, ml->ml.nsubdiv, ml->ml.bit4,ml->ml.bit5,ml->ml.bit6); sub->maplevels[i] = ml; /* FIXME: The document states that * all subdivs are indexed from 1 * BUT in the POI records: * 'this two byte integer implies that there can not be * more than 65535 subdivisions in a map level' * and it's not clear in which map level */ totalsubdivs += ml->ml.nsubdiv; base += ml->ml.nsubdiv; } return totalsubdivs; } static struct gar_subfile *gar_alloc_subfile(struct gimg *g, char *mapid) { struct gar_subfile *sub; sub = calloc(1, sizeof(*sub)); if (!sub) return NULL; sub->gimg = g; sub->mapid = strdup(mapid); if (!sub->mapid) { free(sub); return NULL; } if (*sub->mapid == 'I') { char *ptr = sub->mapid+1; char *eptr; sub->id = strtol(ptr, &eptr, 16); } else { sub->id = atoi(sub->mapid); } if (!sub->id) { if (g->tdbbasemap) { /* our mapid is probably a string so since it's the basemap * give it the number one */ sub->id = 1; } } list_init(&sub->l); sub->subdividx = 1; return sub; } static void gar_free_subfile_data(struct gar_subfile *f) { int i,j,n; struct gar_subdiv *sd; struct gar_maplevel *ml; #if 1 /* FIXME: Used SDs are freed automagicaly * but rest are freed here, get_objects and friends * needs to be FIXED */ if (f->maplevels) { for (i = 0; i < f->nlevels; i++) { ml = f->maplevels[i]; n = ga_get_count(&ml->subdivs); for (j = 0; j < n; j++) { sd = ga_get(&ml->subdivs, j); if (sd) gar_subdiv_free(sd); } // free(f->maplevels[i]); ga_empty(&ml->subdivs); } // free(f->maplevels); } #endif f->subdividx = 1; gar_free_points_overview(f); gar_free_polylines_overview(f); gar_free_polygons_overview(f); gar_free_lbl(f); gar_free_net(f); gar_free_srch(f); f->loaded = 0; } static void gar_free_subfile(struct gar_subfile *f) { int i,j,n; struct gar_subdiv *sd; struct gar_maplevel *ml; if (f->mapid) free(f->mapid); if (f->maplevels) { for (i = 0; i < f->nlevels; i++) { ml = f->maplevels[i]; n = ga_get_count(&ml->subdivs); for (j = 0; j < n; j++) { sd = ga_get(&ml->subdivs, j); gar_subdiv_free(sd); } ga_free(&ml->subdivs); free(f->maplevels[i]); } free(f->maplevels); } gar_free_points_overview(f); gar_free_polylines_overview(f); gar_free_polygons_overview(f); gar_free_lbl(f); gar_free_net(f); gar_free_srch(f); free(f); } int gar_load_subfile_data(struct gar_subfile *sub) { struct hdr_tre_t tre; struct gimg *g = sub->gimg; ssize_t off; int rc; off = gar_subfile_offset(sub, "TRE"); if (!off) { log(1, "Error can not find TRE file!\n"); goto out_err; } if (glseek(g, off, SEEK_SET) != off) { log(1, "Error can not seek to %zd\n", off); goto out_err; } rc = gread(g, &tre, sizeof(struct hdr_tre_t)); if (rc != sizeof(struct hdr_tre_t)) { log(1, "Error can not read TRE header!\n"); goto out_err; } if (tre.hsub.length <= 120) { tre.tre8_size = tre.tre8_offset = 0; tre.tre7_size = tre.tre7_offset = 0; } if (tre.hsub.length <= 188) { tre.tre9_size = tre.tre9_offset = 0; tre.tre10_size = tre.tre10_offset = 0; } gar_init_lbl(sub); gar_init_net(sub); gar_load_polylines_overview(sub, &tre); gar_load_polygons_overview(sub, &tre); gar_load_points_overview(sub, &tre); gar_load_subdivs(sub, &tre); sub->loaded = 1; // gar_load_subdivs_data(sub); return 0; out_err: return -1; } static void gar_calculate_zoom_levels(struct gimg *g) { int nbits[25]; int j,i, fb = 0, lb = 0; struct gar_subfile *sub; struct gar_maplevel *ml; for (i = 0; i < 25; i++) nbits[i] = 0; list_for_entry(sub, &g->lsubfiles, l) { for (i = 0; i < sub->nlevels; i++) { ml = sub->maplevels[i]; if (ml->ml.inherited) continue; nbits[ml->ml.bits] = 1; } } i = 0; for (j = 0; j < 25; j++) { if (nbits[j]) { i++; if (!fb) fb = j; lb = j; } } log(6, "Have %d levels base bits=%d bits=%d\n", i, fb, lb - fb); g->basebits = fb; g->zoomlevels = lb - fb; g->minlevel = 100; g->maxlevel = 0; list_for_entry(sub, &g->lsubfiles, l) { if (sub->basemap) { for (i = 0; i < sub->nlevels; i++) { ml = sub->maplevels[i]; if (ml->ml.inherited) continue; if (g->minlevel > ml->ml.level) g->minlevel = ml->ml.level; if (g->maxlevel < ml->ml.level) g->maxlevel = ml->ml.level; } } } log(9, "Minlevel=%d Maxlevel=%d\n", g->minlevel, g->maxlevel); } static int gar_subfile_have_bits(struct gar_subfile *sub, int bits) { struct gar_maplevel *ml; int i; for (i = 0; i < sub->nlevels; i++) { ml = sub->maplevels[i]; if (ml->ml.inherited) continue; if (ml->ml.bits < bits) return 1; } return 0; } static int gar_check_basemap(struct gar_subfile *sub) { if (1 || gar_subfile_have_bits(sub, 18)) { sub->basemap = 1; sub->gimg->north = sub->north; sub->gimg->east = sub->east; sub->gimg->south = sub->south; sub->gimg->west = sub->west; log(6, "%s selected as a basemap\n", sub->mapid); return 1; } else { log(9, "%s not used as basemap, no enough bits\n", sub->mapid); } return 0; } /* this is uneeded */ static int gar_select_basemaps(struct gimg *g) { struct gar_subfile *sub; int havebase = 0; int id; unsigned int minid = ~0; char *ptr, *eptr; log(11, "Selecting basemap ...\n"); list_for_entry(sub, &g->lsubfiles, l) { if (*sub->mapid == 'I') { ptr = sub->mapid+1; id = strtol(ptr, &eptr, 16); if (!(*ptr && *eptr == '\0')) { havebase = gar_check_basemap(sub); } continue; } if (*sub->mapid >= 'A' && *sub->mapid <= 'Z') { havebase = gar_check_basemap(sub); } } if (havebase) return 1; list_for_entry(sub, &g->lsubfiles, l) { if (*sub->mapid < '0' || *sub->mapid > '9') { havebase = gar_check_basemap(sub); } } if (havebase) return 1; list_for_entry(sub, &g->lsubfiles, l) { id = atoi(sub->mapid); if (id < minid) minid = id; } list_for_entry(sub, &g->lsubfiles, l) { id = atoi(sub->mapid); if (id == minid) { havebase = gar_check_basemap(sub); if (havebase) break; } } #if 0 if (!havebase) { log(1, "Warning no basemap found guessing\n"); list_for_entry(sub, &g->lsubfiles, l) { minid = atoi(sub->mapid); havebase = gar_check_basemap(sub); if (havebase) break; } } #endif return minid; } /* order subfile by drawprio higher at the begining */ static void gar_register_subfile(struct gimg *g, struct gar_subfile *sub) { struct gar_subfile *s; if (list_empty(&g->lsubfiles)) { list_append(&sub->l, &g->lsubfiles); return; } list_for_entry(s, &g->lsubfiles, l) { if (s->drawprio >= sub->drawprio) { list_prepend(&sub->l, &s->l); return; } } list_append(&sub->l, &g->lsubfiles); } static void gar_log_tre_header(struct hdr_tre_t *tre) { log(11, "TRE mapID: %d[%08X] draw priority: %d\n", tre->mapID, tre->mapID, tre->drawprio); log(11, "TRE header: len= %u, TRE1 off=%u,size=%u TRE2 off=%u, size=%u\n", tre->hsub.length, tre->tre1_offset, tre->tre1_size, tre->tre2_offset, tre->tre2_size); if (tre->hsub.length > 120) { log(11, "TRE tre7= %u len = %u rec=%d\n", tre->tre7_offset, tre->tre7_size, tre->tre7_rec_size); log(11, "TRE tre8= %u len = %u rec=%d\n", tre->tre8_offset, tre->tre8_size, tre->tre8_rec_size); } if (tre->hsub.length > 188) { log(11, "TRE tre9= %u len = %u rec=%d\n", tre->tre9_offset, tre->tre9_size, tre->tre9_rec_size); log(11, "TRE tre10= %u len = %u rec=%d\n", tre->tre10_offset, tre->tre10_size, tre->tre10_rec_size); } log(19, "TRE ver=[%02X] flag=[%02X]\n", tre->hsub.byte0x0000000C, tre->hsub.flag); log(19, "3B-3E[%02X][%02X][%02X][%02X]\n", tre->byte0x0000003B_0x0000003E[0], tre->byte0x0000003B_0x0000003E[1], tre->byte0x0000003B_0x0000003E[2], tre->byte0x0000003B_0x0000003E[3]); log(19, "41-49[%02X][%02X][%02X][%02X]" "[%02X][%02X][%02X][%02X]" "[%02X]\n", tre->byte0x00000041_0x00000049[0], tre->byte0x00000041_0x00000049[1], tre->byte0x00000041_0x00000049[2], tre->byte0x00000041_0x00000049[3], tre->byte0x00000041_0x00000049[4], tre->byte0x00000041_0x00000049[5], tre->byte0x00000041_0x00000049[6], tre->byte0x00000041_0x00000049[7], tre->byte0x00000041_0x00000049[8]); log(19, "54-57[%02X][%02X][%02X][%02X]\n", tre->byte0x00000054_0x00000057[0], tre->byte0x00000054_0x00000057[1], tre->byte0x00000054_0x00000057[2], tre->byte0x00000054_0x00000057[3]); log(19, "62-65[%02X][%02X][%02X][%02X]\n", tre->byte0x00000062_0x00000065[0], tre->byte0x00000062_0x00000065[1], tre->byte0x00000062_0x00000065[2], tre->byte0x00000062_0x00000065[3]); log(19, "70-73[%02X][%02X][%02X][%02X]\n", tre->byte0x00000070_0x00000073[0], tre->byte0x00000070_0x00000073[1], tre->byte0x00000070_0x00000073[2], tre->byte0x00000070_0x00000073[3]); if (tre->hsub.flag & 0x80){ log(11, "TRE key: 9A:%02X 9B:%02X 9C:%02X 9D:%02X 9E:%02X 9F:%02X\n", tre->key[0], tre->key[1], tre->key[2], tre->key[3], tre->key[4], tre->key[5] ); } } int gar_load_subfiles(struct gimg *g) { ssize_t off, off1; int rc,j; struct hdr_tre_t tre; struct gar_subfile *sub; int32_t i32; char **imgs; int nimgs; char *cp; char buf[20]; int mapsets=0; char *ap; imgs = gar_file_get_subfiles(g, &nimgs, "TRE"); log(4, "Have %d mapsets\n", nimgs); if (!imgs) return -1; if (gar_debug_level >= 7) { for (rc = 0; rc < nimgs; rc++) { strcpy(buf, imgs[rc]); cp = strchr(buf, '.'); if (!cp) continue; *cp = '\0'; log(1, "mapset: %s\n", buf); } } for (j = 0; j < nimgs; j++) { strcpy(buf, imgs[j]); cp = strchr(buf, '.'); if (!cp) continue; *cp = '\0'; log(5, "Loading mapset id: %s\n", buf); sub = gar_alloc_subfile(g, buf); if (!sub) return -1; off = gar_subfile_offset(sub, "TRE"); if (!off) { log(1, "Error can not find TRE file!\n"); goto out_err; } if (glseek(g, off, SEEK_SET) != off) { log(1, "Error can not seek to %zd\n", off); goto out_err; } rc = gread(g, &tre, sizeof(struct hdr_tre_t)); if (rc != sizeof(struct hdr_tre_t)) { log(1, "Error can not read TRE header!\n"); goto out_err; } if (strncmp("GARMIN TRE", tre.hsub.type, 10)) { log(1, "Invalid file type:[%s] at %d\n", tre.hsub.type, off); goto out_err; } gar_log_file_date(11, "TRE Created", &tre.hsub); if (tre.hsub.length < 116) tre.mapID = 0; else sub->id = tre.mapID; sub->drawprio = tre.drawprio; if (gar_debug_level > 10) { gar_log_tre_header(&tre); } if (tre.hsub.length <= 120) { tre.tre8_size = tre.tre8_offset = 0; tre.tre7_size = tre.tre7_offset = 0; } if (tre.hsub.length <= 188) { tre.tre9_size = tre.tre9_offset = 0; tre.tre10_size = tre.tre10_offset = 0; } log(10, "POI_flags=%04X\n",tre.POI_flags); if (tre.POI_flags & (1<<1)) log(10, "Show street before street number\n"); if (tre.POI_flags & (1<<2)) log(10, "Show Zip before city\n"); sub->transparent = tre.POI_flags & 0x0001; i32 = get_u24(&tre.northbound); sub->north = SIGN3B(i32); i32 = get_u24(&tre.eastbound); sub->east = SIGN3B(i32); i32 = get_u24(&tre.southbound); sub->south = SIGN3B(i32); i32 = get_u24(&tre.westbound); sub->west = SIGN3B(i32); log(5, "Bounds\n"); log(5, "Boundaries - North: %fC, East: %fC, South: %fC, West: %fC\n", GARDEG(sub->north), GARDEG(sub->east), GARDEG(sub->south), GARDEG(sub->west)); // FIXME calculate area area= (pi/180)R^2 |sin(lat1)-sin(lat2)| |lon1-lon2| log(5, "Transparent: %s, Area: %.2f m\n", sub->transparent ? "Yes" : "No", sub->area); if (sub->east == sub->west){ sub->east = -sub->east; } sub->rgnoffset = gar_get_rgnoff(sub, &sub->rgnlen); if (!sub->rgnoffset) { log(1, "Can not find RGN file\n"); goto out_err; } off1 = gar_subfile_offset(sub, "NET"); if (off1) sub->have_net = 1; off1 = gar_subfile_offset(sub, "NOD"); if (off1) sub->have_nod = 1; rc = gar_load_maplevels(sub, &tre); if (rc<0) { log(1, "Error loading map levels!\n"); goto skip_subfile; } if (tre.tre7_size) { // verify map levels if (tre.tre7_size/tre.tre7_rec_size != rc + 1) { log(1, "Error in maplevels have %d must be %d\n" "Are you trying to use an \"unlocked/cracked map\"???\n", rc + 1, tre.tre7_size/tre.tre7_rec_size); goto skip_subfile; } else { log(9, "Map levels match total %d subdivs\n", rc); } } if (g->gar->cfg.opm != OPM_GPS) { gar_init_lbl(sub); gar_init_net(sub); gar_load_polylines_overview(sub, &tre); gar_load_polygons_overview(sub, &tre); gar_load_points_overview(sub, &tre); gar_load_subdivs(sub, &tre); gar_load_subdivs_data(sub); gar_init_srch(sub, 0); gar_init_srch(sub, 1); if (gar_debug_level > 10) { if (sub->net) { // gar_net_parse_nod3(sub); gar_load_roadnetwork(sub); } } } gar_register_subfile(g, sub); mapsets++; continue; skip_subfile: log(1, "ERROR Loading map id: %s\n", buf); gar_free_subfile(sub); } g->mapsets = mapsets; gar_select_basemaps(g); gar_calculate_zoom_levels(g); if (!g->gar->tdbloaded) { // XXX copy basemaps bounds to g->bounds } gclose(g); free(imgs); return 0; out_err: gclose(g); if (imgs) free(imgs); gar_free_subfile(sub); return -1; } void gar_subfile_ref(struct gar_subfile *s) { s->refcnt ++; // ref img } void gar_subfile_unref(struct gar_subfile *s) { s->refcnt --; // if (s->refcnt == 0) { // gar_free_subfile_data(s); // } } void gar_subfile_unload(struct gar_subfile *s) { if (s->refcnt == 0 && s->loaded) { gar_free_subfile_data(s); } } static void gar_subfiles_unload(struct gimg *g) { struct gar_subfile *sub; list_for_entry(sub, &g->lsubfiles, l) { gar_subfile_unload(sub); } } static struct gmap *gar_alloc_gmap(void) { struct gmap *gm; gm = calloc(1, sizeof(*gm)); if (!gm) return gm; /* Initialize default draw order for polygons */ gm->draworder = calloc(1, sizeof(*gm->draworder)); gar_init_draworder(gm->draworder, 4); gar_set_default_poly_order(gm->draworder); return gm; } void gar_free_gmap(struct gmap *g) { int i; struct gar_subfile *sub; for (i=0; i < g->lastsub; i++) { sub = g->subs[i]; gar_subfile_unref(sub); // Disable caching temporary gar_subfiles_unload(sub->gimg); gclose(sub->gimg); } g->subs = NULL; g->zoomlevels = 0; g->basebits = 0; g->minlevel = 0; g->maxlevel = 0; g->lastsub = 0; g->subfiles = 0; if (g->subs) free(g->subs); //free(g); } struct gar_subfile *gar_find_subfile_byid(struct gimg *g, unsigned int id) { struct gar_subfile *sub; list_for_entry(sub, &g->lsubfiles, l) { if (sub->id == id) return sub; } return NULL; } static int gar_find_subs(struct gmap *files, struct gimg *g, struct gar_rect *rect, int flags) { struct gar_subfile *sub; struct gar_rect r; char buf[256]; int nf = 0, idx = 0; idx = files->lastsub; list_for_entry(sub, &g->lsubfiles, l) { if (flags & GO_GET_ROUTABLE && !sub->have_net) continue; if (rect) { r.lulat = sub->north; //DEG(sub->north); r.lulong = sub->west; //DEG(sub->west); r.rllat = sub->south; //DEG(sub->south); r.rllong = sub->east; //DEG(sub->east); sprintf(buf, "Checking %s", sub->mapid); gar_rect_log(12, buf, &r); } if (!rect || gar_rects_intersectboth(rect, &r)) { log(5, "Found subfile %d: [%s] prio=%d\n", idx, sub->mapid, sub->drawprio); gar_rect_log(15, "subfile", &r); gar_subfile_ref(sub); files->subs[idx] = sub; idx++; nf++; if (idx == files->subfiles ) break; } else gar_subfile_unload(sub); } log(2, "Found %d subfiles\n", nf); files->lastsub = idx; return nf; } static int gar_prio_comp(const void *a, const void *b) { return (*(struct gar_subfile **)a)->drawprio - (*(struct gar_subfile **)b)->drawprio; } // public api struct gmap *gar_find_subfiles(struct gar *gar, void *select, int flags) { struct gimg *g; struct gmap *files; struct gar_subfile **rsub; struct gar_rect *rect = select; int fnd; files = gar->gmap; if (!files) { files = gar_alloc_gmap(); if (!files) return NULL; gar->gmap = files; } if (flags&GO_GET_SEARCH) { //goto do_search; // FIXME: If we have object use just its subfile // FIXME: Use only the indexed images from mdr sect1 rect = NULL; } if (rect) gar_rect_log(5, "looking for", rect); if (gar->tdbloaded) { files->zoomlevels = gar->zoomlevels; files->basebits = gar->basebits; } list_for_entry(g, &gar->limgs,l) { if ((flags&GO_GET_SEARCH) && g->mdr) { log(7, "Using MDR\n"); if (gar_mdr_get_files(files, g) > 0) return files; } if (rect && gar->tdbloaded) { struct gar_rect r; r.lulat = g->north; r.lulong = g->west; r.rllat = g->south; r.rllong = g->east; if (!gar_rects_intersectboth(rect, &r)) { gar_subfiles_unload(g); continue; } } if (!gar->tdbloaded) { files->zoomlevels = g->zoomlevels; files->basebits = g->basebits; files->minlevel = g->minlevel; files->maxlevel = g->maxlevel; } rsub = realloc(files->subs, (files->subfiles + g->mapsets) * sizeof(struct gar_subfile *)); if (rsub) { files->subs = rsub; files->subfiles += g->mapsets; } else { break; } fnd = gar_find_subs(files, g, rect, flags); if (fnd) { if (rect) { log(15, "Found subfile for %f %f %f %f\n", rect->lulat, rect->lulong, rect->rllat, rect->rllong); } } } if (!files->lastsub) { gar_free_gmap(files); return NULL; } if (files->lastsub > 1) { qsort(&files->subs[0], files->lastsub, sizeof(struct gar_subfile *), gar_prio_comp); } return files; } libgarmin-0~svn320/src/garmin_rgn.h000066400000000000000000000050631112544465000174220ustar00rootroot00000000000000#include "list.h" #include "array.h" #include "GarminTypedef.h" struct gimg; struct gar_subdiv { struct gar_subfile *subfile; unsigned int refcnt; u_int16_t n; u_int16_t next; // section of next level unsigned terminate :1; u_int32_t rgn_start; u_int32_t rgn_end; u_int32_t rgn2_start; u_int32_t rgn2_end; u_int32_t rgn3_start; u_int32_t rgn3_end; u_int32_t rgn4_start; u_int32_t rgn4_end; u_int32_t rgn5_start; u_int32_t rgn5_end; u_int8_t unknown1; unsigned haspoints :1, hasidxpoints :1, haspolylines :1, haspolygons : 1, loaded: 1; u_int32_t icenterlng; u_int32_t icenterlat; int north; // north boundary of area covered by this subsection int east; // east boundary of area covered by this subsection int south; // south boundary of area covered by this subsection int west; // west boundary of area covered by this subsection u_int32_t shift; struct garray points; struct garray polylines; struct garray polygons; }; struct gar_maplevel { struct tre_map_level_t ml; struct garray subdivs; }; struct mlfilter { unsigned short type; unsigned char maxlevel; unsigned char __padd; }; struct region_def { int country; char *name; }; struct city_def { int point_idx; int subdiv_idx; int region_idx; char *label; }; struct zip_def { char *code; }; struct gar_net_info; struct gar_subfile { list_t l; int loaded; unsigned int refcnt; struct gimg *gimg; unsigned int id; unsigned char drawprio; ssize_t rgnoffset; ssize_t rgnlen; ssize_t rgnbase; ssize_t rgnoffset2; ssize_t rgnlen2; ssize_t rgnoffset3; ssize_t rgnlen3; ssize_t rgnoffset4; ssize_t rgnlen4; ssize_t rgnoffset5; ssize_t rgnlen5; unsigned transparent:1, basemap:1, have_net:1, have_nod:1; double north; double east; double south; double west; double area; int subdividx; int nlevels; struct gar_maplevel **maplevels; struct gar_lbl_t *lbl; struct gar_net_info *net; char **countries; int ccount; struct region_def **regions; int rcount; struct city_def **cities; int cicount; struct zip_def **zips; int czips; struct mlfilter *fpoint; int nfpoint; struct mlfilter *fpolyline; int nfpolyline; struct mlfilter *fpolygone; int nfpolygone; int lbl_countries; int lbl_regions; int lbl_cities; int lbl_zips; char *mapid; }; int gar_load_subfiles(struct gimg *g); int gar_load_subfile_data(struct gar_subfile *sub); void gar_subfile_ref(struct gar_subfile *s); void gar_subfile_unref(struct gar_subfile *s); void gar_subfile_unload(struct gar_subfile *s); struct gar_subfile *gar_find_subfile_byid(struct gimg *g, unsigned int id); libgarmin-0~svn320/src/garmin_route.c000066400000000000000000000151371112544465000177700ustar00rootroot00000000000000/* Copyright (C) 2007,2008 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "GarminTypedef.h" #include "garmin_rgn.h" #include "garmin_net.h" #include "garmin_nod.h" #include "garmin_lbl.h" struct gar_route { struct gar_graph *graph; struct node *pnode; unsigned int posmapid; unsigned int posobjid; int posidx; struct node *dnode; unsigned int dstmapid; unsigned int dstobjid; int dstidx; int route_flags; int vehicle_type; struct gar_road *proad; struct gar_road *droad; }; #if 0 struct gar_route_request { struct gar_route *route; unsigned int posmapid; unsigned int posobjid; int posidx; unsigned int dstmapid; unsigned int dstobjid; int dstidx; int route_flags; int vehicle_type; }; #endif static struct gar_road *gar_find_road_byid(struct gar *gar, int mapid, int objid) { struct gar_subfile *sub; struct gar_road *gr; int sdidx, idx; sub = gar_subfile_get_by_mapid(gar, mapid); if (!sub) return NULL; log(1, "Found subfile:[%d/%x]\n", sub->id, sub->id); sdidx = objid >> 16; idx = (objid >> 8) & 0xFF; gr = gar_get_road_by_id(sub, sdidx, idx); return gr; } static int gar_get_road_nodes(struct gar_route *route, struct gar_road *road ,struct node *n, struct node **ret) { int j; int rc = 0; struct roadptr *rp; for (j=0; j < n->narcs; j++) { rp = gar_cp_idx2road(n->cpoint, n->arcs[j].roadidx); if (!rp) { log(1, "arc:%d do not have rp\n", j); } else { if (get_u24(rp->off) == road->offset) { ret[rc++] = gar_get_node(route->graph, n->arcs[j].dest->offset); } } } return rc; } static struct node *gar_select_node(struct gar_route *route, struct gar_road *road, int pos) { struct node *n, *n1, *n2; struct node *roadnodes[512];; struct node *own[512]; int nrn = 1, nown; struct roadptr *rp; int j,k,p; if (!road->nod) return NULL; /* This is the first road node */ n = gar_get_node(route->graph, road->nod->nodesoff); if (!n) return NULL; if (!gar_read_node(route->graph, NULL, n)) { log(1, "Failed to read node:%d\n",road->nod->nodesoff); return NULL; } roadnodes[0] = n; nown = gar_get_road_nodes(route, road, n, own); log(1, "Own from %d are %d\n", n->offset, nown); { int m; for (m=0; m < nown; m++) log(1, "%d\n", own[m]->offset); } for (j=0; j < n->narcs; j++) { rp = gar_cp_idx2road(n->cpoint, n->arcs[j].roadidx); if (!rp) { log(1, "arc:%d do not have rp\n", j); } else { if (get_u24(rp->off) == road->offset) { n1 = gar_get_node(route->graph, n->arcs[j].dest->offset); roadnodes[nrn++] = n1; if (!gar_read_node(route->graph, NULL, n1)) { log(1, "Failed to read node:%d\n",n1->offset); return NULL; } nown = gar_get_road_nodes(route, road, n1, own); log(1, "Own from %d are %d\n", n1->offset, nown); { int m; for (m=0; m < nown; m++) log(1, "%d\n", own[m]->offset); } } } } for (j=1; j < nrn; j++) { n1 = roadnodes[j]; log(1, "%d\n", n1->offset); if (!gar_read_node(route->graph, NULL, n1)) { log(1, "Failed to read node:%d\n",n1->offset); return NULL; } for (k=0; k < n1->narcs; k++) { rp = gar_cp_idx2road(n1->cpoint, n1->arcs[k].roadidx); if (!rp) { log(1, "arc:%d do not have rp\n", k); } else { if (get_u24(rp->off) == road->offset) { int add = 1; n2 = gar_get_node(route->graph, n1->arcs[k].dest->offset); for (p = 0; p < nrn; p++) { if (roadnodes[p] == n2) { add = 0; break; } } if (add) roadnodes[nrn++] = n2; } } } } log(1, "Road nodes:%d\n", nrn); for (j=0; j < nrn; j++) { log(1, "%d\n", roadnodes[j]->offset); } if (pos < nrn) { log(1, "Selecting node %d: %d\n", pos, roadnodes[pos]->offset); return roadnodes[j]; } else { log(1, "have %d but pos is %d\n", nrn, pos); } return n; } void gar_free_route(struct gar_route *route) { if (route->graph) gar_free_graph(route->graph); free(route); } struct gar_route *gar_route(struct gar *gar, struct gar_route_request *grr) { struct gar_route *route = NULL; struct gar_road *proad; struct gar_road *droad; log(1, "RT: request %s from %d:%d:%d to %d:%d:%d\n", grr->route ? "update" : "new", grr->posmapid, grr->posobjid, grr->posidx, grr->dstmapid, grr->dstobjid, grr->dstidx ); if (!grr->route) { route = calloc(1, sizeof(*route)); route->dstidx = -1; route->posidx = -1; } else { route = grr->route; } if (!route) return NULL; if (route->posmapid != grr->posmapid || route->posobjid != grr->posobjid) { proad = gar_find_road_byid(gar, grr->posmapid, grr->posobjid); if (proad) { log(1, "FROM: pos=%d ROAD:",grr->posidx); gar_log_road_info(proad); route->proad = proad; route->posmapid = grr->posmapid; route->posobjid = grr->posobjid; route->posidx = -1; } else { log(1, "Can not find position road\n"); } } if (route->dstmapid != grr->dstmapid || route->dstobjid != grr->dstobjid) { droad = gar_find_road_byid(gar, grr->dstmapid, grr->dstobjid); if (droad) { log(1, "TO: pos=%d ROAD:",grr->dstidx); gar_log_road_info(droad); route->droad = droad; route->dstmapid = grr->dstmapid; route->dstobjid = grr->dstobjid; route->dstidx = -1; } else { log(1, "Can not find destination road\n"); } } if (!route->proad || !route->droad) { gar_free_route(route); return NULL; } if (route->proad->sub != route->droad->sub) { log(1, "Can not route across subfiles yet\n"); gar_free_route(route); return NULL; } if (!route->graph) { route->graph = gar_alloc_graph(route->proad->sub); } if (route->posidx != grr->posidx) { route->posidx = grr->posidx; route->pnode = gar_select_node(route, route->proad, route->posidx); } if (route->dstidx != grr->dstidx) { route->dstidx = grr->dstidx; route->dnode = gar_select_node(route, route->droad, route->dstidx); } return route; } libgarmin-0~svn320/src/garmin_subdiv.c000066400000000000000000000404451112544465000201260ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "bsp.h" #include "garmin_rgn.h" #include "garmin_lbl.h" #include "garmin_subdiv.h" struct sign_info_t { u_int32_t sign_info_bits; int x_has_sign; int nx; int y_has_sign; int ny; int extrabit; }; static void init_si(struct sign_info_t *si) { si->sign_info_bits = 2; si->x_has_sign = 1; si->nx = 0; si->y_has_sign = 1; si->ny = 0; } //---------------------------------------------------------------------- // signinfor parsing shamelessly stolen from imgdecode //---------------------------------------------------------------------- static int _bits_per_coord (u_int8_t base, int is_signed) { int n= 2; if ( base <= 9 ) n+= base; else n+= (2*base-9); if ( is_signed ) ++n; return n; } static void bits_per_coord (u_int8_t base, u_int8_t bfirst, int extra_bit, int *blong, int *blat, struct sign_info_t *si) { int x_sign_same, y_sign_same; int sign_bit; // Get bits per longitude si->extrabit = !!extra_bit; x_sign_same= bfirst & 0x1; if ( x_sign_same ) { si->x_has_sign = 0; si->nx = bfirst & 0x02; sign_bit= 0; si->sign_info_bits++; } else { sign_bit= 1; si->x_has_sign = 1; } *blong= _bits_per_coord(base&0x0F, sign_bit); // Get bits per latitude if ( x_sign_same ) y_sign_same= bfirst & 0x04; else y_sign_same= bfirst & 0x02; if ( y_sign_same ) { si->y_has_sign = 0; si->ny = x_sign_same ? bfirst & 0x08 : bfirst & 0x04; sign_bit= 0; si->sign_info_bits++; } else { sign_bit= 1; si->y_has_sign = 1; } *blat= _bits_per_coord(base>>4, sign_bit); } static int bs_get_long_lat(struct bsp *bp, struct sign_info_t *si, int bpx, int bpy, struct gpoly *gp, int shift, int dl) { u_int32_t tmp; u_int32_t reg; u_int32_t xmask = ~0; u_int32_t ymask = ~0; u_int32_t xsign, xsign2; u_int32_t ysign, ysign2; int i=0,x,y,j; int scasex, scasey, scase = 0; int total = 0; int valid = 0; xmask = (xmask << (32-bpx)) >> (32-bpx); ymask = (ymask << (32-bpy)) >> (32-bpy); xsign = (1 << (bpx - 1)); ysign = (1 << (bpy - 1)); xsign2 = xsign<<1; ysign2 = ysign<<1; reg = bsp_get_bits(bp, si->sign_info_bits); j = 0; if (si->extrabit) { reg = bsp_get_bits(bp, 1); if (reg==-1) goto out; if (reg) bm_set_bit(gp->nodemap, 0); } for (i=0; i < gp->npoints; i++) { scasex =0; x = 0; reg = bsp_get_bits(bp, bpx); if (reg==-1) goto out; if (si->x_has_sign) { tmp = 0; while (1) { tmp = reg & xmask; if(tmp != xsign) break; scasex++; x += tmp - 1; reg = bsp_get_bits(bp, bpx); if (reg==-1) goto out; } if (tmp < xsign) x = tmp + x; else { x = tmp - (xsign << 1 ) - x; } } else { x = reg & xmask; if(si->nx) x = -x; } reg = bsp_get_bits(bp, bpy); if (reg==-1) goto out; scasey = 0; y = 0; if (si->y_has_sign) { tmp = 0; while (1) { tmp = reg & ymask; if(tmp != ysign) break; scasey++; y += tmp - 1; reg = bsp_get_bits(bp, bpy); if (reg==-1) goto out; } if (tmp < ysign) y = tmp + y; else { y = tmp - (ysign << 1) - y; } } else { y = reg & ymask; if(si->ny) y = -y; } if (si->extrabit) { reg = bsp_get_bits(bp, 1); if (reg==-1) goto out; if (reg) bm_set_bit(gp->nodemap, total+1); } if (x == 0 && y == 0) { log(15, "Point %d have zero deltas eb=%d\n", total, si->extrabit); // break; } if (x || y) valid++; gp->deltas[total].x = x << (shift); gp->deltas[total].y = y << (shift); total ++; } out: gp->valid = !!valid; gp->extrabit = si->extrabit; gp->scase = scase; if (i == gp->npoints) log(1, "Maximal points!!! bpx=%d bpy=%d eb=%d\n", bpx, bpy, si->extrabit); return total; } static void gar_copy_source(struct gar_subfile *sub, u_int8_t *dp, int l, u_int8_t **dst, int *len) { #ifdef DEBUG if (!(sub->gimg->gar->cfg.debugmask & DBGM_OBJSRC)) return; else { int i; u_int8_t *s; if (l>2048) { log(1, "dp=%p len=%d\n", dp, l); log(1, "Aborting ...\n"); sync(); abort(); return; } s = malloc(l+1); if (!s) return; *len = l; i = 0; while(isource) free(gp->source); #endif if (gp->nodemap) free(gp->nodemap); free(gp->deltas); free(gp); } static int gar_parse_poly(u_int8_t *dp, u_int8_t *ep, struct gpoly **ret, int line, int *ok, int cshift) { struct sign_info_t si; struct bsp bp; u_int8_t *sp = dp; u_int32_t total_bytes = 10; u_int16_t bs_len; u_int8_t bs_info; u_int32_t lbloffset; struct gpoly *gp; int bpx; // bits per x int bpy; // bits per y int two_byte,cnt; int extra_bit = 0; int dl = 15; *ok = 0; *ret = NULL; init_si(&si); gp = calloc(1, sizeof(*gp)); if (!gp) return -1; gp->type = *dp; two_byte = gp->type & 0x80; if (line) { gp->line = 1; gp->dir = (gp->type & 0x40) != 0; gp->type &= 0x3F; } else { gp->type &= 0x7F; } if (0 &&(gp->type == 0x21 || gp->type == 0x20 || gp->type == 0x22)) dl = 1; dp++; lbloffset = get_u24(dp); extra_bit = !!(lbloffset & 0x400000); if (line) { gp->netlbl = !!(lbloffset & 0x800000); } lbloffset = get_u24(dp); gp->lbloffset = lbloffset & 0x3FFFFF; dp+=3; gp->c.x = get_u16(dp); dp+=2; gp->c.y = get_u16(dp); dp+=2; gp->c.y = SIGN2B(gp->c.y); gp->c.x = SIGN2B(gp->c.x); gp->c.y<<=cshift; // XXX Check if we have to shift for the extrabit gp->c.x<<=cshift; log(dl, "shift=%d lat=%f, long=%f\n", cshift, GARDEG(gp->c.y), GARDEG(gp->c.x)); if (two_byte) { bs_len = get_u16(dp); dp+=2; total_bytes += bs_len + 1; } else { bs_len = *dp; dp++; total_bytes += bs_len; } if (dp+bs_len > ep) { log(1, "Invalid poligon line:%d len: %d max is %d two_byte=%d bslen=%02X\n", line, bs_len, ep - sp, two_byte, bs_len); free(gp); return total_bytes; } if (!bs_len) { log(1, "Empty poligon definition\n"); free(gp); return total_bytes; } bs_info = *dp; dp++; if (extra_bit) dl = 15; #ifdef DBGEXTRA if (extra_bit) { u_int8_t *t = dp; int j; log(1, "extra bit bs_len=%d\n", bs_len); for (j=0; j < bs_len; j++) log(1,"%02X\n", *t++); // return total_bytes; } #endif bits_per_coord(bs_info, *dp, extra_bit, &bpx, &bpy, &si); log(dl ,"%d/%d bits per long/lat len=%d extra_bit=%d\n", bpx, bpy, bs_len, extra_bit); cnt = 1 + ((bs_len*8)-si.sign_info_bits-si.extrabit)/ (bpx+bpy+si.extrabit); log(dl, "Total coordinates: %d\n", cnt); gp->deltas = calloc(cnt, sizeof(struct gcoord)); if (!gp->deltas) { log(1, "Can not allocate polygon points!\n"); free(gp); return total_bytes; } gp->npoints = cnt; if (extra_bit) { gp->nodemap = calloc(cnt/8+1, sizeof(unsigned char)); } if ((cnt == 1 && bs_len) || !bs_len) { log(1, "Error have %d points but datalen is %d, bpx=%d, bpy=%d si.sign_info_bits=%d\n",cnt, bs_len, bpx, bpy,si.sign_info_bits); log(1, "dp=%02X extra_bit=%d bs_info=%02X\n", *dp,extra_bit,bs_info); { u_int8_t *t = dp; int j; for (j=0; j < bs_len; j++) log(1,"%02X\n", *t++); } free(gp->deltas); free(gp); return total_bytes; } if (bs_len) { bsp_init(&bp, dp, bs_len); gp->npoints = bs_get_long_lat(&bp, &si, bpx, bpy, gp, cshift,dl); } log(dl, "Total real coordinates: %d\n", gp->npoints); if (gp->npoints < 1) { log(1, "Ignoring polydefinition w/ %d points\n", gp->npoints); log(1, "Have %d points datalen is %d, bpx=%d, bpy=%d si.sign_info_bits=%d extrabit=%d\n",cnt, bs_len, bpx, bpy,si.sign_info_bits, si.extrabit); free(gp->deltas); free(gp); return total_bytes; } *ok = 1; *ret = gp; return total_bytes; } static void gar_free_point(struct gpoint *gp) { #ifdef DEBUG if(gp->source) free(gp->source); #endif free(gp); } static int gar_parse_point(u_int8_t *dp, struct gpoint **ret) { struct gpoint *gp; u_int32_t i; *ret = NULL; gp = calloc(1, sizeof(*gp)); if (!gp) return -1; *ret = gp; gp->type = *dp; dp++; i = get_u24(dp); gp->has_subtype = !!(i & 0x800000); gp->is_poi = !!(i & 0x400000); gp->lbloffset = i & 0x3FFFFF; dp+=3; gp->c.x = get_u16(dp); dp+=2; gp->c.y = get_u16(dp); dp+=2; gp->c.x = SIGN2B(gp->c.x); gp->c.y = SIGN2B(gp->c.y); if (gp->has_subtype) { gp->subtype = *dp; *ret = gp; return 9; } return 8; }; static void dmp_lbl(struct gar_subfile *sub, u_int32_t lbloff, int type) { #ifdef DEBUG struct gimg *g = sub->gimg; if (!(g->gar->cfg.debugmask & DBGM_LBLS)) return; else { u_int8_t buf[2048]; off_t offsave = glseek(g, 0, SEEK_CUR); if (lbloff ==0 || lbloff == 0xFFFFFF) { return; } if (gar_get_lbl(sub, lbloff, type, buf, sizeof(buf)) > -1) { if (*buf != '^' && *buf != '\0') log(9, "LBL[%04X]:[%s]\n", lbloff, buf); } glseek(g, offsave, SEEK_SET); } #endif } void gar_free_subdiv_data(struct gar_subdiv *gsd) { int i, cnt; struct gpoint *gp; struct gpoly *gl; cnt = ga_get_count(&gsd->points); for (i=0; i < cnt; i++) { gp = ga_get(&gsd->points, i); if (gp) gar_free_point(gp); } ga_empty(&gsd->points); cnt = ga_get_count(&gsd->polylines); for (i=0; i < cnt; i++) { gl = ga_get(&gsd->polylines, i); if (gl) gar_free_poly(gl); } ga_empty(&gsd->polylines); cnt = ga_get_count(&gsd->polygons); for (i=0; i < cnt; i++) { gl = ga_get(&gsd->polygons, i); if (gl) gar_free_poly(gl); } ga_empty(&gsd->polygons); gsd->loaded = 0; } int gar_load_subdiv_data(struct gar_subfile *sub, struct gar_subdiv *gsub) { ssize_t rsize; u_int8_t *data; u_int16_t *dp; u_int8_t *d, *e; int rc,i,j; u_int32_t objcnt; u_int32_t opnt = 0, oidx = 0, opline = 0, opgon = 0; struct gimg *g = sub->gimg; struct gpoint *gp; u_int32_t pgi = 1, pli = 1, pi = 1; // FIXME: Index for an empty subdiv? if (gsub->rgn_start == gsub->rgn_end) return 0; /* regison start is direct offset */ log(15, "rgnstart: %04X, rgnend: %04X\n", gsub->rgn_start, gsub->rgn_end); rsize = gsub->rgn_end - gsub->rgn_start; if (rsize < 0) { log(1, "Error reading subdiv - negative size!\n"); return -1; } log(15, "Subdiv size: %zd\n", rsize); if (glseek(g, gsub->rgn_start, SEEK_SET) != gsub->rgn_start) { log(1, "Error can not seek to %d\n", gsub->rgn_start); return -1; } data = calloc(rsize, sizeof(u_int8_t)); if (!data) { log(1, "Out of memory reading subdiv\n"); return -1; } rc = gread(g, data, rsize); if (rc != rsize) { log(1, "Error reading subdiv want:%d got:%d\n", rsize, rc); free(data); return -1; } dp = (u_int16_t *)data; objcnt = gsub->haspoints + gsub->hasidxpoints + gsub->haspolylines + gsub->haspolygons; #if 0 if (!objcnt) { log(1, "Error size: %d but no objects!\n", rsize); free(data); return -1; } #endif if (g->is_nt && gar_debug_level > 10) { gar_print_buf("D", data, rsize); } /* * JM's doc is wrong about points / indexed points. * There are two blocks of points, where each point can have subtype. * Why? Alignment? Allow only first 255 to be accessed from indeces? * To be investigated. * But in the maps i have to get the indexes right * they should be in one array. */ if (gsub->haspoints) { opnt = (objcnt - 1) * sizeof(u_int16_t); } if (gsub->hasidxpoints) { if (opnt) oidx = *dp++; else oidx = (objcnt - 1) * sizeof(u_int16_t); } if (gsub->haspolylines) { if (opnt || oidx) opline = *dp++; else opline = (objcnt - 1) * sizeof(u_int16_t); if (opline > rsize) { /* Is it possible to reuse polygons/lines ?? */ log(7, "Correcting: Polylines offset is invalid\n"); gsub->haspolylines = 0; opline = 0; } } if (gsub->haspolygons) { if (opnt || oidx || opline) opgon = *dp++; else opgon = (objcnt - 1) * sizeof(u_int16_t); if (opgon > rsize) { log(7, "Correcting: Polygons offset is invalid\n"); gsub->haspolygons = 0; opgon = 0; } } log(15, "Have: %d objects: pnts: %s, idxpnts: %s, polyline:%s, poly:%s\n", objcnt, gsub->haspoints? "yes" : "no", gsub->hasidxpoints? "yes" : "no", gsub->haspolylines? "yes" : "no", gsub->haspolygons? "yes" : "no"); log(15, "@Points: %04X, IDXPNTs: %04X, PLINES: %04X, PGONS: %04X\n", opnt, oidx, opline, opgon); if (gsub->haspoints) { d = data + opnt; e = data + (oidx ? oidx : opline ? opline : opgon ? opgon : rsize); i = 0; while (d < e) { // decode one pnt rc = gar_parse_point(d, &gp); gp->c.x <<= gsub->shift; gp->c.y <<= gsub->shift; gp->c.x += gsub->icenterlng; gp->c.y += gsub->icenterlat; gp->n = pi++; if (gp->c.x < gsub->west || gp->c.x > gsub->east) { log(10, "Point[%d] out of bonds: %f, west=%f, east=%f\n", gp->n, GARDEG(gp->c.x), GARDEG(gsub->west), GARDEG(gsub->east)); j = 0; } if (gp->c.y < gsub->south || gp->c.y > gsub->north) { log(10, "Point[%d] out of bonds: %f, south=%f, north=%f\n", gp->n, GARDEG(gp->c.y), GARDEG(gsub->south), GARDEG(gsub->north)); j = 0; } j = 1; if (j) { gp->subdiv = gsub; ga_append(&gsub->points, gp); dmp_lbl(sub, gp->lbloffset, L_LBL); } else { free(gp); } d+=rc; }; } if (gsub->hasidxpoints) { d = data + oidx; e = data + (opline ? opline : opgon ? opgon : rsize); i = 0; while (d < e) { rc = gar_parse_point(d, &gp); gp->c.x <<= gsub->shift; gp->c.y <<= gsub->shift; gp->c.x += gsub->icenterlng; gp->c.y += gsub->icenterlat; gp->n = pi++; if (gp->c.x < gsub->west || gp->c.x > gsub->east) { log(1, "Poi[%d] out of bonds: %f, west=%f, east=%f\n", gp->n, GARDEG(gp->c.x), GARDEG(gsub->west), GARDEG(gsub->east)); j = 0; } if (gp->c.y < gsub->south || gp->c.y > gsub->north) { log(1, "Poi[%d] out of bonds: %f, south=%f, north=%f\n", gp->n, GARDEG(gp->c.y), GARDEG(gsub->south), GARDEG(gsub->north)); j = 0; } j = 1; if (j) { gp->subdiv = gsub; ga_append(&gsub->points, gp); dmp_lbl(sub, gp->lbloffset, gp->is_poi ? L_POI : L_LBL); } else free(gp); d+=rc; }; } if (gsub->haspolylines) { int ok = 0; struct gpoly *poly; d = data + opline; e = data + (opgon ? opgon : rsize); if (d>=data+rsize || e > data+rsize) { log(1,"Invalid polyline! data=%p rsize=%d ep=%p d=%p e=%p opline=%u opgon=%u\n", data, rsize, data+rsize, d, e, opline, opgon); objcnt-=1; goto out; } while (d < e) { rc = gar_parse_poly(d, e, &poly, 1, &ok, gsub->shift); if (ok) { poly->n = pli++; poly->c.x += gsub->icenterlng; poly->c.y += gsub->icenterlat; poly->subdiv = gsub; gar_copy_source(sub, d, rc, &poly->source, &poly->slen); /* FIXME: &gsub->polylines[MAXDRAWORDER] */ ga_append(&gsub->polylines, poly); dmp_lbl(sub, poly->lbloffset, L_LBL); } d+=rc; } } if (gsub->haspolygons) { int ok = 0; struct gpoly *poly; d = data + opgon; e = data + rsize; if (d>=data+rsize || e > data+rsize) { log(1,"Invalid polygon! data=%p d=%p e=%p opline=%04X\n", data, d, e, opline); objcnt-=1; goto out; } while (d < e) { rc = gar_parse_poly(d, e, &poly, 0, &ok,gsub->shift); if (ok) { poly->n = pgi++; poly->c.x += gsub->icenterlng; poly->c.y += gsub->icenterlat; poly->subdiv = gsub; ga_append(&gsub->polygons, poly); dmp_lbl(sub, poly->lbloffset, L_LBL); } d+=rc; } } out: free(data); gsub->loaded = 1; ga_trim(&gsub->points); ga_trim(&gsub->polylines); ga_trim(&gsub->polygons); #if 0 if (gar_debug_level > 10) { int size; size = ga_get_count(&gsub->points); log(1, "points:%d\n", size); size = ga_get_count(&gsub->polylines); log(1, "lines:%d\n", size); size = ga_get_count(&gsub->polygons); log(1, "polys:%d\n", size); } #endif return objcnt; } libgarmin-0~svn320/src/garmin_subdiv.h000066400000000000000000000007551112544465000201330ustar00rootroot00000000000000int gar_load_subdiv_data(struct gar_subfile *sub, struct gar_subdiv *gsub); void gar_free_subdiv_data(struct gar_subdiv *gsd); //void gar_subdiv_ref(struct gar_subdiv *sd); //void gar_subdiv_unref(struct gar_subdiv *sd); static void inline gar_subdiv_ref(struct gar_subdiv *sd) { gar_subfile_ref(sd->subfile); sd->refcnt ++; } static void inline gar_subdiv_unref(struct gar_subdiv *sd) { sd->refcnt --; if (sd->refcnt == 0) gar_free_subdiv_data(sd); gar_subfile_unref(sd->subfile); } libgarmin-0~svn320/src/garmin_tdb.c000066400000000000000000000160601112544465000173770ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #define __USE_GNU #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "GarminTypedef.h" #include "garmin_tdb.h" #ifdef STANDALONE #undef log #define log(x, y...) fprintf(stderr, ## y) int gar_img_load_dskimg(struct gar *gar, char *a, int bm, int data, double north, double east, double south, double west) { } #endif #define GAR4DEG(x) ((double)(x)* 360.0 / (1<<31)) /* * XXX: Use TDB for lookups */ static int gar_tdb_load_img(struct gar *gar, char *file, int basemap, int data, double north, double east, double south, double west) { char path[4096]; int rc; if (!gar) return 0; if (!gar->tdbdir) { log(1, "Trying to load [%s] but not TDB header seen yet\n", file); return -1; } sprintf(path, "%s/%s.img", gar->tdbdir, file); rc = gar_img_load_dskimg(gar, path, basemap, data, DEGGAR(north), DEGGAR(east), DEGGAR(south), DEGGAR(west)); if (rc < 0) log(1, "Failed to load [%s]\n", path); return rc; } int gar_parse_tdb(struct gar *gar, char *file, int data) { int fd, rc; u_int16_t s,t; char *buf, *cp, *tp; unsigned char *uc; struct tdb_block block; int version = 0; int c; int havebase = -1; int td4bm = 0; float north, south, east, west; char imgname[128]; fd = open(file, (OPENFLAGS&~O_NOATIME)); if (fd <0) { log(1, "Can not open:[%s] errno=%d(%s)\n", file, errno, strerror(errno)); return -1; } while (read(fd, &block, sizeof(struct tdb_block)) == sizeof(struct tdb_block)) { log(11,"Block type: %02X size=%d\n", block.id, block.size); buf = malloc(block.size); if (!buf) { break; } rc = read(fd, buf, block.size); if (rc != block.size) break; cp = buf; switch (block.id) { case TDB_HEADER: log(1, "ProductID: %d\n", *(u_int16_t *)cp); log(1, "MapID: %d\n", *(u_int16_t *)(cp+2)); log(1, "TDB Version: %.2f\n", (*(u_int16_t *)(cp+4))/100.0); version = (*(u_int16_t *)(cp+4))/100.0; log(1, "Map Series Name: [%s]\n", cp+16); cp+=16+strlen(cp+16) + 1; log(1, "Version: %.2f\n", (*(u_int16_t *)cp)/100.0); log(1, "Map Family: [%s]\n", cp+2); log(11, "Left bytes: %d\n", block.size - (cp - buf)); if (version != 3 && version != 4) { log(1, "Unsupported TDB version\n"); close(fd); return -1; } if (gar) { gar->tdbdir = strdup(file); tp = strrchr(gar->tdbdir, '/'); if (tp) *tp = '\0'; else *gar->tdbdir = '\0'; gar->tdbloaded = 1; } break; case TDB_COPYRIGHT: log(1, "Map copyrights:\n"); while (cp < buf+block.size) { log(1, "%s\n", cp+4); cp+=4+strlen(cp+4) + 1; } log(11, "Left bytes: %d\n", block.size - (cp - buf)); break; case TDB_TRADEMARK: log(1, "Map TradeMarks:\n"); while (cp < buf+block.size) { log(1, "[%02X]%s\n", *cp, cp + 1); cp+=1+ strlen(cp+1) + 1; } log(11, "Left bytes: %d\n", block.size - (cp - buf)); break; case TDB_REGIONS: log(1, "Covered Regions:\n"); while (cp < buf+block.size) { log(1, "[%02X][%02X]%s\n", *cp, *(cp+1),cp+2); cp+=2+strlen(cp+2) + 1; } log(11, "Left bytes: %d\n", block.size - (cp - buf)); break; case TDB_BASEMAP: if (version == 3) { log(4, "BaseMap number: %08u\n", *(u_int32_t *)cp); log(11, "Parent map: %08u\n", *(u_int32_t *)cp+4); sprintf(imgname, "%08u", *(u_int32_t *)cp); } else if (version == 4) { uc = (unsigned char *)cp; log(4, "BaseMap number: %08u\n", *(u_int32_t *)cp); log(11, "BaseMap number: [%02X][%02X][%02X][%02X]\n", *uc, *(uc+1), *(uc+2), *(uc+3)); log(11, "Parent map: [%02X][%02X][%02X][%02X]\n", *(uc+4), *(uc+5), *(uc+6), *(uc+7)); } else { log(1, "Unknown TDB version\n"); break; } if (version == 3) { north = GAR4DEG(*(u_int32_t *)(cp+8)); east = GAR4DEG(*(u_int32_t *)(cp+0xc)); south = GAR4DEG(*(u_int32_t *)(cp+0x10)); west = GAR4DEG(*(u_int32_t *)(cp+0x14)); } else if (version == 4) { c = *(int32_t *)(cp+8) >>8; north = GARDEG(c); c = *(int32_t *)(cp+12) >> 8; east = GARDEG(c); c = *(int32_t *)(cp+16) >> 8; south = GARDEG(c); c = *(int32_t *)(cp+20) >> 8; west = GARDEG(c); } else { log(1, "Unknown TDB version:%d\n", version); break; } log(9, "North: %fC West: %fC South: %fC East: %fC\n", north, west, south, east); cp+= 0x18; if (cp < buf+block.size) { log(9, "Descr:[%s]\n", cp); cp += strlen(cp) + 1; } log(11, "Left bytes: %d\n", block.size - (cp - buf)); if (version == 4) { tp = strrchr(file, '/'); if (tp) { sprintf(imgname, "%s", tp+1); } else { strncpy(imgname, file, sizeof(imgname)-1); imgname[sizeof(imgname)-1] = '\0'; } tp = strrchr(imgname, '.'); if (tp) *tp = '\0'; } if (version == 3) { havebase = 1; gar_tdb_load_img(gar, imgname, 1, data, north, east, south, west); } else if (version == 4) { havebase = 1; /* IN v4 looks like there are definitions pointing in the basemap */ if (!td4bm) { gar_tdb_load_img(gar, imgname, 1, data, north, east, south, west); td4bm = 1; } } break; case TDB_DETAILMAP: log(4, "DetailMap number: %08u\n", *(u_int32_t *)cp); sprintf(imgname, "%08u", *(u_int32_t *)cp); log(11, "Parent map: %08u\n", *(u_int32_t *)cp+4); if (version == 3) { north = GAR4DEG(*(u_int32_t *)(cp+8)); east = GAR4DEG(*(u_int32_t *)(cp+0xc)); south = GAR4DEG(*(u_int32_t *)(cp+0x10)); west = GAR4DEG(*(u_int32_t *)(cp+0x14)); } else if (version == 4) { c = *(int32_t *)(cp+8) >>8; c = SIGN3B(c); north = GARDEG(c); c = *(int32_t *)(cp+12) >> 8; c = SIGN3B(c); east = GARDEG(c); c = *(int32_t *)(cp+16) >> 8; c = SIGN3B(c); south = GARDEG(c); c = *(int32_t *)(cp+20) >> 8; c = SIGN3B(c); west = GARDEG(c); } else { log(1, "Unknown TDB version:%d\n", version); break; } log(9, "North: %fC West: %fC South: %fC East: %fC\n", north, west, south, east); cp+= 0x18; if (cp < buf+block.size) { log(9, "Descr:[%s]\n", cp); cp += strlen(cp) + 1; } t = *(u_int16_t*)cp; log(15, "blocks: %04X\n", *(u_int16_t*)cp); cp+=2; s = *(u_int16_t*)cp; log(15, "data: %04X\n", *(u_int16_t*)cp); cp+=2; while (s--) { log(15, "size: %08u\n", *(u_int32_t*)cp); cp+=4; } log(15, "term: %02X\n", *cp); cp++; log(11, "Left bytes: %d\n", block.size - (cp - buf)); gar_tdb_load_img(gar, imgname, 0, data, north, east, south, west); break; case TDB_TAIL: log(11, "TDB Tail block\n"); for (c=0; c < block.size; c++) { log(11, "[%02X]\n", *(unsigned char *)cp); cp++; } break; default: log(1, "Unknown TDB block ID:0x%02X\n", block.id); } free(buf); } close(fd); return havebase; } #ifdef STANDALONE int main(int argc, char **argv) { return gar_parse_tdb(NULL,argv[1],0); } #endif libgarmin-0~svn320/src/garmin_tdb.h000066400000000000000000000000721112544465000174000ustar00rootroot00000000000000int gar_parse_tdb(struct gar *gar, char *file, int data); libgarmin-0~svn320/src/garmin_typ.c000066400000000000000000000021001112544465000174300ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "libgarmin.h" #include "libgarmin_priv.h" /* http://ati.land.cz/gps/typdecomp/ */ struct hdr_typ_t { struct hdr_subfile_part_t hsub; u_int32_t tre1_offset; u_int32_t tre1_size; u_int32_t tre2_offset; u_int32_t tre2_size; u_int32_t tre3_offset; u_int32_t tre3_size; }; libgarmin-0~svn320/src/geoutils.c000066400000000000000000000104521112544465000171230ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "libgarmin.h" #include "libgarmin_priv.h" #include "geoutils.h" #ifdef STANDALONE #undef log #define log(x, y ...) fprintf(stdout, ## y) #endif void gar_rect_log(int l, char *pref,struct gar_rect *r) { char buf[1024]; if (!r) { return; } sprintf(buf,"%s%slulat=%f, lulong=%f, rllat=%f, rllong=%f\n", pref, pref ? ":" : "", GARDEG(r->lulat), GARDEG(r->lulong), GARDEG(r->rllat), GARDEG(r->rllong)); log(l, "%s", buf); } int gar_rect_contains(struct gar_rect *r1, double lat, double lon) { int ret = 0; // if (r1->lulat <= lat && lat <= r1->rllat) // ret = 3; // else if (r1->lulat >= lat && lat >= r1->rllat) ret = 3; if (r1->lulong <= lon && lon <= r1->rllong) ret ++; // if (r1->lulong >= lon && r1->rllong >= lon) // ret ++; #if 0 if (ret !=4 ) { gar_rect_log(1,"rect", r1); log(1,"lat=%f, lon=%f, ret=%d\n", lat, lon, ret); if (r1->lulong <= lon) log(1, "lulong %f <= lon %f\n", r1->lulong, lon); if (r1->lulong >= lon) log(1, "lulong %f >= lon %f\n", r1->lulong, lon); if (r1->rllong <= lon) log(1, "rllong %f <= lon %f\n", r1->rllong, lon); if (r1->rllong >= lon) log(1, "rllong %f >= lon %f\n", r1->rllong, lon); } else { gar_rect_log(1,"contains rect", r1); } #endif return ret == 4; } int gar_rects_overlaps(struct gar_rect *r1, struct gar_rect *r2) { return !( r2->lulong > r1->rllong || r2->rllong < r1->lulong || r2->lulat < r1->rllat || r2->rllat > r1->lulat ); } int gar_rects_intersect(struct gar_rect *r2, struct gar_rect *r1) { if (gar_rect_contains(r2, r1->lulat, r1->lulong)) return 1; if (gar_rect_contains(r2, r1->rllat, r1->rllong)) return 1; if (gar_rect_contains(r2, r1->lulat, r1->rllong)) return 1; if (gar_rect_contains(r2, r1->rllat, r1->lulong)) return 1; return 0; } int gar_rects_intersectboth(struct gar_rect *r1, struct gar_rect *r2) { // return gar_rects_intersect(r2,r1) || gar_rects_intersect(r1,r2); return gar_rects_overlaps(r2, r1) || gar_rects_overlaps(r1, r2); } #if 0 float gar_heading(struct gcoord *from, struct gcoord *to) { int dx, dy; float a; dx = to->x - from->x; dy = to->y - from->y; a = atan2(dx,dy)*180/M_PI; if (a < 0) { a = a+360; } return a; } #endif #ifdef STANDALONE /* North: 41.622133C West: 23.706822C East: 23.917301C South: 41.395862C */ int main(int argc, char **argv) { struct gar_rect r; struct gar_rect r1; int rc; r.lulat = 41.622133; r.lulong = 23.706822; r.rllat = 41.395862; r.rllong = 23.917301; gar_rect_log(1,"r", &r); rc = gar_rect_contains(&r, 41.612133, 23.806822); printf("contains: %d must be 1\n", rc); rc = gar_rect_contains(&r, 41.612133, 24.806822); printf("contains: %d must be 0\n", rc); rc = gar_rect_contains(&r, 42.612133, 23.806822); printf("contains: %d must be 0\n", rc); r1.lulat = 41.622133; r1.lulong = 23.706822; r1.rllat = 41.3958622; r1.rllong = 23.917301; gar_rect_log(1,"r1", &r1); printf("overlap: %d\n", gar_rects_overlaps(&r, &r1)); printf("intersect: %d\n", gar_rects_intersect(&r, &r1)); r1.lulat = 41.263315; r1.lulong = 24.003882; r1.rllat = 45.802112; r1.rllong = 22.292740; gar_rect_log(1,"r1", &r1); printf("overlap: %d\n", gar_rects_overlaps(&r, &r1)); printf("intersect: %d\n", gar_rects_intersect(&r, &r1)); if (argc > 1) { r1.lulat = atof(argv[1]); r1.lulong = atof(argv[2]); r1.rllat = atof(argv[3]); r1.rllong = atof(argv[4]); gar_rect_log(1,"r1", &r1); printf("overlap: %d\n", gar_rects_overlaps(&r, &r1)); printf("intersect: %d\n", gar_rects_intersect(&r, &r1)); } return 0; } #endif libgarmin-0~svn320/src/geoutils.h000066400000000000000000000006071112544465000171310ustar00rootroot00000000000000int gar_rect_contains(struct gar_rect *r1, double lat, double lon); int gar_rects_intersect(struct gar_rect *r2, struct gar_rect *r1); void gar_rect_log(int l, char *pref,struct gar_rect *r); int gar_rects_overlaps(struct gar_rect *r2, struct gar_rect *r1); int gar_rects_intersectboth(struct gar_rect *r2, struct gar_rect *r1); // float gar_heading(struct gcoord *from, struct gcoord *to); libgarmin-0~svn320/src/libgarmin.h000066400000000000000000000140061112544465000172400ustar00rootroot00000000000000/* Copyright (C) 2007,2008 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #ifdef __cplusplus extern "C" { #endif enum { L_LBL, L_NET, L_POI, L_MDR, }; struct gcoord { int x; int y; }; #define GS_COUNTRY 1 #define GS_REGION 2 #define GS_CITY 3 #define GS_ZIP 4 #define GS_ROAD 5 #define GS_INTERSECT 6 #define GS_HOUSENUMBER 7 #define GS_POI 8 #define GM_EXACT 0 #define GM_START 1 #define GM_ANY 2 struct gar_subfile; struct gar_search_res { struct gar_subfile *sub; unsigned fileid; unsigned countryid; unsigned regionid; unsigned cityid; unsigned zipid; unsigned roadid; unsigned poiid; }; struct gar_search { unsigned char type; unsigned char match; char *needle; struct gar_search_res fromres; }; #define GO_POINT 1 // GO_POI is now unused leave for compat #define GO_POI 1 #define GO_POLYLINE 3 #define GO_POLYGON 4 #define GO_ROAD 5 #define GO_SEARCH 6 struct gar_subfile; struct gar_objdraworder; struct gmap { struct gar_objdraworder *draworder; int subfiles; int lastsub; struct gar_subfile **subs; int zoomlevels; int basebits; int minlevel; int maxlevel; }; struct gobject { int type; void *gptr; void *priv_data; struct gobject *next; }; struct gar_rect { double lulat; double lulong; double rllat; double rllong; }; /* Walk and parse all data */ #define OPM_PARSE (1<<0) /* Call a callback w/ every object */ #define OPM_DUMP (1<<1) /* Work as a map backend */ #define OPM_GPS (1<<2) typedef void (*dump_fn)(struct gobject *obj); #define DBGM_LBLS (1<<0) #define DBGM_OBJSRC (1<<1) #define DBGM_DUMP (1<<2) #define DBGM_NTMAP (1<<3) struct gar_config { int opm; int maxsubdivs; /* Load max N subdivs for OPM_GPS */ dump_fn cb; /* Callback function for OPM_DUMP */ unsigned debugmask; /* Debuging aid */ int debuglevel; /* Debug level */ }; struct gimg; struct gar; typedef void (*log_fn)(char *file, int line, int level, char *fmt, ...) __attribute__ ((format(printf,4,5))); /* Default init w/ config, keep for the latest navit release */ struct gar *gar_init(char *tbd, log_fn l); struct gar *gar_init_cfg(char *tbd, log_fn l, struct gar_config *cfg); void gar_free(struct gar *g); int gar_img_load(struct gar *gar, char *file, int data); struct gmap *gar_find_subfiles(struct gar *gar, void *select, int flags); void gar_free_gmap(struct gmap *g); int gar_get_zoomlevels(struct gar_subfile *sub); #define GO_GET_SORTED (1<<0) #define GO_GET_ROUTABLE (1<<1) #define GO_GET_SEARCH (1<<2) struct gobject *gar_get_object(struct gar *gar, void *ptr); int gar_get_objects(struct gmap *gm, int level, void *select, struct gobject **ret, int flags); void gar_free_objects(struct gobject *g); unsigned short gar_obj_type(struct gobject *o); int gar_object_group(struct gobject *o); int gar_get_object_position(struct gobject *o, struct gcoord *ret); int gar_object_subtype(struct gobject *o); int gar_get_object_dcoord(struct gmap *gm, struct gobject *o, int ndelta, struct gcoord *ret); int gar_get_object_coord(struct gmap *gm, struct gobject *o, struct gcoord *ret); int gar_is_object_dcoord_node(struct gmap *gm, struct gobject *o, int ndelta); int gar_get_object_deltas(struct gobject *o); /* Get lbl as strdup'ed string */ char *gar_get_object_lbl(struct gobject *o); int gar_get_object_intlbl(struct gobject *o); /* Code page for labels */ char *gar_obj_codepage(struct gobject *o); int gar_object_get_draw_order(struct gobject *o); char *gar_object_debug_str(struct gobject *o); /* Object index is (subdividx << 16) | (idx << 8) | otype */ int gar_object_index(struct gobject *o); /* Object mapid is the id of the file containing the object */ int gar_object_mapid(struct gobject *o); struct gobject *gar_get_object_by_id(struct gar *gar, unsigned int mapid, unsigned int objid); int gar_fat_file2fd(struct gimg *g, char *name, int fd); /* Get ptr to a dskimg file */ struct gimg *gar_get_dskimg(struct gar *gar, char *file); #define F_ONEWAY (1<<0) #define F_SEGMENTED (1<<1) #define F_LOCKONROAD (1<<2) int gar_object_flags(struct gobject *o); #define GARDEG(x) ((x) < 0x800000 ? (double)(x) * 360.0 / 16777216.0 : -(double)((x) - 0x100000) * 360.0 / 16777216.0) #define GARRAD(x) ((x) < 0x800000 ? (double)(x) * TWOPI / 16777216.0 : -(double)((x) - 0x100000) * TWOPI / 16777216.0) #define DEGGAR(x) ((x) * (1/(360.0/(1<<24)))) #define FEET2METER(x) ((x)/3.28084) #define POI_STREET_NUM (1<<0) #define POI_STREET (1<<1) #define POI_CITY (1<<2) #define POI_ZIP (1<<3) #define POI_PHONE (1<<4) #define POI_EXIT (1<<5) #define POI_TIDE_PREDICT (1<<6) #define POI_UNKNOW (1<<7) unsigned int gar_srch_get_countryid(struct gobject *o); char *gar_srch_get_country(struct gobject *o); unsigned int gar_srch_get_regionid(struct gobject *o); char *gar_srch_get_region(struct gobject *o); unsigned int gar_srch_get_cityid(struct gobject *o); char *gar_srch_get_city(struct gobject *o); unsigned int gar_srch_get_zipid(struct gobject *o); char *gar_srch_get_zip(struct gobject *o); unsigned int gar_srch_get_roadid(struct gobject *o); char *gar_srch_get_roadname(struct gobject *o); /* Routing */ struct gar_route; struct gar_route_request { struct gar_route *route; unsigned int posmapid; unsigned int posobjid; int posidx; unsigned int dstmapid; unsigned int dstobjid; int dstidx; int route_flags; int vehicle_type; }; struct gar_route *gar_route(struct gar *gar, struct gar_route_request *grr); #ifdef __cplusplus } #endif libgarmin-0~svn320/src/libgarmin_priv.h000066400000000000000000000072251112544465000203050ustar00rootroot00000000000000#include "config.h" #include #ifdef TARGET_WIN32CE #include "win32support.h" #endif #include "list.h" #include "GarminTypedef.h" #define __USE_GNU #include #ifndef TARGET_WIN32CE #include #endif #include "align.h" #ifndef O_NOATIME #define O_NOATIME 0 #endif #ifndef O_BINARY #define O_BINARY 0 #endif #define OPENFLAGS (O_RDONLY|O_NOATIME|O_BINARY) extern log_fn glogfn; extern int gar_debug_level; // #define glog(g, l, x ...) g->logfn(__FILE__, __LINE__, l, ## x) #define log(l, x ...) do { \ if (l <= gar_debug_level) \ glogfn(__FILE__, __LINE__, l, ## x); \ } while(0) #define SIGN2B(x) (((x) < 0x8000) ? (x) : ((x)-0x10000)) #define SIGN3B(x) (((x) < 0x800000) ? (x) : ((x)-0x1000000)) //#define TWOPI (M_PI*2) #define TWOPI 6.283185307179586476925287 #define DEG_TO_RAD(A) ((A) * (M_PI/180.0)) //#define DEG_TO_RAD(A) ((A) * 16777216.0) //#define RAD_TO_DEG(x) ((x) * 16777216.0) #define RAD_TO_DEG(x) ((double)(x) * ((double)180.0/M_PI)) #define DEG(x) ((x) < 0x800000 ? (double)(x) * 360.0 / 16777216.0 : -(double)((x) - 0x100000) * 360.0 / 16777216.0) #define RAD(x) ((x) < 0x800000 ? (double)(x) * TWOPI / 16777216.0 : -(double)((x) - 0x100000) * TWOPI / 16777216.0) //#define DEG(x) ((x) < 0x800000 ? (double)(x) * 360.0 / (1<<24) : -(double)((x) - 0x100000) * 360.0 / (1<<24)) //#define RAD(x) ((x) < 0x800000 ? (double)(x) * TWOPI / (1<<24) : -(double)((x) - 0x100000) * TWOPI / (1<<24)) struct gar { struct gar_config cfg; char *tdbdir; int tdbloaded; int basebits; int zoomlevels; log_fn logfn; list_t limgs; struct gmap *gmap; }; struct bspfd; typedef int (*decode_fn)(struct bspfd *bp, u_int8_t *out, ssize_t len); struct gar_lbl_t { decode_fn decode; int bits; char codepage[512]; u_int32_t offset; u_int32_t lbl1off; u_int32_t lbl1size; u_int8_t lbl6_glob_mask; u_int32_t lbl6off; u_int32_t lbl6size; u_int32_t addrshift; u_int32_t addrshiftpoi; }; struct gar_mdr; struct gimg { list_t l; list_t lfatfiles; list_t lsubfiles; struct gar *gar; int fd; unsigned char xor; int is_nt; int tdbbasemap; int basebits; int zoomlevels; int minlevel; int maxlevel; int mapsets; double north; double east; double south; double west; struct gar_mdr *mdr; char *file; }; struct gpoint { struct gar_subdiv *subdiv; u_int16_t n; u_int8_t type; u_int8_t subtype; u_int32_t lbloffset; struct gcoord c; unsigned is_poi :1, has_subtype :1, is_nt:1; #ifdef DEBUG unsigned char *source; int slen; #endif }; struct gpoly { struct gar_subdiv *subdiv; u_int16_t n; u_int16_t type; u_int32_t lbloffset; struct gcoord c; unsigned dir:1, netlbl:1, line:1, extrabit:1, scase:1, valid:1, is_nt:1; int npoints; struct gcoord *deltas; unsigned char *nodemap; #ifdef DEBUG unsigned char *source; int slen; #endif }; void gar_log_file_date(int l, char *pref, struct hdr_subfile_part_t *h); int gar_img_load_dskimg(struct gar *gar, char *file, int tdbbase, int data, double north, double east, double south, double west); ssize_t gread(struct gimg *g, void *buf, size_t count); ssize_t gread_safe(struct gimg *g, void *buf, size_t count); ssize_t gwrite(struct gimg *g, void *buf, size_t count); off_t glseek(struct gimg *g, off_t offset, int whence); int gopen(struct gimg *g); int gclose(struct gimg *g); struct gobject *gar_get_subfile_object_byidx(struct gar_subfile *sub, int sdidx, int oidx, int otype); void gar_print_buf(char *pref, unsigned char *a, int s); struct gar_subfile *gar_subfile_get_by_mapid(struct gar *gar, unsigned int mapid); struct gar_subdiv *gar_find_subdiv_by_idx(struct gar_subfile *gsub, int fromlevel, int idx); libgarmin-0~svn320/src/list.c000066400000000000000000000035061112544465000162450ustar00rootroot00000000000000/* Copyright (C) 2007 Alexander Atanasov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA This file is originaly based on linux kernel lists. */ #include "list.h" void list_init(list_t *l) { l->n = l; l->p = l; } static inline void list_ins(list_t *f, list_t *l, list_t *p, list_t *n) { l->n = n; f->p = p; p->n = f; n->p = l; } void list_del(list_t *p,list_t *n) { n->p = p; p->n = n; } void list_prepend(list_t *e,list_t *l) { list_ins(e, e, l, l->n); } void list_append(list_t *e,list_t *l) { list_ins(e, e, l->p, l); } void list_remove(list_t *e) { list_del(e->p, e->n); } void list_remove_init(list_t *e) { list_del(e->p,e->n); list_init(e); } void list_prepend_list(list_t *l, list_t *lhead) { if (!list_empty(l)) { list_ins(l->n, l->p, lhead, lhead->n); } } void list_prepend_list_init(list_t *l, list_t *lhead) { if (!list_empty(l)) { list_ins(l->n, l->p, lhead, lhead->n); list_init(l); } } void list_append_list(list_t *l, list_t *lhead) { if (!list_empty(l)) { list_ins(l->n, l->p, lhead->p, lhead); } } void list_append_list_init(list_t *l, list_t *lhead) { if (!list_empty(l)) { list_ins(l->n, l->p, lhead->p, lhead); list_init(l); } } libgarmin-0~svn320/src/list.h000066400000000000000000000042411112544465000162470ustar00rootroot00000000000000#ifndef __LIST_H #define __LIST_H #undef offsetof #ifdef __compiler_offsetof #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) #else #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member));}) #define list_entry(ptr, type, member) \ container_of(ptr, type, member) #define list_t struct struct_list list_t { list_t *n, *p; }; #define list_head(h) list_t h = { &h, &h } void list_init(list_t *l); void list_del(list_t *p,list_t *n); void list_prepend(list_t *e,list_t *l); void list_append(list_t *e,list_t *l); #define list_add(e,l) list_append(e,l); void list_remove(list_t *e); void list_remove_init(list_t *e); void list_prepend_list(list_t *l, list_t *lhead); void list_prepend_list_init(list_t *l, list_t *lhead); void list_append_list(list_t *l, list_t *lhead); void list_append_list_init(list_t *l, list_t *lhead); static __inline__ int list_empty(list_t *l) {return l->n == l;} #define list_for(_p,_l) for (_p = (_l)->n; _p != (_l); _p = _p->n) #define list_for_backward(_p,_l) for (_p = (_l)->p; _p != (_l); _p = _p->p) //#define list_entry(_p,_t,_m) ((_t *)((char *)(&_p->n)-(unsigned long)(&((_t *)0)->_m))) //#define list_entry(_p,_t,_m) ((_t *)((char *)(&_p->n)-offsetof(_t,_m))) #define list_for_entry(pos, head, member) \ for (pos = list_entry((head)->n, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.n, typeof(*pos), member)) #define list_for_entry_backward(_e,_l,_m) \ for (_e = list_entry((_l)->p, typeof(*_e), _m); \ &_e->_m != (_l); \ _e = list_entry(_e->_m.p, typeof(*_e), _m)) #define list_for_first_entry(e,l,m) \ for (e = list_entry((l)->n, typeof(*e), m); \ &e->m != (l); \ e = list_entry((l)->n, typeof(*e), m)) #define list_for_entry_safe(_e,_n,_l,_m) \ for (_e = list_entry((_l)->n, typeof(*_e), _m), \ _n = list_entry(_e->_m.n, typeof(*_e), _m); \ &_e->_m != (_l); \ _e = _n, _n = list_entry(_e->_m.n, typeof(*_e), _m)) #endif libgarmin-0~svn320/src/win32support.h000066400000000000000000000005261112544465000176750ustar00rootroot00000000000000#ifndef _WIN32_SUPPORT_H_ #include #include #include typedef unsigned char u_int8_t; typedef unsigned short int u_int16_t; typedef unsigned int u_int32_t; #define EPERM ERROR_ACCESS_DENIED #define sync() do {} while(0) #define errno GetLastError() #define strerror(x) "" #define _WIN32_SUPPORT_H_ #endif libgarmin-0~svn320/utils/000077500000000000000000000000001112544465000154735ustar00rootroot00000000000000libgarmin-0~svn320/utils/Makefile.am000066400000000000000000000004011112544465000175220ustar00rootroot00000000000000AM_CPPFLAGS=-I$(top_srcdir)/src -Wall bin_PROGRAMS = garxtract garxor noinst_PROGRAMS = gartest bsptest garroute gartest_LDADD = ../src/libgarmin.a garxtract_LDADD = ../src/libgarmin.a garroute_LDADD = ../src/libgarmin.a clean-local: rm -rf *~ *.bak core libgarmin-0~svn320/utils/bsptest.c000066400000000000000000000116511112544465000173270ustar00rootroot00000000000000#include #include #include #include #define log(x, y ...) fprintf(stdout, ## y) unsigned char d1[] = { 0x08, 0x00, 0x00, 0x00, 0xd0, 0x01, 0xe6, 0xfe, 0x03, 0x01, 0xab, 0x7a, 0xb1 }; unsigned char d2[] = { 0x05, 0x40, 0x07, 0x00, 0xbc, 0x01, 0x85, 0x00, 0x03, 0x57, 0x6d, 0x12, 0x0a }; struct gpoly { u_int8_t type; unsigned dir:1, netlbl:1, line:1; double dlng; double dlat; u_int32_t lbloffset; }; struct sign_info_t { u_int32_t sign_info_bits; int x_has_sign; int nx; int y_has_sign; int ny; }; static void init_si(struct sign_info_t *si) { si->sign_info_bits = 2; si->x_has_sign = 1; si->nx = 0; si->y_has_sign = 1; si->ny = 0; } static int _bits_per_coord (u_int8_t base, int is_signed, int extra_bit) { int n= 2; if ( base <= 9 ) n+= base; else n+= (2*base-9); if ( is_signed ) ++n; if ( extra_bit ) ++n; return n; } static void bits_per_coord (u_int8_t base, u_int8_t bfirst, int extra_bit, int *blong, int *blat, struct sign_info_t *si) { int x_sign_same, y_sign_same; int sign_bit; // Get bits per longitude x_sign_same= bfirst & 0x1; if ( x_sign_same ) { si->x_has_sign = 0; si->nx = bfirst & 0x02; si->sign_info_bits++; sign_bit= 0; } else { sign_bit= 1; si->x_has_sign = 1; } *blong= _bits_per_coord(base&0x0F, sign_bit, extra_bit); // Get bits per latitude if ( x_sign_same ) y_sign_same= bfirst & 0x04; else y_sign_same= bfirst & 0x02; if ( y_sign_same ) { si->y_has_sign = 0; si->ny = x_sign_same ? bfirst & 0x08 : bfirst & 0x04; sign_bit= 0; si->sign_info_bits++; } else { sign_bit= 1; si->y_has_sign = 1; } *blat= _bits_per_coord((base&0xF0)>>4, sign_bit, extra_bit); } struct bsp { u_int8_t *data; u_int8_t *cb; int cbit; }; static void bsp_init(struct bsp *bp, u_int8_t *data) { bp->cbit = 0; bp->data = data; bp->cb = bp->data; } static int inline bsp_get_bits(struct bsp *bp, int bits) { u_int32_t ret = 0; int i; for (i=0; i < bits; i++) { if (bp->cbit == 8) { bp->cbit = 0; bp->cb++; } ret |= (!!(*bp->cb & (1<cbit))) << i; bp->cbit ++; } return ret; } static int bs_get_mask(int bits) { int a = 0,i; for (i =0; i < bits; i++) a |= (1<sign_info_bits); log(10, "X has sign=%d, nx=%d\n", si->x_has_sign, si->nx); log(10, "Y has sign=%d, ny=%d\n", si->y_has_sign, si->ny); xmask = bs_get_mask(bpx-1); ymask = bs_get_mask(bpy-1); x = bsp_get_bits(bp, si->sign_info_bits); for (i=0; i < count; i++) { x = bsp_get_bits(bp, bpx); if (si->x_has_sign) { s = x & sxmask; if (s) { x &= ~sxmask; if (!x) { /* FIXME: Is it possible to have nested special cases ?*/ nw = bsp_get_bits(bp, bpx); if (nw&sxmask) { nw &= ~sxmask; nw = - (xmask ^ (nw - 1)); } x = nw << 1; } else { x = bpx - 1 - x; } } } else if (si->nx) { x = -x; } y = bsp_get_bits(bp, bpy); if (si->y_has_sign) { s = y & symask; if (s) { y &= ~symask; if (!y) { nw = bsp_get_bits(bp, bpy); if (nw&symask) { nw &= ~symask; nw = - (ymask ^ (nw - 1)); } y = nw << 1; // special case! } else { y &= ~symask; y = - (ymask ^ (y-1)); } } } else if (si->ny) { y = -y; } log(10, "lat=%d, long=%d\n", y, x); } return 0; } static int parse(unsigned char *dp, int line) { struct bsp bp; struct sign_info_t si; u_int32_t total_bytes = 10; u_int16_t bs_len; u_int8_t bs_info; u_int32_t lbloffset; struct gpoly *gp; int bpx; // bits per x int bpy; // bits per y int two_byte; int extra_bit = 0; init_si(&si); gp = calloc(1, sizeof(*gp)); if (!gp) return -1; gp->type = *dp; two_byte = gp->type & 0x80; if (line) { gp->line = 1; gp->dir = gp->type & 0x40; gp->type &= 0x3F; } else { gp->type &= 0x7F; } lbloffset = *(u_int32_t *)dp; lbloffset &= 0x00FFFFFF; extra_bit = lbloffset & 0x400000; gp->lbloffset = lbloffset & 0x3FFFFF; if (line) { gp->netlbl = !!(lbloffset & 0x800000); if (gp->netlbl) { // FIXME read .NET file } } dp+=4; gp->dlng = *(u_int16_t *)dp; dp+=2; gp->dlat = *(u_int16_t *)dp; dp+=2; if (two_byte) { bs_len = *(u_int16_t*)dp; dp+=2; total_bytes += bs_len + 1; } else { bs_len = *dp++; total_bytes += bs_len; } bs_info = *dp; log(10, "Base %u/%u bits per long/lat\n", bs_info&0x0F, (bs_info&0xF0)>>4); dp++; bits_per_coord(bs_info, *dp, extra_bit, &bpx, &bpy, &si); log(10,"%d/%d bits per long/lat len=%d\n", bpx, bpy, bs_len); log(10, "Total coordinates: %d\n", (bs_len*8)/(bpx+bpy)); bsp_init(&bp, dp); bs_get_long_lat((bs_len*8)/(bpx+bpy), &bp, &si, bpx, bpy); return total_bytes; } int main(int argc, char **argv) { parse(d1,0); parse(d2,1); return 0; } libgarmin-0~svn320/utils/garroute.c000066400000000000000000000120271112544465000174710ustar00rootroot00000000000000#include #include #include #include #include #define __USE_BSD #include #include "libgarmin.h" #include "GarminTypedef.h" #include "list.h" #include "garmin_nod.h" static int debug = 15; static void logfn(char *file, int line, int level, char *fmt, ...) { va_list ap; if (level > debug) return; va_start(ap, fmt); fprintf(stdout, "%s:%d:%d|", file, line, level); vfprintf(stdout, fmt, ap); va_end(ap); } static struct gar * load(char *file) { struct gar *g; struct gar_config cfg; cfg.opm = OPM_PARSE; // FIXME: make cmdline arg cfg.debugmask = 0; // DBGM_LBLS | DBGM_OBJSRC; cfg.debuglevel = debug; g = gar_init_cfg(NULL, logfn, &cfg); if (!g) return NULL; if (gar_img_load(g, file, 1) > 0) return g; else { gar_free(g); return NULL; } } static int usage(char *pn) { fprintf(stderr, "%s [-d level] garmin.img from [to]\n", pn); return -1; } static void dump_q(struct gar_graph *graph) { struct node *n; int d=0; list_for_entry(n, &graph->lqueue, lc) { // fprintf(stderr, "%d %d\n", n->offset, n->value); d++; } // fprintf(stderr, "Depth %d\n", d); } void enqueue_node(struct gar_graph *graph, struct node *node) { // fprintf(stderr, "NOD enqueue:%d c=%d v=%d\n", node->offset, node->complete, node->value); if (!node->complete) { struct node *n; list_remove_init(&node->lc); list_for_entry(n, &graph->lqueue, lc) { if (n->value > node->value) { list_append(&node->lc, &n->lc); dump_q(graph); return; } } list_append(&node->lc, &graph->lqueue); } dump_q(graph); } int can_visit(struct node *from, struct node *to) { return 1; } static int get_arc_heuristic(struct node *n, struct grapharc *arc) { return arc->len; } int route(struct gar_subfile *sub, struct gar_graph *g, struct node *from, struct node *to) { struct node *n; unsigned int iter = 0; unsigned int newval; int i; enqueue_node(g, from); from->value = 0; while (!list_empty(&g->lqueue)) { iter++; n = list_entry(g->lqueue.n, struct node, lc); list_remove_init(&n->lc); // fprintf(stderr, "node %d value=%d\n", n->offset, n->value); if (!n->complete) { if (gar_read_node(g, NULL, n) < 0) { fprintf(stderr, "error reading node\n"); return -1; } n->complete = 1; } if (n == to) { printf("route %d\n", iter); // to->from = n; return 1; } for (i=0; i < n->narcs; i++) { if (n->arcs[i].dest == n) continue; if (n->arcs[i].islink) continue; if (can_visit(n, n->arcs[i].dest)) { newval = n->value + get_arc_heuristic(to, &n->arcs[i]); if (n->arcs[i].dest->value != ~0) { if (n->arcs[i].dest->value > newval) { n->arcs[i].dest->from = n; n->arcs[i].dest->value = newval; enqueue_node(g, n->arcs[i].dest); } else if (n->arcs[i].dest->value == newval) { // fprintf(stderr, "same val %d %d\n", n->class, n->arcs[i].dest->class); if (n->class < n->arcs[i].dest->class) { n->arcs[i].dest->from = n; enqueue_node(g, n->arcs[i].dest); } } } else { n->arcs[i].dest->value = newval; n->arcs[i].dest->from = n; enqueue_node(g, n->arcs[i].dest); } } } } printf("noroute %d\n", iter); return 0; } int write_routemap(struct node *goal, char *file) { FILE *fp; struct node *pn = goal; fp = fopen(file, "w"); if (!fp) return -1; while (pn) { fprintf(fp, "type=street_route value=\"%d\" label=\"%d\"\n", pn->value, pn->offset); fprintf(fp, "garmin:0x%x 0x%x\n", pn->c.x, pn->c.y); pn = pn->from; if (pn) fprintf(fp, "garmin:0x%x 0x%x\n",pn->c.x, pn->c.y); } fclose(fp); return 0; } int main(int argc, char **argv) { struct gar *gar; struct gar_graph *g; struct gar_subfile *sub; int ofrom = -1, oto = -1; char *file = argv[1]; struct gmap *gm; struct timeval tv1, tv2,tv3; int i; struct node *from, *to, *pn; if (argc < 2) { return usage(argv[0]); } if (!strcmp(argv[1], "-d")) { if (argc > 3) { debug = atoi(argv[2]); fprintf(stderr, "debug level set to %d\n", debug); file = argv[3]; } else { return usage(argv[0]); } } if (argc > 4) ofrom = atoi(argv[4]); if (argc > 5) oto = atoi(argv[5]); gar = load(file); fprintf(stderr, "Graph from %d to %d\n", ofrom, oto); gm = gar_find_subfiles(gar, NULL, GO_GET_ROUTABLE); for (i=0; i < gm->subfiles; i++) { sub = gm->subs[i]; gettimeofday(&tv1, NULL); // if (to != -1) // g = gar_read_graph(sub, 0, from, 0, to); // else // g = gar_read_graph(sub, 0, from, 1000, to); g = gar_alloc_graph(sub); to = gar_get_node(g, oto); from = gar_get_node(g, ofrom); #if 1 if (route(sub, g, from, to)==1) { pn = to; while (pn) { fprintf(stderr, "P:%d value=%d\n", pn->offset, pn->value); pn = pn->from; } write_routemap(to, "/tmp/route.txt"); } #endif gettimeofday(&tv2, NULL); timersub(&tv2,&tv1,&tv3); printf("Read %d in %d.%d sec\n", g->totalnodes, tv3.tv_sec,tv3.tv_usec); if (g) { char buf[512]; sprintf(buf,"/tmp/%d-graph.txt", ofrom); gar_graph2tfmap(g, buf); gar_free_graph(g); } break; } gar_free(gar); return 0; } libgarmin-0~svn320/utils/gartest.c000066400000000000000000000046271112544465000173210ustar00rootroot00000000000000#include #include #include #include #include "libgarmin.h" static int debug = 15; static int debugmask = 0; static void logfn(char *file, int line, int level, char *fmt, ...) { va_list ap; if (level > debug) return; va_start(ap, fmt); fprintf(stdout, "%s:%d:%d|", file, line, level); vfprintf(stdout, fmt, ap); va_end(ap); } static struct gar * load(char *file) { struct gar *g; struct gar_config cfg; cfg.opm = OPM_PARSE; // DBGM_LBLS | DBGM_OBJSRC | DBGM_DUMP | DBGM_NTMAP cfg.debugmask = debugmask; cfg.debuglevel = debug; g = gar_init_cfg(NULL, logfn, &cfg); if (!g) return NULL; if (gar_img_load(g, file, 1) > 0) return g; else { gar_free(g); return NULL; } } static int usage(char *pn) { fprintf(stderr, "%s [-d level] [-l] [-n] [-r] garmin.img\n", pn); fprintf(stderr, "\t-l Dump labels\n"); fprintf(stderr, "\t-n Dump data\n"); fprintf(stderr, "\t-r Read NT/Marine data\n"); return -1; } int main(int argc, char **argv) { struct gar *gar; struct gar_rect r; char *file = argv[1]; int i = 1; if (argc < 2) { return usage(argv[0]); } while (i < argc) { if (*argv[i] != '-') break; if (!strcmp(argv[i], "-d")) { if (argc > i+1) { debug = atoi(argv[i+1]); fprintf(stderr, "debug level set to %d\n", debug); i++; } else { return usage(argv[0]); } } else if (!strcmp(argv[i], "-l")) { debugmask |= DBGM_LBLS; } else if (!strcmp(argv[i], "-n")) { debugmask |= DBGM_DUMP; } else if (!strcmp(argv[i], "-r")) { debugmask |= DBGM_NTMAP; } i++; } if (i >= argc) return usage(argv[0]); file = argv[i]; r.lulat = 43.706080; r.lulong = 29.942551; r.rllat = 43.698679; r.rllong = 29.977290; gar = load(file); if (!gar) { fprintf(stderr, "Failed to load: [%s]\n", file); return 0; } gar_find_subfiles(gar, &r, 0); r.lulat = DEGGAR(44.281147); r.lulong = DEGGAR(22.274888); r.rllat = DEGGAR(42.787006); r.rllong = DEGGAR(24.032700); gar_find_subfiles(gar, &r,0); r.lulat = DEGGAR(24.281147); r.lulong = DEGGAR(12.274888); r.rllat = DEGGAR(22.787006); r.rllong = DEGGAR(14.032700); gar_find_subfiles(gar, &r,0); /* 43.892183C, East: 22.952971C, South: 43.638103C, West: 22.643273C */ r.lulat = DEGGAR(43.892183); r.lulong = DEGGAR(22.643273); r.rllat = DEGGAR(43.638103); r.rllong = DEGGAR(22.952971); gar_find_subfiles(gar, &r,0); gar_find_subfiles(gar, NULL,0); gar_free(gar); return 0; } libgarmin-0~svn320/utils/garxor.c000066400000000000000000000055271112544465000171520ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "../src/GarminTypedef.h" static int gar_xor_file(char *in, char *out) { char buf[4096]; int fd, fd1; int first = 1; char xorb = 0; int ret = -1; int rc,i; fd = open(in, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can not open:%s\n", in); return -1; } fd1 = open(out, O_RDWR|O_CREAT|O_TRUNC, 0660); if (fd1 < 0) { fprintf(stderr, "Can not open:%s\n", out); return -1; } while ((rc = read(fd, buf, sizeof(buf))) > 0) { i = 0; if (first) { xorb = buf[0]; } for (;isignature,"DSKIMG",6)) { fprintf(stderr, "%s is not garmin image - invalid signature\n", in); goto out; } if (strncmp(img->identifier,"GARMIN",6)) { fprintf(stderr, "%s is not garmin image - invalid identifier\n", in); goto out; } first = 0; } if (write(fd1, buf, rc) != rc) { fprintf(stderr, "Error writing %d bytes\n", rc); ret = -1; goto out; } } ret = 0; out: close(fd); close(fd1); if (ret < 0) unlink(out); return ret; } static int gar_xor_dir(char *path) { struct dirent **namelist; int n, rc; int cnt = 0; char in[4096]; char out[4096]; char ren[4096]; n = scandir(path, &namelist, 0, NULL); if (n < 0) { fprintf(stderr, "Bad directory path\n"); return -1; } while(n--) { if ( *namelist[n]->d_name == '.') { free(namelist[n]); continue; } fprintf(stderr, "Processing: [%s]\n", namelist[n]->d_name); sprintf(in,"%s/%s", path, namelist[n]->d_name); sprintf(out,"%s/%s.tmp", path, namelist[n]->d_name); rc = gar_xor_file(in, out); if (rc == 0) { sprintf(ren,"%s/%s.orig", path, namelist[n]->d_name); if (!rename(in, ren)) { if (!rename(out, in)) { fprintf(stdout, "Converted [%s]\n", namelist[n]->d_name); unlink(ren); cnt++; } else { fprintf(stderr, "Error renaming [%s] to [%s]\n", out, in); // Can't help if that fails rename(ren, in); } } else { fprintf(stderr, "Error renaming [%s] to [%s]\n", in, ren); unlink(out); } cnt++; } else { fprintf(stderr, "Error processing: [%s]\n", namelist[n]->d_name); } free(namelist[n]); } free(namelist); return cnt; } int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "usage: %s infile outfile | -d directory\n", argv[0]); return -1; } if (!strcmp(argv[1], "-d")) { gar_xor_dir(argv[2]); } else { if (strcmp(argv[1], argv[2])) { gar_xor_file(argv[1], argv[2]); } else { char buf[4096]; sprintf(buf, "%s.tmp", argv[1]); if (gar_xor_file(argv[1], buf) > -1) { unlink(argv[1]); rename(buf, argv[1]); } } } return 0; } libgarmin-0~svn320/utils/garxtract.c000066400000000000000000000022551112544465000176420ustar00rootroot00000000000000#include #include #include #include "libgarmin.h" #include #include #include static int debug = 10; static void logfn(char *file, int line, int level, char *fmt, ...) { va_list ap; if (level > debug) return; va_start(ap, fmt); fprintf(stdout, "%s:%d:%d|", file, line, level); vfprintf(stdout, fmt, ap); va_end(ap); } static struct gar * get_gar(void) { struct gar *g; g = gar_init(NULL, logfn); if (!g) return NULL; return g; } int main(int argc, char **argv) { struct gimg *g; struct gar * gar; int fd; if (argc < 3) { fprintf(stderr, "%s garmin.img file\n", argv[0]); return -1; } #warning FIXME gar_img_load returns int find the image in the list gar = get_gar(); if (gar_img_load(gar, argv[1], 0) < 0) { fprintf(stderr, "Failed to load:[%s]\n", argv[1]); return 0; } g = gar_get_dskimg(gar, NULL); if (g) { fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0660); if (fd > -1) { if (gar_fat_file2fd(g, argv[2], fd) < 0) { unlink(argv[2]); } close(fd); } } else { fprintf(stderr, "Failed to find dskimg! Run %s on a .img file\n", argv[0]); } gar_free(gar); return 0; }