|
View:
New views
1 Messages
—
Rating Filter:
Alert me
|
|
|
Write support for binary lmxHi,
I sat down a while and implemented write support for the binary lmx format. I also implicitly fixed some mistakes in the lmx xml format: - XML files support UTF-8, so no need to convert special characters - Shortnames are now handled just like in gpx - There was a missing space in the xsi:schemaLocation - indentation is now with tabs just like it is generated by my Nokia N82 - added a test to testo for the binary format - I also added a bit to the lmx documentation Feel free to fine tune the documentation as I am not a native english speaker. Unfortunately, just after I finished this, I realized that my mobile does not support the binary format at all, so I won't use this in production. But I hope this is of use for someone else. However, it was a good practice :-) Regards, Christian [lmx_binary.diff] diff --git a/lmx.c b/lmx.c index f40762b..84fd561 100644 --- a/lmx.c +++ b/lmx.c @@ -32,11 +32,15 @@ static gbfile *ofd; static waypoint *wpt_tmp; char *urllink, *urllinkt; +static char *binary = NULL; #define MYNAME "lmx" static arglist_t lmx_args[] = { + { "binary", &binary, + "Compact binary representation", + NULL, ARGTYPE_BOOL, ARG_NOMINMAX }, ARG_TERMINATOR }; @@ -57,61 +61,181 @@ lmx_wr_deinit(void) gbfclose(ofd); } +static char * +lmx_stag(int tag) +{ + switch (tag) { + case 0xC5: return "lmx"; + case 0x46: return "landmarkCollection"; + case 0x47: return "landmark"; + case 0x48: return "name"; + case 0x49: return "description"; + case 0x4A: return "coordinates"; + case 0x4B: return "latitude"; + case 0x4C: return "longitude"; + case 0x4D: return "altitude"; + case 0x4E: return "horizontalAccuracy"; + case 0x4F: return "verticalAccuracy"; + case 0x50: return "timeStamp"; + case 0x51: return "coverageRadius"; + case 0x52: return "category"; + case 0x53: return "id"; + case 0x54: return "addressInfo"; + case 0x55: return "country"; + case 0x56: return "countryCode"; + case 0x57: return "state"; + case 0x58: return "county"; + case 0x59: return "city"; + case 0x5A: return "district"; + case 0x5B: return "postalCode"; + case 0x5C: return "crossing1"; + case 0x5D: return "crossing2"; + case 0x5E: return "street"; + case 0x5F: return "buildingName"; + case 0x60: return "buildingFloor"; + case 0x61: return "buildingZone"; + case 0x62: return "buildingRoom"; + case 0x63: return "extension"; + case 0x64: return "phoneNumber"; + case 0x65: return "mediaLink"; + case 0x66: return "mime"; + case 0x67: return "url"; + default: return 0; + } +} + static void -lmx_write_xml(int indent_level, const char *tag, const char *data) +lmx_indent(int count) { int i; - char *tmp_ent = xml_entitize(data); + for (i=0; i<count; i++) + gbfputc('\t', ofd); +} - for (i = 0; i < indent_level; i++) { - gbfputs(" ", ofd); +static void +lmx_start_tag(int tag, int indent) +{ + if (binary) + gbfputc(tag, ofd); + else { + lmx_indent(indent); + gbfprintf(ofd, "<lm:%s>", lmx_stag(tag)); } +} - gbfprintf(ofd, "<%s>%s</%s>\n", tag, tmp_ent, tag); +static void +lmx_end_tag(int tag, int indent) +{ + if (binary) + gbfputc(0x01, ofd); + else { + lmx_indent(indent); + gbfprintf(ofd, "</lm:%s>\n", lmx_stag(tag)); + } +} - xfree(tmp_ent); +static void +lmx_write_xml(int tag, const char *data, int indent) +{ + lmx_start_tag(tag, indent); + + if (binary) { + gbfputc(0x03, ofd); // inline string follows + gbfputcstr(data, ofd); + } + else { + char *tmp_ent = xml_entitize(data); + gbfputs(tmp_ent, ofd); + xfree(tmp_ent); + } + + lmx_end_tag(tag, 0); } static void lmx_print(const waypoint *wpt) { - gbfprintf(ofd, " <lm:landmark>\n"); - if (wpt->shortname) { - lmx_write_xml(4, "lm:name", global_opts.synthesize_shortnames ? wpt->description : wpt->shortname); + const char *oname; + char *odesc; + char tbuf[100]; + + /* + * Desparation time, try very hard to get a good shortname + */ + odesc = wpt->notes; + if (!odesc) { + odesc = wpt->description; + } + if (!odesc) { + odesc = wpt->shortname; + } + + oname = global_opts.synthesize_shortnames ? odesc : wpt->shortname; + + lmx_start_tag(0x47, 2); // landmark + if (!binary) gbfputc('\n', ofd); + if (oname) { + lmx_write_xml(0x48, oname, 3); // name } if (wpt->description) { - lmx_write_xml(4, "lm:description", wpt->description); + lmx_write_xml(0x49, wpt->description, 3); // description } - gbfprintf(ofd, " <lm:coordinates>\n"); - gbfprintf(ofd, " <lm:latitude>%f</lm:latitude>\n", wpt->latitude); - gbfprintf(ofd, " <lm:longitude>%f</lm:longitude>\n",wpt->longitude); + lmx_start_tag(0x4A, 3); // coordinates + if (!binary) gbfputc('\n', ofd); + + sprintf(tbuf, "%f", wpt->latitude); + lmx_write_xml(0x4B, tbuf, 4); // latitude + + sprintf(tbuf, "%f", wpt->longitude); + lmx_write_xml(0x4C, tbuf, 4); // longitude + if (wpt->altitude && (wpt->altitude != unknown_alt)) { - gbfprintf(ofd, " <lm:altitude>%f</lm:altitude>\n",wpt->altitude); + sprintf(tbuf, "%f", wpt->altitude); + lmx_write_xml(0x4D, tbuf, 4); // altitude } - gbfprintf(ofd, " </lm:coordinates>\n"); + lmx_end_tag(0x4A, 3); // coordinates if (wpt->url && wpt->url[0]) { - gbfprintf(ofd, " <lm:mediaLink>\n"); + lmx_start_tag(0x65, 3); // mediaLink + if (!binary) gbfputc('\n', ofd); if (wpt->url_link_text) - lmx_write_xml(5,"lm:name", wpt->url_link_text); - lmx_write_xml(5, "lm:url", wpt->url); - gbfprintf(ofd, " </lm:mediaLink>\n"); + lmx_write_xml(0x48, wpt->url_link_text, 4); // name + lmx_write_xml(0x67, wpt->url, 4); // url + lmx_end_tag(0x65, 3); // mediaLink } - gbfprintf(ofd, " </lm:landmark>\n"); + lmx_end_tag(0x47, 2); // landmark } static void lmx_write(void) { - gbfprintf(ofd, "<?xml version=\"1.0\" ?>\n"); - gbfprintf(ofd, "<lm:lmx xmlns:lm=\"http://www.nokia.com/schemas/location/landmarks/1/0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.nokia.com/schemas/location/landmarks/1/0/lmx.xsd\">"); + if (binary) { + gbfputc(0x03, ofd); // WBXML version 1.3 + gbfputuint16(0x04A4, ofd); // "-//NOKIA//DTD LANDMARKS 1.0//EN" + gbfputc(106, ofd); // Charset=UTF-8 + gbfputc(0x00, ofd); // empty string table + gbfputc(0xC5, ofd); // lmx + gbfputc(0x05, ofd); // xmlns=http://www.nokia.com/schemas/location/landmarks/ + gbfputc(0x85, ofd); // 1/0/ + gbfputc(0x06, ofd); // xmlns:xsi= + gbfputc(0x86, ofd); // http://www.w3.org/2001/XMLSchema-instance + gbfputc(0x07, ofd); // xsi:schemaLocation=http://www.nokia.com/schemas/location/landmarks/ + gbfputc(0x85, ofd); // 1/0/ + gbfputc(0x87, ofd); // whitespace + gbfputc(0x88, ofd); // lmx.xsd + gbfputc(0x01, ofd); // END lmx attributes + } else { + gbfprintf(ofd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); + gbfprintf(ofd, "<lm:lmx xmlns:lm=\"http://www.nokia.com/schemas/location/landmarks/1/0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.nokia.com/schemas/location/landmarks/1/0/ lmx.xsd\">\n"); + } - gbfprintf(ofd, " <lm:landmarkCollection>\n"); + lmx_start_tag(0x46, 1); // landmarkCollection + if (!binary) gbfputc('\n', ofd); waypt_disp_all(lmx_print); - gbfprintf(ofd, " </lm:landmarkCollection>\n"); - gbfprintf(ofd, "</lm:lmx>\n"); + lmx_end_tag(0x46, 1); // landmarkCollection + lmx_end_tag(0xC5, 0); // lmx } /* @@ -242,5 +366,5 @@ ff_vecs_t lmx_vecs = { lmx_write, NULL, lmx_args, - CET_CHARSET_ASCII, 0 /* CET-REVIEW */ + CET_CHARSET_UTF8, 0 /* CET-REVIEW */ }; diff --git a/reference/binary.lmx b/reference/binary.lmx new file mode 100644 index 0000000..cceb86e Binary files /dev/null and b/reference/binary.lmx differ diff --git a/reference/nokia.lmx b/reference/nokia.lmx index 1807707..01331e8 100644 --- a/reference/nokia.lmx +++ b/reference/nokia.lmx @@ -1,112 +1,113 @@ -<?xml version="1.0" ?> -<lm:lmx xmlns:lm="http://www.nokia.com/schemas/location/landmarks/1/0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.nokia.com/schemas/location/landmarks/1/0/lmx.xsd"> <lm:landmarkCollection> - <lm:landmark> - <lm:name>GCEBB</lm:name> - <lm:description>Mountain Bike Heaven by susy1313</lm:description> - <lm:coordinates> - <lm:latitude>35.972033</lm:latitude> - <lm:longitude>-87.134700</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=3771</lm:url> - </lm:mediaLink> - </lm:landmark> - <lm:landmark> - <lm:name>GC1A37</lm:name> - <lm:description>The Troll by a182pilot & Family</lm:description> - <lm:coordinates> - <lm:latitude>36.090683</lm:latitude> - <lm:longitude>-86.679550</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=6711</lm:url> - </lm:mediaLink> - </lm:landmark> - <lm:landmark> - <lm:name>GC1C2B</lm:name> - <lm:description>Dive Bomber by JoGPS & family</lm:description> - <lm:coordinates> - <lm:latitude>35.996267</lm:latitude> - <lm:longitude>-86.620117</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=7211</lm:url> - </lm:mediaLink> - </lm:landmark> - <lm:landmark> - <lm:name>GC25A9</lm:name> - <lm:description>FOSTER by JoGPS & Family</lm:description> - <lm:coordinates> - <lm:latitude>36.038483</lm:latitude> - <lm:longitude>-86.648617</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=9641</lm:url> - </lm:mediaLink> - </lm:landmark> - <lm:landmark> - <lm:name>GC2723</lm:name> - <lm:description>Logan Lighthouse by JoGps & Family</lm:description> - <lm:coordinates> - <lm:latitude>36.112183</lm:latitude> - <lm:longitude>-86.741767</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=10019</lm:url> - </lm:mediaLink> - </lm:landmark> - <lm:landmark> - <lm:name>GC2B71</lm:name> - <lm:description>Ganier Cache by Susy1313</lm:description> - <lm:coordinates> - <lm:latitude>36.064083</lm:latitude> - <lm:longitude>-86.790517</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=11121</lm:url> - </lm:mediaLink> - </lm:landmark> - <lm:landmark> - <lm:name>GC309F</lm:name> - <lm:description>Shy's Hill by FireFighterEng33</lm:description> - <lm:coordinates> - <lm:latitude>36.087767</lm:latitude> - <lm:longitude>-86.809733</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=12447</lm:url> - </lm:mediaLink> - </lm:landmark> - <lm:landmark> - <lm:name>GC317A</lm:name> - <lm:description>GittyUp by JoGPS / Warner Parks</lm:description> - <lm:coordinates> - <lm:latitude>36.057500</lm:latitude> - <lm:longitude>-86.892000</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=12666</lm:url> - </lm:mediaLink> - </lm:landmark> - <lm:landmark> - <lm:name>GC317D</lm:name> - <lm:description>Inlighting by JoGPS / Warner Parks</lm:description> - <lm:coordinates> - <lm:latitude>36.082800</lm:latitude> - <lm:longitude>-86.867283</lm:longitude> - </lm:coordinates> - <lm:mediaLink> - <lm:name>Cache Details</lm:name> - <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=12669</lm:url> - </lm:mediaLink> - </lm:landmark> - </lm:landmarkCollection> +<?xml version="1.0" encoding="UTF-8"?> +<lm:lmx xmlns:lm="http://www.nokia.com/schemas/location/landmarks/1/0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.nokia.com/schemas/location/landmarks/1/0/ lmx.xsd"> + <lm:landmarkCollection> + <lm:landmark> + <lm:name>GCEBB</lm:name> + <lm:description>Mountain Bike Heaven by susy1313</lm:description> + <lm:coordinates> + <lm:latitude>35.972033</lm:latitude> + <lm:longitude>-87.134700</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=3771</lm:url> + </lm:mediaLink> + </lm:landmark> + <lm:landmark> + <lm:name>GC1A37</lm:name> + <lm:description>The Troll by a182pilot & Family</lm:description> + <lm:coordinates> + <lm:latitude>36.090683</lm:latitude> + <lm:longitude>-86.679550</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=6711</lm:url> + </lm:mediaLink> + </lm:landmark> + <lm:landmark> + <lm:name>GC1C2B</lm:name> + <lm:description>Dive Bomber by JoGPS & family</lm:description> + <lm:coordinates> + <lm:latitude>35.996267</lm:latitude> + <lm:longitude>-86.620117</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=7211</lm:url> + </lm:mediaLink> + </lm:landmark> + <lm:landmark> + <lm:name>GC25A9</lm:name> + <lm:description>FOSTER by JoGPS & Family</lm:description> + <lm:coordinates> + <lm:latitude>36.038483</lm:latitude> + <lm:longitude>-86.648617</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=9641</lm:url> + </lm:mediaLink> + </lm:landmark> + <lm:landmark> + <lm:name>GC2723</lm:name> + <lm:description>Logan Lighthouse by JoGps & Family</lm:description> + <lm:coordinates> + <lm:latitude>36.112183</lm:latitude> + <lm:longitude>-86.741767</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=10019</lm:url> + </lm:mediaLink> + </lm:landmark> + <lm:landmark> + <lm:name>GC2B71</lm:name> + <lm:description>Ganier Cache by Susy1313</lm:description> + <lm:coordinates> + <lm:latitude>36.064083</lm:latitude> + <lm:longitude>-86.790517</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=11121</lm:url> + </lm:mediaLink> + </lm:landmark> + <lm:landmark> + <lm:name>GC309F</lm:name> + <lm:description>Shy's Hill by FireFighterEng33</lm:description> + <lm:coordinates> + <lm:latitude>36.087767</lm:latitude> + <lm:longitude>-86.809733</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=12447</lm:url> + </lm:mediaLink> + </lm:landmark> + <lm:landmark> + <lm:name>GC317A</lm:name> + <lm:description>GittyUp by JoGPS / Warner Parks</lm:description> + <lm:coordinates> + <lm:latitude>36.057500</lm:latitude> + <lm:longitude>-86.892000</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=12666</lm:url> + </lm:mediaLink> + </lm:landmark> + <lm:landmark> + <lm:name>GC317D</lm:name> + <lm:description>Inlighting by JoGPS / Warner Parks</lm:description> + <lm:coordinates> + <lm:latitude>36.082800</lm:latitude> + <lm:longitude>-86.867283</lm:longitude> + </lm:coordinates> + <lm:mediaLink> + <lm:name>Cache Details</lm:name> + <lm:url>http://www.geocaching.com/seek/cache_details.asp?ID=12669</lm:url> + </lm:mediaLink> + </lm:landmark> + </lm:landmarkCollection> </lm:lmx> diff --git a/testo b/testo index 2134fb8..4edd485 100755 --- a/testo +++ b/testo @@ -1298,6 +1298,8 @@ compare ${REFERENCE}/umsonstdraussen.gpx ${TMPDIR}/umsonstdraussen.gpx # gpsbabel -i lmx -f ${REFERENCE}/nokia.lmx -o lmx -F ${TMPDIR}/nokia.lmx compare ${REFERENCE}/nokia.lmx ${TMPDIR}/nokia.lmx +gpsbabel -i lmx -f ${REFERENCE}/nokia.lmx -o lmx,binary -F ${TMPDIR}/binary.lmx +bincompare ${REFERENCE}/binary.lmx ${TMPDIR}/binary.lmx # # Swiss Map (.xol) tests diff --git a/xmldoc/formats/lmx.xml b/xmldoc/formats/lmx.xml index 8f512a8..f668be4 100644 --- a/xmldoc/formats/lmx.xml +++ b/xmldoc/formats/lmx.xml @@ -1,6 +1,14 @@ <para> -This format supports Nokia Landmark Exchange (LMX) files used by several -Nokia phones. GPSBabel supports only the traditional XML format and -not the compressed binary format. +This format supports +<ulink url="http://sw.nokia.com/id/9001c8de-c19e-41a0-87d3-5be4297e4d4c/S60_Platform_Landmarks_Exchange_Specification_v1_0_en.pdf"> +Nokia Landmark Exchange (LMX) files</ulink> used by several Nokia phones. +GPSBabel supports the traditional XML format for reading and writing. The +compressed binary format (WBXML) can be written, but most current Nokia phones +do not support it (confirmed with N82 and N95). +</para> +<para> +With this format, landmarks can be imported into the landmark store of the +mobile phone. This landmark store is then used to display them on a map with +several applications. The most common ones are the pre-installed Ovi Maps (or +its predecessor Nokia Maps) and Google Maps Mobile. </para> - diff --git a/xmldoc/formats/options/lmx-binary.xml b/xmldoc/formats/options/lmx-binary.xml new file mode 100644 index 0000000..dbf05fb --- /dev/null +++ b/xmldoc/formats/options/lmx-binary.xml @@ -0,0 +1,9 @@ +<para> +This option specifies if you want to write the compressed binary format (WBXML) +instead of the XML format. However, most current Nokia phones do only support +the XML format (confirmed with N82 and N95). +</para> +<para> +This option has no effect when used for input, only reading the traditional XML +format is supported. +</para> ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Gpsbabel-code mailing list http://www.gpsbabel.org Gpsbabel-code@... https://lists.sourceforge.net/lists/listinfo/gpsbabel-code |
| Free embeddable forum powered by Nabble | Forum Help |