1 /*
2 Garmin icon tables
3 Based on information provided by Ian Cowley, Sigurd Humerfelt,
4 and Garmin MapSource
5
6 Copyright (C) 2003-2007 Robert Lipe, robertlipe@usa.net
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
21 */
22
23 #include "garmin_tables.h"
24 #include "jeeps/gpsmath.h"
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #define MYNAME "garmin_tables"
30
31 /* MapSource 4.13 */
32 icon_mapping_t garmin_icon_table[] = {
33 /* mps pcx desc */
34 { 107, 16384, "Airport" },
35 { 73, 8204, "Amusement Park" },
36 { 55, 169, "Ball Park" },
37 { 6, 6, "Bank" },
38 { 13, 13, "Bar" },
39 { 104, 8244, "Beach" },
40 { 1, 1, "Bell" },
41 { 37, 150, "Boat Ramp" },
42 { 74, 8205, "Bowling" },
43 { 93, 8233, "Bridge" },
44 { 94, 8234, "Building" },
45 { 38, 151, "Campground" },
46 { 56, 170, "Car" },
47 { 75, 8206, "Car Rental" },
48 { 76, 8207, "Car Repair" },
49 { 95, 8235, "Cemetery" },
50 { 96, 8236, "Church" },
51 { 65, 179, "Circle with X" },
52 { 72, 8203, "City (Capitol)" },
53 { 71, 8200, "City (Large)" },
54 { 70, 8199, "City (Medium)" },
55 { 69, 8198, "City (Small)" },
56 { 69, 8198, "Small City" },
57 { 97, 8237, "Civil" },
58 { 119, 8262, "Contact, Afro" },
59 { 120, 8272, "Contact, Alien" },
60 { 121, 8258, "Contact, Ball Cap" },
61 { 122, 8259, "Contact, Big Ears" },
62 { 123, 8271, "Contact, Biker" },
63 { 124, 8273, "Contact, Bug" },
64 { 125, 8274, "Contact, Cat" },
65 { 126, 8275, "Contact, Dog" },
66 { 127, 8263, "Contact, Dreadlocks" },
67 { 128, 8264, "Contact, Female1" },
68 { 129, 8265, "Contact, Female2" },
69 { 130, 8266, "Contact, Female3" },
70 { 131, 8261, "Contact, Goatee" },
71 { 132, 8268, "Contact, Kung-Fu" },
72 { 133, 8276, "Contact, Pig" },
73 { 134, 8270, "Contact, Pirate" },
74 { 135, 8267, "Contact, Ranger" },
75 { 136, 8257, "Contact, Smiley" },
76 { 137, 8260, "Contact, Spike" },
77 { 138, 8269, "Contact, Sumo" },
78 { 52, 165, "Controlled Area" },
79 { 89, 8220, "Convenience Store" },
80 { 98, 8238, "Crossing" },
81 { 51, 164, "Dam" },
82 { 53, 166, "Danger Area" },
83 { 87, 8218, "Department Store" },
84 { 4, 4, "Diver Down Flag 1" },
85 { 5, 5, "Diver Down Flag 2" },
86 { 41, 154, "Drinking Water" },
87 { 63, 177, "Exit" },
88 { 77, 8208, "Fast Food" },
89 { 7, 7, "Fishing Area" },
90 { 78, 8209, "Fitness Center" },
91 { 64, 178, "Flag" },
92 { 105, 8245, "Forest" },
93 { 8, 8, "Gas Station" },
94 { 117, 8255, "Geocache" },
95 { 118, 8256, "Geocache Found" },
96 { 99, 8239, "Ghost Town" },
97 { 113, 16393, "Glider Area" },
98 { 68, 8197, "Golf Course" },
99 { 2, 2, "Diamond, Green" },
100 { 15, 15, "Square, Green" },
101 { 108, 16388, "Heliport" },
102 { 9, 9, "Horn" },
103 { 57, 171, "Hunting Area" },
104 { 44, 157, "Information" },
105 { 100, 8240, "Levee" },
106 { 12, 12, "Light" },
107 { 90, 8221, "Live Theater" },
108 { 59, 173, "Lodging" },
109 { 59, 173, "Hotel" },
110 { 20, 21, "Man Overboard" },
111 { 0, 0, "Anchor" },
112 { 43, 156, "Medical Facility" },
113 { 66, 8195, "Mile Marker" },
114 { 101, 8241, "Military" },
115 { 60, 174, "Mine" },
116 { 79, 8210, "Movie Theater" },
117 { 80, 8211, "Museum" },
118 { 21, 22, "Navaid, Amber" },
119 { 22, 23, "Navaid, Black" },
120 { 23, 24, "Navaid, Blue" },
121 { 24, 25, "Navaid, Green" },
122 { 25, 26, "Navaid, Green/Red" },
123 { 26, 27, "Navaid, Green/White" },
124 { 27, 28, "Navaid, Orange" },
125 { 28, 29, "Navaid, Red" },
126 { 29, 30, "Navaid, Red/Green" },
127 { 30, 31, "Navaid, Red/White" },
128 { 31, 32, "Navaid, Violet" },
129 { 32, 33, "Navaid, White" },
130 { 33, 34, "Navaid, White/Green" },
131 { 34, 35, "Navaid, White/Red" },
132 { 102, 8242, "Oil Field" },
133 { 115, 16395, "Parachute Area" },
134 { 46, 159, "Park" },
135 { 45, 158, "Parking Area" },
136 { 81, 8212, "Pharmacy" },
137 { 47, 160, "Picnic Area" },
138 { 82, 8213, "Pizza" },
139 { 83, 8214, "Post Office" },
140 { 109, 16389, "Private Field" },
141 { 36, 37, "Radio Beacon" },
142 { 3, 3, "Diamond, Red" },
143 { 16, 16, "Square, Red" },
144 { 10, 10, "Residence" },
145 { 10, 10, "House" },
146 { 11, 11, "Restaurant" },
147 { 54, 167, "Restricted Area" },
148 { 39, 152, "Restroom" },
149 { 84, 8215, "RV Park" },
150 { 91, 8226, "Scales" },
151 { 48, 161, "Scenic Area" },
152 { 85, 8216, "School" },
153 { 116, 16402, "Seaplane Base" },
154 { 19, 19, "Shipwreck" },
155 { 58, 172, "Shopping Center" },
156 { 112, 16392, "Short Tower" },
157 { 40, 153, "Shower" },
158 { 49, 162, "Skiing Area" },
159 { 14, 14, "Skull and Crossbones" },
160 { 110, 16390, "Soft Field" },
161 { 86, 8217, "Stadium" },
162 { 106, 8246, "Summit" },
163 { 50, 163, "Swimming Area" },
164 { 111, 16391, "Tall Tower" },
165 { 42, 155, "Telephone" },
166 { 92, 8227, "Toll Booth" },
167 { 67, 8196, "TracBack Point" },
168 { 61, 175, "Trail Head" },
169 { 62, 176, "Truck Stop" },
170 { 103, 8243, "Tunnel" },
171 { 114, 16394, "Ultralight Area" },
172 { 139, 8282, "Water Hydrant" }, /* new in MapSource V5 */
173 { 18, 18, "Waypoint" },
174 { 17, 17, "Buoy, White" },
175 { 35, 36, "Dot, White" },
176 { 88, 8219, "Zoo" },
177
178 /* Custom icons. The spec reserves 7680-8191 for the custom
179 * icons on the C units, Quest, 27xx, 276, 296, and other units.
180 * Note that firmware problems on the earlier unit result in these
181 * being mangled, so be sure you're on a version from at least
182 * late 2005.
183 * { -2, 7680, "Custom 0" },
184 * ....
185 * { -2, 8192, "Custom 511" },
186 */
187 /* MapSource V6.x */
188
189 { 140, 8286, "Flag, Red" },
190 { 141, 8284, "Flag, Blue" },
191 { 142, 8285, "Flag, Green" },
192 { 143, 8289, "Pin, Red" },
193 { 144, 8287, "Pin, Blue" },
194 { 145, 8288, "Pin, Green" },
195 { 146, 8292, "Block, Red" },
196 { 147, 8290, "Block, Blue" },
197 { 148, 8291, "Block, Green" },
198 { 149, 8293, "Bike Trail" },
199 { 150, 181, "Fishing Hot Spot Facility" },
200 { 151, 8249, "Police Station"},
201 { 152, 8251, "Ski Resort" },
202 { 153, 8252, "Ice Skating" },
203 { 154, 8253, "Wrecker" },
204 { 155, 184, "Anchor Prohibited" },
205 { 156, 185, "Beacon" },
206 { 157, 186, "Coast Guard" },
207 { 158, 187, "Reef" },
208 { 159, 188, "Weed Bed" },
209 { 160, 189, "Dropoff" },
210 { 161, 190, "Dock" },
211 { 162, 191, "Marina" },
212 { 163, 192, "Bait and Tackle" },
213 { 164, 193, "Stump" },
214
215 /* New in Garmin protocol spec from June 2006. Extracted from
216 * spec and fed through some horrible awk to add ones we didn't
217 * have before but normalized for consistency. */
218 { -1, 8359, "Asian Food" },
219 { 167, 8296, "Circle, Blue" },
220 { 168, 8299, "Diamond, Blue" },
221 { 178, 8317, "Letter A, Blue" },
222 { 181, 8318, "Letter B, Blue" },
223 { 184, 8319, "Letter C, Blue" },
224 { 187, 8320, "Letter D, Blue" },
225 { 190, 8341, "Number 0, Blue" },
226 { 193, 8342, "Number 1, Blue" },
227 { 196, 8343, "Number 2, Blue" },
228 { 199, 8344, "Number 3, Blue" },
229 { 202, 8345, "Number 4, Blue" },
230 { 205, 8346, "Number 5, Blue" },
231 { 208, 8347, "Number 6, Blue" },
232 { 211, 8348, "Number 7, Blue" },
233 { 214, 8349, "Number 8, Blue" },
234 { 217, 8350, "Number 9, Blue" },
235 { 171, 8302, "Oval, Blue" },
236 { 174, 8305, "Rectangle, Blue" },
237 { 175, 8308, "Square, Blue" },
238 { 218, 8351, "Triangle, Blue" },
239 { -1, 8254, "Border Crossing (Port Of Entry)" },
240 { -1, 182, "Bottom Conditions" },
241 { -1, 8360, "Deli" },
242 { -1, 8228, "Elevation point" },
243 { -1, 8229, "Exit without services" },
244 { -1, 16398, "First approach fix" },
245 { -1, 8250, "Gambling/casino" },
246 { -1, 8232, "Geographic place name, land" },
247 { -1, 8230, "Geographic place name, Man-made" },
248 { -1, 8231, "Geographic place name, water" },
249 { 166, 8295, "Circle, Green" },
250 { 177, 8313, "Letter A, Green" },
251 { 180, 8315, "Letter B, Green" },
252 { 183, 8314, "Letter C, Green" },
253 { 186, 8316, "Letter D, Green" },
254 { 189, 8331, "Number 0, Green" },
255 { 192, 8332, "Number 1, Green" },
256 { 195, 8333, "Number 2, Green" },
257 { 198, 8334, "Number 3, Green" },
258 { 201, 8335, "Number 4, Green" },
259 { 204, 8336, "Number 5, Green" },
260 { 207, 8337, "Number 6, Green" },
261 { 210, 8338, "Number 7, Green" },
262 { 213, 8339, "Number 8, Green" },
263 { 216, 8340, "Number 9, Green" },
264 { 170, 8301, "Oval, Green" },
265 { 173, 8304, "Rectangle, Green" },
266 { 219, 8352, "Triangle, Green" },
267 { -1, 16385, "Intersection" },
268 { -1, 8201, "Intl freeway hwy" },
269 { -1, 8202, "Intl national hwy" },
270 { -1, 8361, "Italian food" },
271 { -1, 8248, "Large exit without services" },
272 { -1, 8247, "Large Ramp intersection" },
273 { -1, 16399, "Localizer Outer Marker" },
274 { -1, 16400, "Missed approach point" },
275 { -1, 16386, "Non-directional beacon" },
276 { -1, 168, "Null" },
277 { -1, 180, "Open 24 Hours" },
278 { -1, 8222, "Ramp intersection" },
279 { 165, 8294, "Circle, Red" },
280 { 176, 8309, "Letter A, Red" },
281 { 179, 8310, "Letter B, Red" },
282 { 182, 8311, "Letter C, Red" },
283 { 185, 8312, "Letter D, Red" },
284 { 188, 8321, "Number 0, Red" },
285 { 191, 8322, "Number 1, Red" },
286 { 194, 8323, "Number 2, Red" },
287 { 197, 8324, "Number 3, Red" },
288 { 200, 8325, "Number 4, Red" },
289 { 203, 8326, "Number 5, Red" },
290 { 206, 8327, "Number 6, Red" },
291 { 209, 8328, "Number 7, Red" },
292 { 212, 8329, "Number 8, Red" },
293 { 215, 8330, "Number 9, Red" },
294 { 169, 8300, "Oval, Red" },
295 { 172, 8303, "Rectangle, Red" },
296 { 220, 8353, "Triangle, Red" },
297 { -1, 8362, "Seafood" },
298 { -1, 8194, "State Hwy" },
299 { -1, 8363, "Steak" },
300 { -1, 8223, "Street Intersection" },
301 { -1, 16401, "TACAN" },
302 { -1, 183, "Tide/Current PRediction Station" },
303 { -1, 191, "U Marina" },
304 { -1, 8193, "US hwy" },
305 { -1, 193, "U stump" },
306 { -1, 16387, "VHF Omni-range" },
307 { -1, 16397, "VOR-DME" },
308 { -1, 16396, "VOR/TACAN" },
309
310 /* This block new on 1/15 from the Mapsource 6.12 beta */
311 { 221, -1, "Contact, Blonde" },
312 { 222, -1, "Contact, Clown" },
313 { 223, -1, "Contact, Glasses" },
314 { 224, -1, "Contact, Panda" },
315 { 225, -1, "Multi-Cache" },
316 { 226, -1, "Letterbox Cache" },
317 { 227, -1, "Puzzle Cache" },
318 { 228, -1, "Library" },
319 { 229, -1, "Ground Transportation" },
320 { 230, -1, "City Hall" },
321 { 231, -1, "Winery" },
322 { 232, -1, "ATV" },
323 { 233, -1, "Big Game" },
324 { 234, -1, "Blind" },
325 { 235, -1, "Blood Trail" },
326 { 236, -1, "Cover" },
327 { 237, -1, "Covey" },
328 { 238, -1, "Food Source" },
329 { 239, -1, "Furbearer" },
330 { 240, -1, "Lodge" },
331 { 241, -1, "Small Game" },
332 { 242, -1, "Animal Tracks" },
333 { 243, -1, "Treed Quarry" },
334 { 244, -1, "Tree Stand" },
335 { 245, -1, "Truck" },
336 { 246, -1, "Upland Game" },
337 { 247, -1, "Waterfowl" },
338 { 248, -1, "Water Source" },
339
340
341 { -1, -1, NULL },
342 };
343
344 icon_mapping_t garmin_smart_icon_table[] = {
345 /* Additional (optional, activated with -Si) icons */
346 { 92, 8227, "Micro-Cache" }, /* icon for "Toll Booth" */
347 { 48, 161, "Virtual cache" }, /* icon for "Scenic Area" */
348 { 86, 8217, "Multi-Cache" }, /* icon for "Stadium" */
349 { 44, 157, "Unknown Cache" }, /* icon for "Information" */
350 { 64, 178, "Locationless (Reverse) Cache" }, /* Icon for "Flag" */
351 { 83, 8214, "Post Office" }, /* Icon for "Post Office" */
352 { 47, 160, "Event Cache" }, /* Icon for "Event" */
353 { 90, 8221, "Webcam Cache" }, /* Icon for "Live Theatre" */
354 { -1, -1, NULL }
355 };
356
357 /* ICAO coutry code table */
358
359 /* source: http://en.wikipedia.org/wiki/ICAO_airport_code */
360
361 gt_country_code_t gt_country_codes[] = {
362 { "ZM,", "Mongolia" },
363 { "ZK,", "North Korea" },
364 { "Z*,", "China" },
365 { "Y*,", "Australia" },
366 { "WS,", "Singapore" },
367 { "WM,", "Brunei/Malaysia" },
368 { "WB,", "Malaysia" },
369 { "WA,WI,WQ,WR,", "Indonesia" },
370 { "VV,", "Vietnam" },
371 { "VT,", "Thailand" },
372 { "VR,", "Maldives" },
373 { "VQ,", "Bhutan" },
374 { "VN,", "Nepal" },
375 { "VM,", "Macau" },
376 { "VL,", "Laos" },
377 { "VH,", "Hong Kong" },
378 { "VG,", "Bangladesh" },
379 { "VD,", "Kampuchea" },
380 { "VC,", "Sri Lanka" },
381 { "VB,VY,", "Myanmar/Burma" },
382 { "VA,VE,VI,VO,", "India" },
383 { "UR,", "Kazakhstan/Russia" },
384 { "UT,", "Kazakhstan/Tadzhikistan/Turkmenistan/Uzbekistan" },
385 { "UM,", "Belorussia/Russia" },
386 { "UK,", "Ukraine" },
387 { "UB,", "Azerbaijan" },
388 { "UA,", "Kazakhstan/Kirgizia" },
389 { "U*,", "Russia" },
390 { "TX,", "Bermuda" },
391 { "TV,", "St Vincent and the Grenadines" },
392 { "TU,", "British Virgin Islands" },
393 { "TT,", "Trinidad and Tobago" },
394 { "TR,", "Montserrat Island" },
395 { "TQ,", "Anguilla" },
396 { "TN,", "Aruba/Neth Antilles" },
397 { "TL,", "St Lucia" },
398 { "TK,", "St Kitts/Nevis Islands" },
399 { "TJ,", "Puerto Rico" },
400 { "TG,", "Grenada" },
401 { "TF,", "Guadeloupe/Martinique" },
402 { "TD,", "Dominica" },
403 { "TB,", "Barbados" },
404 { "TA,", "Antigua" },
405 { "SY,", "Guyana" },
406 { "SV,", "Venezuela" },
407 { "SU,", "Uruguay" },
408 { "SP,", "Peru" },
409 { "SO,", "French Guiana" },
410 { "SM,", "Suriname" },
411 { "SL,", "Bolivia" },
412 { "SK,", "Colombia/San Andres" },
413 { "SG,", "Paraguay" },
414 { "SF,", "Falkland Islands" },
415 { "SE,", "Ecuador" },
416 { "SC,", "Chile/Easter Island" },
417 { "SB,SD,SN,SS,SW,", "Brazil" },
418 { "SA,", "Argentina" },
419 { "S1,", "Antarctica (Argentina/Chile)" },
420 { "RP,", "Philippines" },
421 { "RK,", "South Korea" },
422 { "RJ,", "Japan" },
423 { "RC,", "Taiwan" },
424 { "PW,", "Wake Island" },
425 { "PT,", "Caroline Islands/Micronesia/Palau" },
426 { "PM,", "Midway Islands" },
427 { "PK,", "Marshall Islands" },
428 { "PJ,", "Johnston Atoll" },
429 { "PG,", "Guam/Mariana Islands/Northern Mariana Islands" },
430 { "PC,", "Kiribati" },
431 { "P", "Oakland Octa" },
432 { "OY,", "Yemen Arab Rep" },
433 { "OT,", "Qatar" },
434 { "OS,", "Syria" },
435 { "OR,", "Iraq" },
436 { "OP,", "Pakistan" },
437 { "OO,", "Oman" },
438 { "OM,", "United Arab Emirates" },
439 { "OL,", "Lebanon" },
440 { "OK,", "Kuwait" },
441 { "OJ,", "Jordan" },
442 { "OI,", "Iran" },
443 { "OE,", "Saudi Arabia" },
444 { "OB,", "Bahrain" },
445 { "OA,", "Afghanistan" },
446 { "NZ,PL,", "New Zealand" },
447 { "NW,", "New Caledonia" },
448 { "NV,", "Vanuatu" },
449 { "NT,", "French Polynesia/Society Islands/Tuamotu Islands" },
450 { "NS,", "American Samoa/Western Samoa" },
451 { "NL,", "Futuna Island/Wallis Island" },
452 { "NI,", "Niue" },
453 { "NG,", "Kiribati/Tuvalu" },
454 { "NF,", "Fiji Island/Tonga" },
455 { "NC,", "Cook Islands" },
456 { "MZ,", "Belize" },
457 { "MY,", "Bahamas" },
458 { "MW,", "Cayman Islands" },
459 { "MU,", "Cuba" },
460 { "MT,", "Haiti" },
461 { "MS,", "El Salvador" },
462 { "MR,", "Costa rica" },
463 { "MP,", "Panama" },
464 { "MN,", "Nicaragua" },
465 { "MM,", "Mexico" },
466 { "MK,", "Jamaica" },
467 { "MI,TI,", "Virgin Islands (U.S.)" },
468 { "MH,", "Honduras" },
469 { "MG,", "Guatemala" },
470 { "MD,", "Dominican Republic" },
471 { "MB,", "Turks Island/Caicos Island" },
472 { "LZ,", "Slovakia" },
473 { "LY,", "Yugoslavia" },
474 { "LX,", "Gibraltar" },
475 { "LW,", "Macedonia" },
476 { "LV,", "Gaza" },
477 { "LU,", "Moldova" },
478 { "LT,", "Turkey" },
479 { "LS,", "Switzerland" },
480 { "LR,", "Romania" },
481 { "LQ,", "Bosnia-Herzegovina" },
482 { "LP,", "Portugal/Azores/Madeira Islands" },
483 { "LO,", "Austria" },
484 { "LN,", "Monaco" },
485 { "LM,", "Malta" },
486 { "LL,", "Israel/Jerusalem" },
487 { "LK,", "Czech" },
488 { "LI,", "Italy" },
489 { "LH,", "Hungary" },
490 { "LG,", "Slovenia" },
491 { "LG,", "Greece" },
492 { "LF,", "France" },
493 { "LF,", "Miquelon Island/St Pierre Island" },
494 { "LE,", "Spain" },
495 { "LD,", "Croatia" },
496 { "LC,", "Cyprus/Turkey (Northern Cyprus)" },
497 { "LB,", "Bulgaria" },
498 { "LA,", "Albania" },
499 { "K*,X*,PA,PB,PF,PJ,PL,PM,PO,PP,PH,PW,", "United States of America" },
500 { "HU,", "Uganda" },
501 { "HT,", "Tanzania" },
502 { "HS,", "Sudan" },
503 { "HR,", "Rwanda" },
504 { "HL,", "Libya, Spa Jamahiriya" },
505 { "HK,", "Kenya" },
506 { "HH,", "Eritrea" },
507 { "HE,", "Egypt" },
508 { "HD,HF,", "Djibouti" },
509 { "HC,", "Somalia" },
510 { "HB,", "Burundi" },
511 { "HA,", "Ethiopia" },
512 { "GV,", "Cape Verde" },
513 { "GU,", "Guinea Tepublic" },
514 { "GQ,", "Mauritania" },
515 { "GO,", "Senegal" },
516 { "GM,", "Morocco/Ad Dakhla/La'Youn" },
517 { "GL,", "Liberia" },
518 { "GG,", "Guinea-Bissau" },
519 { "GF,", "Sierra Leone" },
520 { "GE,", "Melilla" },
521 { "GC,", "Canary Island" },
522 { "GB,", "Gambia" },
523 { "GA,", "Mali" },
524 { "FZ,", "Democratic Republic of Congo" },
525 { "FY,", "Namibia" },
526 { "FX,", "Lesotho" },
527 { "FW,", "Malawi" },
528 { "FV,", "Zimbabwe" },
529 { "FT,", "Chad" },
530 { "FS,", "Seychelles" },
531 { "FQ,", "Mozambique" },
532 { "FP,", "Sao Tome & Principe" },
533 { "FO,", "Gabon" },
534 { "FN,", "Angola" },
535 { "FM,", "Madagascar/Comoros/Reunion/Mayotte Islands" },
536 { "FL,", "Zambia" },
537 { "FK,", "Cameroon" },
538 { "FJ,", "Chagos Archipelago/British Indian Ocean Territory" },
539 { "FI,", "Mauritius" },
540 { "FH,", "Ascension Island/St Helena Island" },
541 { "FG,", "Equitorial Guinea" },
542 { "FE,", "Central African Republic" },
543 { "FD,", "Swaziland" },
544 { "FC,", "Congo" },
545 { "FB,", "Botswana" },
546 { "FA,", "South African Republic" },
547 { "EY,", "Lithuania" },
548 { "EV,", "Latvia" },
549 { "ES,", "Sweden" },
550 { "EP,", "Poland" },
551 { "EN,", "Norway" },
552 { "EL,", "Luxembourg" },
553 { "EK,", "Denmark/Faroe Island" },
554 { "EI,", "Ireland" },
555 { "EH,", "Netherlands" },
556 { "EG,LX,", "United Kingdom" },
557 { "EF,", "Finland" },
558 { "EE,", "Estonia" },
559 { "ED,ET,", "Germany" },
560 { "EB,", "Belgium" },
561 { "DX,", "Togo" },
562 { "DT,", "Tunisia" },
563 { "DR,", "Niger" },
564 { "DN,", "Nigeria" },
565 { "DI,", "Ivory Coast" },
566 { "DG,", "Ghana" },
567 { "DF,", "Burkina Faso" },
568 { "DB,", "Benin" },
569 { "DA,", "Algeria" },
570 { "C*,", "Canada" },
571 { "BI,", "Iceland" },
572 { "BG,", "Greenland" },
573 { "AY,", "Papua New Guinea" },
574 { "AN,", "Nauru" },
575 { "AG,", "Solomon Island" },
576 { NULL, NULL }
577 };
578
579 /* gt_waypt_classes: gdb internal order */
580 char* gt_waypt_class_names[] = {
581 "User Waypoint",
582 "Airport",
583 "Intersection",
584 "NDB",
585 "VOR",
586 "Runway Threshold",
587 "Airport Intersection",
588 "Airport NDB",
589 "Map Point",
590 "Map Area",
591 "Map Intersection",
592 "Map Address",
593 "Map Line",
594 NULL
595 };
596
597 /* gt_display_mode_names: this order is used by most devices */
598 char* gt_display_mode_names[] = {
599 "Symbol & Name",
600 "Symbol",
601 "Symbol & Description"
602 };
603
604 typedef struct {
605 const char* shortname;
606 const char* longname;
607 grid_type grid;
608 } grid_mapping_t;
609
610 /* gt_mps_grid_names: !!! degree sign substituted with '*' !!! */
611
612 grid_mapping_t gt_mps_grid_names[] = {
613 { "ddd", "Lat/Lon hddd.ddddd*", grid_lat_lon_ddd },
614 { "dmm", "Lat/Lon hddd*mm.mmm'", grid_lat_lon_dmm },
615 { "dms", "Lat/Lon hddd*mm'ss.s\"", grid_lat_lon_dms },
616 { "bng", "British National Grid", grid_bng },
617 { "utm", "UTM", grid_utm },
618 { "swiss", "Swiss grid", grid_swiss },
619 { NULL, NULL, (grid_type) 0 }
620 };
621
622 /* gt_mps_datum_names: */
623
624 typedef struct {
625 const char* jeeps_name;
626 const char* mps_name;
627 } datum_mapping_t;
628
629 /* will be continued (when requested) */
630 static datum_mapping_t gt_mps_datum_names[] = {
631 { "Alaska-NAD27", "NAD27 Alaska" },
632 { "Bahamas NAD27", "NAD27 Bahamas" },
633 { "Canada_Mean(NAD27)", "NAD27 Canada" },
634 { "Canal_Zone_(NAD27)", "NAD27 Canal Zone" },
635 { "Carribean NAD27", "NAD27 Caribbean" },
636 { "Cent America NAD27", "NAD27 Central" },
637 { "Cuba NAD27", "NAD27 Cuba" },
638 { "Geodetic Datum 49", "Geodetic Datum '49" },
639 { "Greenland NAD27", "NAD27 Greenland" },
640 { "Mexico NAD27", "NAD27 Mexico" },
641 { "North America 83", "NAD83" },
642 { "OSGB36", "Ord Srvy Grt Britn" },
643 { NULL, NULL }
644 };
645
646 typedef struct garmin_color_s {
647 const char* name;
648 gbint32 rgb;
649 } garmin_color_t;
650
651 static garmin_color_t gt_colors[] = {
652 { "Unknown", unknown_color },
653 { "Black", 0x000000 },
654 { "DarkRed", 0x00008B },
655 { "DarkGreen", 0x006400 },
656 { "DarkYellow", 0x008B8B },
657 { "DarkBlue", 0x8B0000 },
658 { "DarkMagenta", 0x8B008B },
659 { "DarkCyan", 0x8B8B00 },
660 { "LightGray", 0xD3D3D3 },
661 { "DarkGray", 0xA9A9A9 },
662 { "Red", 0x0000FF },
663 { "Green", 0x008000 },
664 { "Yellow", 0x00FFFF },
665 { "Blue", 0xFF0000 },
666 { "Magenta", 0xFF00FF },
667 { "Cyan", 0xFFFF00 },
668 { "White", 0xFFFFFF },
669 { "Transparent", unknown_color }, /* Currently not handled */
670 { NULL }
671 };
672
673 #define GT_COLORS_CT ((sizeof(gt_colors) / sizeof(gt_colors[0])) - 1)
674
675 unsigned char
gt_switch_display_mode_value(const unsigned char display_mode,const int protoid,const char device)676 gt_switch_display_mode_value(const unsigned char display_mode, const int protoid, const char device)
677 {
678 if (device) {
679 switch (protoid) {
680
681 case 103:
682 case 107:
683 case 108:
684 case 109:
685 case 110:
686 return display_mode & 3;
687 case 104:
688 switch (display_mode) {
689 case 0:
690 case 1:
691 return gt_display_mode_symbol;
692 case 3:
693 return gt_display_mode_symbol_and_name;
694 case 5:
695 return gt_display_mode_symbol_and_comment;
696 }
697 case 155:
698 switch (display_mode) {
699 case 1:
700 return gt_display_mode_symbol;
701 case 3:
702 return gt_display_mode_symbol_and_name;
703 case 5:
704 return gt_display_mode_symbol_and_comment;
705 }
706 }
707 return gt_display_mode_symbol_and_name;
708 } else {
709 switch (protoid) {
710
711 case 103:
712 case 107:
713 case 108:
714 case 109:
715 case 110:
716 return display_mode & 3;
717 case 104:
718 case 155:
719 switch (display_mode) {
720 case gt_display_mode_symbol:
721 return 1;
722 case gt_display_mode_symbol_and_name:
723 return 3;
724 case gt_display_mode_symbol_and_comment:
725 return 5;
726 }
727 }
728 return 0;
729 }
730 }
731
732 char*
gt_find_desc_from_icon_number(const int icon,garmin_formats_e garmin_format,int * dynamic)733 gt_find_desc_from_icon_number(const int icon, garmin_formats_e garmin_format, int* dynamic)
734 {
735 icon_mapping_t* i;
736 char custom[] = "Custom 63 ";
737
738 if ((garmin_format == GDB) && (icon >= 500) && (icon <= 563)) {
739 snprintf(custom, sizeof(custom), "Custom %d", icon - 500);
740 *dynamic = 1;
741 return xstrdup(custom);
742 }
743
744 if ((garmin_format == PCX) && (icon >= 7680) && (icon <= 8191)) {
745 snprintf(custom, sizeof(custom), "Custom %d", icon - 7680);
746 *dynamic = 1;
747 return xstrdup(custom);
748 }
749
750 if (dynamic) {
751 *dynamic = 0;
752 }
753
754 for (i = garmin_icon_table; i->icon; i++) {
755 switch (garmin_format) {
756 case MAPSOURCE:
757 case GDB:
758 if (icon == i->mpssymnum) {
759 return (char*)i->icon;
760 }
761 break;
762 case PCX:
763 case GARMIN_SERIAL:
764 if (icon == i->pcxsymnum) {
765 return (char*)i->icon;
766 }
767 break;
768 default:
769 fatal(MYNAME ": unknown garmin format.\n");
770 }
771 }
772 return DEFAULT_ICON_DESCR;
773 }
774
gt_find_icon_number_from_desc(const char * desc,garmin_formats_e garmin_format)775 int gt_find_icon_number_from_desc(const char* desc, garmin_formats_e garmin_format)
776 {
777 static int find_flag = 0;
778 icon_mapping_t* i;
779 int def_icon = DEFAULT_ICON_VALUE;
780 int n;
781
782 if (!desc) {
783 return def_icon;
784 }
785
786 /*
787 * If we were given a numeric icon number as a description
788 * (i.e. 8255), just return that.
789 */
790 n = atoi(desc);
791 if (n) {
792 return n;
793 }
794
795 if (0 == case_ignore_strncmp(desc, "Custom ", 7)) {
796 int base = 0;
797 if (garmin_format == GDB) {
798 base = 500;
799 }
800 if (garmin_format == PCX) {
801 base = 7680;
802 }
803 if (base) {
804 n = atoi(&desc[7]);
805 return n + base;
806 }
807 }
808
809 for (i = garmin_smart_icon_table; global_opts.smart_icons && i->icon; i++) {
810 if (case_ignore_strcmp(desc,i->icon) == 0) {
811 switch (garmin_format) {
812 case MAPSOURCE:
813 case GDB:
814 return i->mpssymnum;
815 case PCX:
816 case GARMIN_SERIAL:
817 return i->pcxsymnum;
818 default:
819 fatal(MYNAME ": unknown garmin format.\n");
820 }
821 }
822 }
823 for (i = garmin_icon_table; i->icon; i++) {
824 if (case_ignore_strcmp(desc,i->icon) == 0) {
825 switch (garmin_format) {
826 case MAPSOURCE:
827 case GDB:
828 return i->mpssymnum;
829 case PCX:
830 case GARMIN_SERIAL:
831 return i->pcxsymnum;
832 default:
833 fatal(MYNAME ": unknown garmin format.\n");
834 }
835 }
836 }
837
838 /*
839 * try to handle some complex icon names: i.e. "Blue Diamond" and "Diamond, Blue"
840 * "find_flag" prevents us from a possible endless loop
841 */
842
843 if (find_flag == 0) {
844 char** prefix;
845 char* prefixes[] = {"White ", "Red ", "Green ", "Blue ", "Black ", NULL};
846
847 for (prefix = prefixes; *prefix != NULL; prefix++) {
848 int len = strlen(*prefix);
849
850 if (case_ignore_strncmp(desc, *prefix, len) == 0) {
851 char buff[64];
852 int result;
853
854 snprintf(buff, sizeof(buff), "%s, %s", &desc[len], *prefix);
855 rtrim(buff);
856
857 find_flag = 1;
858 result = gt_find_icon_number_from_desc(buff, garmin_format);
859 find_flag = 0;
860
861 return result;
862 }
863 }
864 }
865 return def_icon;
866 }
867
868 const char*
gt_get_icao_country(const char * cc)869 gt_get_icao_country(const char* cc)
870 {
871 gt_country_code_t* x = >_country_codes[0];
872
873 if ((cc == NULL) || (*cc == '\0')) {
874 return NULL;
875 }
876
877 do {
878 const char* ccx = x->cc;
879 while (ccx != NULL) {
880 if (strncmp(ccx, cc, 2) == 0) {
881 return x->country;
882 }
883 if ((ccx[0] == cc[0]) && (ccx[1] == '*')) {
884 return x->country;
885 }
886 ccx = strchr(ccx, ',');
887 if (ccx == NULL) {
888 break;
889 }
890 ccx++;
891 }
892 x++;
893 } while (x->cc != NULL);
894 return NULL;
895 }
896
897 const char*
gt_get_icao_cc(const char * country,const char * shortname)898 gt_get_icao_cc(const char* country, const char* shortname)
899 {
900 static char res[3];
901 gt_country_code_t* x = >_country_codes[0];
902
903 if ((country == NULL) || (*country == '\0')) {
904 const char* test;
905 if (shortname == NULL) {
906 return NULL;
907 }
908 switch (strlen(shortname)) {
909 case 3:
910 strncpy(res, shortname, 1);
911 break;
912 case 4:
913 strncpy(res, shortname, 2);
914 break;
915 default:
916 return NULL;
917 }
918 test = gt_get_icao_country(res);
919 if (test != NULL) {
920 return res;
921 } else {
922 return NULL;
923 }
924 }
925
926 do {
927 if (case_ignore_strcmp(country, x->country) != 0) {
928 x++;
929 continue;
930 }
931
932 if (strlen(x->cc) <= 3) {
933 strncpy(res, x->cc, 3);
934 if (res[1] == '*') {
935 res[1] = '\0';
936 } else {
937 res[2] = '\0';
938 }
939 return res;
940 }
941 if (shortname && (strlen(shortname) == 4)) {
942 const char* ccx = x->cc;
943
944 strncpy(res, shortname, 2);
945 res[2] = '\0';
946 while (ccx != NULL) {
947 if (strncmp(ccx, res, 2) == 0) {
948 return res;
949 }
950 if ((ccx[0] == res[0]) && (ccx[1] == '*')) {
951 return res;
952 }
953 ccx = strchr(ccx, ',');
954 if (ccx == NULL) {
955 break;
956 }
957 ccx++;
958 }
959 }
960 return NULL;
961 } while (x->country != NULL);
962 return NULL;
963 }
964
965 grid_type
gt_lookup_grid_type(const char * grid_name,const char * module)966 gt_lookup_grid_type(const char* grid_name, const char* module)
967 {
968 grid_mapping_t* g;
969
970 for (g = gt_mps_grid_names; (g->shortname); g++) {
971 if ((case_ignore_strcmp(grid_name, g->shortname) == 0) ||
972 (case_ignore_strcmp(grid_name, g->longname) == 0)) {
973 return g->grid;
974 }
975 }
976
977 fatal("%s: Unsupported grid (%s)! See GPSBabel help for supported grids.\n",
978 module, grid_name);
979
980 return grid_unknown; /* (warnings) */
981 }
982
983 const char*
gt_get_mps_grid_longname(const grid_type grid,const char * module)984 gt_get_mps_grid_longname(const grid_type grid, const char* module)
985 {
986 if ((grid < GRID_INDEX_MIN) || (grid > GRID_INDEX_MAX))
987 fatal("%s: Grid index out of range %d (%d..%d)!",
988 module, (int) grid,
989 (int)GRID_INDEX_MIN, (int)GRID_INDEX_MAX);
990 return gt_mps_grid_names[grid].longname;
991 }
992
993 const char*
gt_get_mps_datum_name(const int datum_index)994 gt_get_mps_datum_name(const int datum_index)
995 {
996 char* result;
997 datum_mapping_t* d;
998
999 result = GPS_Math_Get_Datum_Name(datum_index);
1000
1001 for (d = gt_mps_datum_names; (d->jeeps_name); d++)
1002 if (case_ignore_strcmp(result, d->jeeps_name) == 0) {
1003 return d->mps_name;
1004 }
1005
1006 return result;
1007 }
1008
1009 int
gt_lookup_datum_index(const char * datum_str,const char * module)1010 gt_lookup_datum_index(const char* datum_str, const char* module)
1011 {
1012 datum_mapping_t* d;
1013 int result;
1014 const char* name = datum_str;
1015
1016 for (d = gt_mps_datum_names; (d->jeeps_name); d++) {
1017 if (case_ignore_strcmp(name, d->mps_name) == 0) {
1018 name = d->jeeps_name;
1019 break;
1020 }
1021 }
1022
1023 result = GPS_Lookup_Datum_Index(name);
1024
1025 if (result < 0) {
1026 char* tmp;
1027 xasprintf(&tmp, "%s mean", datum_str);
1028 result = GPS_Lookup_Datum_Index(tmp);
1029 xfree(tmp);
1030 }
1031
1032 is_fatal(result < 0,
1033 "%s: Unsupported datum (%s)! See GPSBabel help for supported datums.",
1034 module, datum_str);
1035
1036 return result;
1037 }
1038
1039 gbuint32
gt_color_value(const int garmin_index)1040 gt_color_value(const int garmin_index)
1041 {
1042 if ((garmin_index >= 0) && (garmin_index < GT_COLORS_CT)) {
1043 return gt_colors[garmin_index].rgb;
1044 } else {
1045 return unknown_color; /* -1 */
1046 }
1047 }
1048
1049 gbuint32
gt_color_value_by_name(const char * name)1050 gt_color_value_by_name(const char* name)
1051 {
1052 int i;
1053
1054 for (i = 0; i < GT_COLORS_CT; i++)
1055 if (case_ignore_strcmp(gt_colors[i].name, name) == 0) {
1056 return gt_colors[i].rgb;
1057 }
1058
1059 return gt_colors[0].rgb;
1060 }
1061
1062 int
gt_color_index_by_name(const char * name)1063 gt_color_index_by_name(const char* name)
1064 {
1065 int i;
1066
1067 for (i = 0; i < GT_COLORS_CT; i++)
1068 if (case_ignore_strcmp(name, gt_colors[i].name) == 0) {
1069 return i;
1070 }
1071
1072 return 0; /* unknown */
1073 }
1074
1075 int
gt_color_index_by_rgb(const int rgb)1076 gt_color_index_by_rgb(const int rgb)
1077 {
1078 int i;
1079
1080 for (i = 0; i < GT_COLORS_CT; i++)
1081 if (rgb == gt_colors[i].rgb) {
1082 return i;
1083 }
1084
1085 return 0; /* unknown */
1086 }
1087
1088 const char*
gt_color_name(const int garmin_index)1089 gt_color_name(const int garmin_index)
1090 {
1091 if ((garmin_index >= 0) && (garmin_index < GT_COLORS_CT)) {
1092 return gt_colors[garmin_index].name;
1093 } else {
1094 return gt_colors[0].name;
1095 }
1096 }
1097
1098 #if MAKE_TABLE
1099
1100 /*
1101 * Used to generate icon tables in appendix.
1102 * cc -DMAKE_TABLE garmin_tables.c fatal.o util.o globals.o -lm
1103 */
1104
cet_utf8_to_ucs4(const char * str,int * bytes,int * value)1105 int cet_utf8_to_ucs4(const char* str, int* bytes, int* value)
1106 {
1107 fatal("Should not be here.");
1108 }
1109
1110
1111 int
sortem(const void * a,const void * b)1112 sortem(const void* a, const void* b)
1113 {
1114 const icon_mapping_t* aa = a;
1115 const icon_mapping_t* bb = b;
1116
1117 // return aa->mpssymnum - bb->mpssymnum;
1118 return strcmp(aa->icon, bb->icon);
1119
1120 }
1121
main()1122 main()
1123 {
1124 icon_mapping_t* i;
1125 qsort(garmin_icon_table, sizeof(garmin_icon_table) / sizeof(garmin_icon_table[0]) - 1, sizeof(garmin_icon_table[0]), sortem);
1126 for (i = garmin_icon_table; i->icon; i++) {
1127 // printf("%03d\t%s\n", i->mpssymnum, i->icon);
1128 printf("<member>%s</member>\n", i->icon);
1129 }
1130 }
1131 #endif
1132