You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bushnell.cc 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. Read and write Bushnell files.
  3. Copyright (C) 2008, 2009 Robert Lipe (robertlipe+source@gpsbabel.org)
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include "defs.h"
  17. #include <math.h>
  18. #include <QtCore/QFileInfo>
  19. #define MYNAME "Bushnell"
  20. static gbfile* file_in;
  21. static QString ofname;
  22. static short_handle mkshort_handle = NULL;
  23. static
  24. arglist_t bushnell_args[] = {
  25. ARG_TERMINATOR
  26. };
  27. // Apparently, the icons are undocumented, so we made up names,
  28. // preferring them to be consistent with other brands where possiblde.
  29. typedef struct {
  30. const signed int symbol;
  31. const char* icon;
  32. } icon_mapping_t;
  33. icon_mapping_t bushnell_icons[] = {
  34. { 0x00, "Yellow Square"},
  35. { 0x01, "Blue Grey Circle" },
  36. { 0x02, "Yellow Diamond" },
  37. { 0x03, "Blue Asterisk" },
  38. { 0x04, "Blue Bulls Eye pointing NE" },
  39. { 0x05, "Red =O= on a 45 degree." },
  40. { 0x06, "House" },
  41. { 0x06, "Residence" },
  42. { 0x07, "Lodging" },
  43. { 0x08, "Hospital" },
  44. { 0x09, "Auto Repair" },
  45. { 0x09, "Car Repair" },
  46. { 0x0a, "Tools" },
  47. { 0x0b, "Gas" },
  48. { 0x0c, "Hiking" },
  49. { 0x0d, "Camping" },
  50. { 0x0e, "Picnic Area" },
  51. { 0x0f, "Deer Stand" },
  52. { 0x10, "Deer" },
  53. { 0x11, "Park" },
  54. { 0x11, "Tree" },
  55. { 0x12, "Highway Exit" },
  56. { 0x13, "Fjord"}, // Looks like a road narrows.
  57. { 0x14, "Bridge" },
  58. { 0x15, "Waypoint" }, // or golf hole/flag
  59. { 0x16, "Warning" }, // Caution Triangle with ! in it.
  60. { 0x17, "Bicycle" },
  61. { 0x18, "Blue Circle" }, // ? in it, undocumented icon.
  62. { 0x19, "Blue Diamond Checkmark" }, // undocumented.
  63. { 0x1a, "Camera" },
  64. { 0x1b, "Restaraunt" }, // "Fork/Knife (meal place?)"
  65. { 0x1c, "Restroom" }, // (man & Woman icon)"
  66. { 0x1d, "RV Park" }, // "Bus or RV (RV campground?)"
  67. { 0x1e, "Potable Water" }, // (faucet/glass or bucket)"
  68. { 0x1f, "Fishing" },
  69. { 0x20, "Anchor in square" },
  70. { 0x21, "Boat ramp/launch" },
  71. { 0x22, "Anchor" },
  72. { 0x23, "Bouy" },
  73. { 0x24, "Man Overboard?" },
  74. { 0x25, "Snow Skiing" },
  75. { 0x26, "Mouantin/Mountain Peak" },
  76. { 0x27, "Turkey Tracks/animal tracks" },
  77. { 0x28, "Bank" }, // "Cash (ATM MAybe)"
  78. { 0x29, "Bar" }, // "Martini undocumented"
  79. { 0x2a, "Lighthouse" },
  80. { 0x2b, "Tent" },
  81. { 0x2c, "Cresent Wrench or can opener" },
  82. { 0x2d, "School" }, //? White Building with tunnel looking door and flag on top."
  83. { 0x2f, "Information" }, // "i (info/internet maybe?)"
  84. { 0x30, "Picnic" }, //"Picnic table & Tree, maybe forest picnic or day use area?"
  85. { 0x31, "Phone" },
  86. { 0x32, "Letter/Envelope" },
  87. { 0x33, "Forest/Park Ranger" },
  88. { 0x34, "Fire department" }, //? Red Square building with yellow flag."
  89. { 0x35, "Shopping" },
  90. { 0x36, "Looks like Cross+hurricane symbol, strange also undocumented." },
  91. { 0x37, "Tunnel" },
  92. { 0x38, "Mountain/Summit" },
  93. { 0x39, "Square split diagonally with lines between... magnet maybe? undocumented" },
  94. { 0x3a, "Swimmer/swimming" },
  95. { 0x3b, "Officer? Looks like man leaned over holding blue cube..." },
  96. { 0x3c, "Parking" }, //"Car Parked"
  97. { 0x3d, "Airport" },
  98. { 0x3e, "Bus Terminal" }, // (guess) Loks like Bus under canopy."
  99. { 0x3f, "Red Cross" },
  100. { 0x40, "Red Buidling with flag, Fire Station maybe." },
  101. { 0x41, "Bus" },
  102. { 0x42, "Officer" }, // "see 3b: duplicate"
  103. { 0x43, "Railroad" },
  104. { 0x44, "Auto Ferry" },
  105. {-1, NULL}
  106. };
  107. static unsigned int
  108. bushnell_get_icon_from_name(QString name)
  109. {
  110. icon_mapping_t* t;
  111. if (name.isNull()) {
  112. name = "Waypoint";
  113. }
  114. for (t = bushnell_icons; t->icon > 0; t++) {
  115. if (0 == name.compare(t->icon, Qt::CaseInsensitive)) {
  116. return t->symbol;
  117. }
  118. }
  119. return 0;
  120. }
  121. static const char*
  122. bushnell_get_name_from_symbol(signed int s)
  123. {
  124. icon_mapping_t* t;
  125. for (t = bushnell_icons; t->icon > 0; t++) {
  126. if (s == t->symbol) {
  127. return t->icon;
  128. }
  129. }
  130. return "Waypoint";
  131. }
  132. static void
  133. rd_init(const QString& fname)
  134. {
  135. file_in = gbfopen_le(fname, "rb", MYNAME);
  136. }
  137. static void
  138. rd_deinit(void)
  139. {
  140. gbfclose(file_in);
  141. }
  142. static void
  143. wr_init(const QString& fname)
  144. {
  145. static char valid_chars [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789"
  146. ".-/\\~@#$%^&*()_+=<>"
  147. "abcdefghijklmnopqrstuvwxyz";
  148. // If user provided an extension in the pathname, whack it.
  149. ofname = fname;
  150. int suffix_len = QFileInfo(fname).suffix().length();
  151. if (suffix_len > 0) {
  152. /* drop the suffix and the period */
  153. ofname.chop(suffix_len + 1);
  154. }
  155. mkshort_handle = mkshort_new_handle();
  156. setshort_length(mkshort_handle, 19);
  157. setshort_goodchars(mkshort_handle, valid_chars);
  158. }
  159. static void
  160. wr_deinit(void)
  161. {
  162. mkshort_del_handle(&mkshort_handle);
  163. ofname.clear();
  164. }
  165. /*
  166. * Each file contains a single waypoint.
  167. */
  168. static void
  169. bushnell_read(void)
  170. {
  171. int32_t lat_tmp,lon_tmp;
  172. unsigned int proximity;
  173. unsigned int icon;
  174. Waypoint* wpt_tmp = new Waypoint;
  175. lat_tmp = gbfgetint32(file_in);
  176. lon_tmp = gbfgetint32(file_in);
  177. icon = gbfgetc(file_in);
  178. wpt_tmp->icon_descr = bushnell_get_name_from_symbol(icon);
  179. proximity = gbfgetc(file_in); // 1 = off, 3 = proximity alarm.
  180. (void) proximity;
  181. wpt_tmp->latitude = lat_tmp / 10000000.0;
  182. wpt_tmp->longitude = lon_tmp / 10000000.0;
  183. // Apparently this is always zero terminated, though it's never been
  184. // observed to be longer than 19 bytes + a null terminator.
  185. wpt_tmp->shortname = gbfgetstr(file_in);
  186. waypt_add(wpt_tmp);
  187. }
  188. static void
  189. bushnell_write_one(const Waypoint* wpt)
  190. {
  191. char tbuf[20]; // 19 text bytes + null terminator.
  192. char padding[2] = {0, 0};
  193. gbfile* file_out;
  194. static int wpt_count;
  195. QString fname(ofname);
  196. fname += "-";
  197. fname += QString::number(wpt_count++);
  198. fname += ".wpt";
  199. file_out = gbfopen_le(fname, "wb", MYNAME);
  200. gbfputint32(round(wpt->latitude * 10000000), file_out);
  201. gbfputint32(round(wpt->longitude * 10000000), file_out);
  202. gbfputc(bushnell_get_icon_from_name(wpt->icon_descr), file_out);
  203. gbfputc(0x01, file_out); // Proximity alarm. 1 == "off", 3 == armed.
  204. strncpy(tbuf, CSTRc(wpt->shortname), sizeof(tbuf));
  205. tbuf[sizeof(tbuf)-1] = 0;
  206. gbfwrite(tbuf, sizeof(tbuf), 1, file_out);
  207. // two padding bytes follow name.
  208. gbfwrite(padding, sizeof(padding), 1, file_out);
  209. gbfclose(file_out);
  210. }
  211. static void
  212. bushnell_write(void)
  213. {
  214. waypt_disp_all(bushnell_write_one);
  215. }
  216. ff_vecs_t bushnell_vecs = {
  217. ff_type_file,
  218. FF_CAP_RW_WPT,
  219. rd_init,
  220. wr_init,
  221. rd_deinit,
  222. wr_deinit,
  223. bushnell_read,
  224. bushnell_write,
  225. NULL,
  226. bushnell_args,
  227. CET_CHARSET_MS_ANSI, 0 /* Not really sure... */
  228. };