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 = &gt_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 = &gt_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