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.

an1.cc 29KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  1. /*
  2. Read DeLorme drawing files (.an1)
  3. Copyright (C) 2005-2014 Ron Parker and Robert Lipe.
  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 <stdlib.h> // atof
  18. #include <stdio.h> // sprintf
  19. #define MYNAME "an1"
  20. static gbfile* infile;
  21. static gbfile* outfile;
  22. static char* output_type = NULL;
  23. static char* road_changes = NULL;
  24. static char* nogc = NULL;
  25. static char* nourl = NULL;
  26. static char* opt_symbol = NULL;
  27. static char* opt_color = NULL;
  28. static char* opt_zoom = NULL;
  29. static char* opt_wpt_type = NULL;
  30. static char* opt_radius = NULL;
  31. static short output_type_num = 0;
  32. static short opt_zoom_num = 0;
  33. static long opt_color_num = 0;
  34. static short wpt_type_num = 0;
  35. static short last_read_type = 0;
  36. static double radius = 0.0;
  37. static long serial=10000;
  38. static long rtserial=1;
  39. typedef struct roadchange {
  40. long type;
  41. char* name;
  42. } roadchange;
  43. roadchange* roadchanges = NULL;
  44. static
  45. arglist_t an1_args[] = {
  46. {
  47. "type", &output_type, "Type of .an1 file",
  48. "", ARGTYPE_STRING, ARG_NOMINMAX
  49. },
  50. {
  51. "road", &road_changes, "Road type changes",
  52. "", ARGTYPE_STRING, ARG_NOMINMAX
  53. },
  54. {
  55. "nogc", &nogc, "Do not add geocache data to description",
  56. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  57. },
  58. {
  59. "nourl", &nourl, "Do not add URLs to description",
  60. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  61. },
  62. {
  63. "deficon", &opt_symbol, "Symbol to use for point data",
  64. "Red Flag", ARGTYPE_STRING, ARG_NOMINMAX
  65. },
  66. {
  67. "color", &opt_color, "Color for lines or mapnotes",
  68. "red", ARGTYPE_STRING, ARG_NOMINMAX
  69. },
  70. {
  71. "zoom", &opt_zoom, "Zoom level to reduce points",
  72. NULL, ARGTYPE_INT, ARG_NOMINMAX
  73. },
  74. {
  75. "wpt_type", &opt_wpt_type,
  76. "Waypoint type",
  77. "", ARGTYPE_STRING, ARG_NOMINMAX
  78. },
  79. {
  80. "radius", &opt_radius, "Radius for circles",
  81. NULL, ARGTYPE_STRING, ARG_NOMINMAX
  82. },
  83. ARG_TERMINATOR
  84. };
  85. typedef struct guid {
  86. unsigned long l;
  87. unsigned short s[3];
  88. unsigned char c[6];
  89. } GUID;
  90. #include "an1sym.h"
  91. #define ReadShort(f) gbfgetint16(f)
  92. #define WriteShort(f,s) gbfputint16((s),f)
  93. #define ReadLong(f) gbfgetint32(f)
  94. #define WriteLong(f,l) gbfputint32((l),f)
  95. #define ReadDouble(f) gbfgetdbl(f)
  96. #define WriteDouble(f,d) gbfputdbl((d),f)
  97. static char*
  98. ReadString(gbfile* f, short len)
  99. {
  100. char* result = NULL;
  101. result = (char*)xcalloc(1, len + 1);
  102. if (len) {
  103. gbfread(result, 1, len, f);
  104. }
  105. return result;
  106. }
  107. #define ReadChar(f) (unsigned char) gbfgetc(f)
  108. #define WriteChar(f,c) gbfputc((unsigned char)(c),f)
  109. #define WriteString(f,s) gbfputs((s),f)
  110. static void
  111. ReadGuid(gbfile* f, GUID* guid)
  112. {
  113. int i = 0;
  114. guid->l = ReadLong(f);
  115. for (i = 0; i < 3; i++) {
  116. guid->s[i] = ReadShort(f);
  117. }
  118. for (i = 0; i < 6; i++) {
  119. guid->c[i] = ReadChar(f);
  120. }
  121. }
  122. static void
  123. WriteGuid(gbfile* f, GUID* guid)
  124. {
  125. int i = 0;
  126. WriteLong(f, guid->l);
  127. for (i = 0; i < 3; i++) {
  128. WriteShort(f, guid->s[i]);
  129. }
  130. for (i = 0; i < 6; i++) {
  131. WriteChar(f, guid->c[i]);
  132. }
  133. }
  134. static void
  135. Skip(gbfile* f,
  136. unsigned long distance)
  137. {
  138. gbfseek(f, distance, SEEK_CUR);
  139. }
  140. static double
  141. DecodeOrd(long ord)
  142. {
  143. return (double)((int32_t)(0x80000000 - ord)) / 0x800000;
  144. }
  145. static long
  146. EncodeOrd(double ord)
  147. {
  148. return (int32_t)(0x80000000 - (int32_t)(ord * 0x800000));
  149. }
  150. typedef struct {
  151. short hotspotxhi;
  152. long hotspoty;
  153. long unk1;
  154. GUID guid;
  155. char* name;
  156. } an1_symbol_record;
  157. typedef struct {
  158. format_specific_data fs;
  159. short magic;
  160. long unk1;
  161. long lon;
  162. long lat;
  163. short type;
  164. long height;
  165. long width;
  166. short unk2;
  167. short unk3;
  168. short serial;
  169. short unk4;
  170. unsigned char create_zoom;
  171. unsigned char visible_zoom;
  172. short unk5;
  173. double radius; /* in km */
  174. char* name;
  175. char* fontname;
  176. GUID guid;
  177. long fontcolor;
  178. long fontstyle;
  179. long fontsize;
  180. long outlineweight;
  181. long outlinecolor;
  182. long outlineflags;
  183. long fillcolor;
  184. long unk6;
  185. long fillflags;
  186. /* Added in SA2006/Topo 6.0 */
  187. short unk6_1;
  188. char* url;
  189. char* comment;
  190. long creation_time;
  191. long modification_time;
  192. char* image_name;
  193. } an1_waypoint_record;
  194. typedef struct {
  195. format_specific_data fs;
  196. short magic;
  197. long unk0;
  198. long lon;
  199. long lat;
  200. short unk1;
  201. } an1_vertex_record;
  202. typedef struct {
  203. format_specific_data fs;
  204. long roadtype;
  205. short serial;
  206. long unk2;
  207. short unk3;
  208. short type;
  209. long unk4;
  210. char* name;
  211. long lineweight;
  212. long linestyle;
  213. long linecolor;
  214. long opacity;
  215. long polyfillcolor;
  216. long unk6;
  217. long unk7;
  218. short unk8;
  219. long pointcount;
  220. } an1_line_record;
  221. static an1_waypoint_record* Alloc_AN1_Waypoint();
  222. void Destroy_AN1_Waypoint(void* vwpt)
  223. {
  224. an1_waypoint_record* wpt = (an1_waypoint_record*)vwpt;
  225. xfree(wpt->name);
  226. xfree(wpt->fontname);
  227. if (wpt->url) {
  228. xfree(wpt->url);
  229. }
  230. if (wpt->comment) {
  231. xfree(wpt->comment);
  232. }
  233. if (wpt->image_name) {
  234. xfree(wpt->image_name);
  235. }
  236. xfree(vwpt);
  237. }
  238. void Copy_AN1_Waypoint(void** vdwpt, void* vwpt)
  239. {
  240. an1_waypoint_record* wpt = (an1_waypoint_record*)vwpt;
  241. an1_waypoint_record* dwpt = Alloc_AN1_Waypoint();
  242. memcpy(dwpt, wpt, sizeof(an1_waypoint_record));
  243. dwpt->name = xstrdup(wpt->name);
  244. dwpt->fontname = xstrdup(wpt->fontname);
  245. dwpt->url = xstrdup(wpt->url);
  246. dwpt->comment = xstrdup(wpt->comment);
  247. dwpt->image_name = xstrdup(wpt->image_name);
  248. *vdwpt = (void*)dwpt;
  249. }
  250. static an1_waypoint_record* Alloc_AN1_Waypoint()
  251. {
  252. an1_waypoint_record* result = NULL;
  253. result = (an1_waypoint_record*)xcalloc(sizeof(*result), 1);
  254. result->fs.type = FS_AN1W;
  255. result->fs.copy = Copy_AN1_Waypoint;
  256. result->fs.destroy = Destroy_AN1_Waypoint;
  257. result->fs.convert = NULL;
  258. return result;
  259. }
  260. static an1_vertex_record* Alloc_AN1_Vertex();
  261. void Destroy_AN1_Vertex(void* vvertex)
  262. {
  263. xfree(vvertex);
  264. }
  265. void Copy_AN1_Vertex(void** vdvert, void* vvert)
  266. {
  267. an1_vertex_record* vert = (an1_vertex_record*)vvert;
  268. an1_vertex_record* dvert = Alloc_AN1_Vertex();
  269. memcpy(dvert, vert, sizeof(an1_vertex_record));
  270. *vdvert = (void*)dvert;
  271. }
  272. static an1_vertex_record* Alloc_AN1_Vertex()
  273. {
  274. an1_vertex_record* result = NULL;
  275. result = (an1_vertex_record*)xcalloc(sizeof(*result), 1);
  276. result->fs.type = FS_AN1V;
  277. result->fs.copy = Copy_AN1_Vertex;
  278. result->fs.destroy = Destroy_AN1_Vertex;
  279. result->fs.convert = NULL;
  280. return result;
  281. }
  282. static an1_line_record* Alloc_AN1_Line();
  283. void Destroy_AN1_Line(void* vline)
  284. {
  285. an1_line_record* line = (an1_line_record*)vline;
  286. xfree(line->name);
  287. xfree(vline);
  288. }
  289. void Copy_AN1_Line(void** vdline, void* vline)
  290. {
  291. an1_line_record* line = (an1_line_record*)vline;
  292. an1_line_record* dline = Alloc_AN1_Line();
  293. memcpy(dline, line, sizeof(an1_line_record));
  294. dline->name = xstrdup(line->name);
  295. *vdline = (void*)dline;
  296. }
  297. static an1_line_record* Alloc_AN1_Line()
  298. {
  299. an1_line_record* result = NULL;
  300. result = (an1_line_record*)xcalloc(sizeof(*result), 1);
  301. result->fs.type = FS_AN1L;
  302. result->fs.copy = Copy_AN1_Line;
  303. result->fs.destroy = Destroy_AN1_Line;
  304. result->fs.convert = NULL;
  305. return result;
  306. }
  307. static void Destroy_AN1_Symbol(an1_symbol_record* symbol)
  308. {
  309. xfree(symbol->name);
  310. }
  311. static void Read_AN1_Waypoint(gbfile* f, an1_waypoint_record* wpt)
  312. {
  313. unsigned short len;
  314. wpt->magic = ReadShort(f);
  315. wpt->unk1 = ReadLong(f);
  316. wpt->lon = ReadLong(f);
  317. wpt->lat = ReadLong(f);
  318. wpt->type = ReadShort(f);
  319. wpt->height = ReadLong(f);
  320. wpt->width = ReadLong(f);
  321. wpt->unk2 = ReadShort(f);
  322. wpt->unk3 = ReadShort(f);
  323. wpt->serial = ReadShort(f);
  324. wpt->unk4 = ReadShort(f);
  325. wpt->create_zoom = ReadChar(f);
  326. wpt->visible_zoom = ReadChar(f);
  327. wpt->unk5 = ReadShort(f);
  328. wpt->radius = ReadDouble(f);
  329. len = ReadShort(f);
  330. wpt->name = ReadString(f, len);
  331. if (len != strlen(wpt->name)) {
  332. /* This happens in 06/6.0 files that put extra data in the
  333. * name record for backward compatibility's sake */
  334. char* ofs = wpt->name + strlen(wpt->name) + 1;
  335. wpt->unk6_1 = le_read16(ofs);
  336. ofs += 2;
  337. len = le_read16(ofs);
  338. ofs += 2;
  339. if (len) {
  340. char* oldurlstr;
  341. /*
  342. * Trust URL encoded in new format over one in
  343. * old format if both are present. Whack the
  344. * name starting at '{URL='.
  345. */
  346. oldurlstr = strstr(wpt->name, "{URL=");
  347. if (oldurlstr) {
  348. *oldurlstr = 0;
  349. }
  350. wpt->url = (char*) xcalloc(len+1, 1);
  351. memcpy(wpt->url, ofs, len);
  352. ofs += len;
  353. }
  354. len = le_read16(ofs);
  355. ofs += 2;
  356. if (len) {
  357. wpt->comment = (char*) xcalloc(len+1, 1);
  358. memcpy(wpt->comment, ofs, len);
  359. ofs += len;
  360. }
  361. /* these are quadwords, presumably for year-2038 compat. */
  362. wpt->creation_time = le_read32(ofs);
  363. ofs += 8;
  364. wpt->modification_time = le_read32(ofs);
  365. ofs += 8;
  366. }
  367. if (wpt->type == 0x12) {
  368. /* 'image' type */
  369. ReadShort(f); /* length of font + filename */
  370. len = ReadShort(f);
  371. wpt->fontname = ReadString(f, len);
  372. len = ReadShort(f);
  373. wpt->image_name = ReadString(f, len);
  374. } else {
  375. len = ReadShort(f);
  376. wpt->fontname = ReadString(f, len);
  377. wpt->image_name = NULL;
  378. }
  379. ReadGuid(f, &wpt->guid);
  380. wpt->fontcolor = ReadLong(f);
  381. wpt->fontstyle = ReadLong(f);
  382. wpt->fontsize = ReadLong(f);
  383. wpt->outlineweight = ReadLong(f);
  384. wpt->outlinecolor = ReadLong(f);
  385. wpt->outlineflags = ReadLong(f);
  386. wpt->fillcolor = ReadLong(f);
  387. wpt->unk6 = ReadLong(f);
  388. wpt->fillflags = ReadLong(f);
  389. }
  390. static void Write_AN1_Waypoint(gbfile* f, an1_waypoint_record* wpt)
  391. {
  392. short len;
  393. WriteShort(f, wpt->magic);
  394. WriteLong(f, wpt->unk1);
  395. WriteLong(f, wpt->lon);
  396. WriteLong(f, wpt->lat);
  397. WriteShort(f, wpt->type);
  398. WriteLong(f, wpt->height);
  399. WriteLong(f, wpt->width);
  400. WriteShort(f, wpt->unk2);
  401. WriteShort(f, wpt->unk3);
  402. WriteShort(f, wpt->serial);
  403. WriteShort(f, wpt->unk4);
  404. WriteChar(f, wpt->create_zoom);
  405. WriteChar(f, wpt->visible_zoom);
  406. WriteShort(f, wpt->unk5);
  407. WriteDouble(f, wpt->radius);
  408. len = strlen(wpt->name) + 1 + 2 + 2 +
  409. (wpt->url ? strlen(wpt->url) : 0) + 2 +
  410. (wpt->comment ? strlen(wpt->comment) : 0) + 8 + 8;
  411. WriteShort(f, len);
  412. WriteString(f, wpt->name);
  413. WriteChar(f, 0); /* name string terminator */
  414. WriteShort(f, wpt->unk6_1);
  415. if (wpt->url) {
  416. WriteShort(f, strlen(wpt->url));
  417. WriteString(f, wpt->url);
  418. } else {
  419. WriteShort(f, 0);
  420. }
  421. if (wpt->comment) {
  422. WriteShort(f, strlen(wpt->comment));
  423. WriteString(f, wpt->comment);
  424. } else {
  425. WriteShort(f, 0);
  426. }
  427. WriteLong(f, wpt->creation_time);
  428. WriteLong(f, 0);
  429. WriteLong(f, wpt->modification_time);
  430. WriteLong(f, 0);
  431. if (wpt->type == 0x12) { /* image */
  432. len = 2 + (wpt->fontname ? strlen(wpt->fontname) : 0) +
  433. 2 + (wpt->image_name ? strlen(wpt->image_name) : 0);
  434. WriteShort(f, len);
  435. if (wpt->fontname) {
  436. len = strlen(wpt->fontname);
  437. WriteShort(f, len);
  438. WriteString(f, wpt->fontname);
  439. } else {
  440. WriteShort(f, 0);
  441. }
  442. if (wpt->image_name) {
  443. len = strlen(wpt->image_name);
  444. WriteShort(f, len);
  445. WriteString(f, wpt->image_name);
  446. } else {
  447. WriteShort(f, 0);
  448. }
  449. } else {
  450. len = strlen(wpt->fontname);
  451. WriteShort(f, len);
  452. WriteString(f, wpt->fontname);
  453. }
  454. WriteGuid(f, &wpt->guid);
  455. WriteLong(f, wpt->fontcolor);
  456. WriteLong(f, wpt->fontstyle);
  457. WriteLong(f, wpt->fontsize);
  458. WriteLong(f, wpt->outlineweight);
  459. WriteLong(f, wpt->outlinecolor);
  460. WriteLong(f, wpt->outlineflags);
  461. WriteLong(f, wpt->fillcolor);
  462. WriteLong(f, wpt->unk6);
  463. WriteLong(f, wpt->fillflags);
  464. }
  465. static void Read_AN1_Vertex(gbfile* f, an1_vertex_record* vertex)
  466. {
  467. vertex->magic = ReadShort(f);
  468. vertex->unk0 = ReadLong(f);
  469. vertex->lon = ReadLong(f);
  470. vertex->lat = ReadLong(f);
  471. vertex->unk1 = ReadShort(f);
  472. }
  473. static void Write_AN1_Vertex(gbfile* f, an1_vertex_record* vertex)
  474. {
  475. WriteShort(f, vertex->magic);
  476. WriteLong(f, vertex->unk0);
  477. WriteLong(f, vertex->lon);
  478. WriteLong(f, vertex->lat);
  479. WriteShort(f, vertex->unk1);
  480. }
  481. static void Read_AN1_Line(gbfile* f, an1_line_record* line)
  482. {
  483. short len;
  484. line->roadtype = ReadLong(f);
  485. line->serial = ReadShort(f);
  486. line->unk2 = ReadLong(f);
  487. line->unk3 = ReadShort(f);
  488. line->type = ReadShort(f);
  489. line->unk4 = ReadLong(f);
  490. len = ReadShort(f);
  491. line->name = ReadString(f, len);
  492. line->lineweight = ReadShort(f);
  493. line->linestyle = ReadLong(f);
  494. line->linecolor = ReadLong(f);
  495. line->opacity = ReadLong(f);
  496. line->polyfillcolor = ReadLong(f);
  497. line->unk6 = ReadLong(f);
  498. line->unk7 = ReadLong(f);
  499. line->unk8 = ReadShort(f);
  500. line->pointcount = ReadLong(f);
  501. }
  502. static void Write_AN1_Line(gbfile* f, an1_line_record* line)
  503. {
  504. short len;
  505. WriteLong(f, line->roadtype);
  506. WriteShort(f, line->serial);
  507. WriteLong(f, line->unk2);
  508. WriteShort(f, line->unk3);
  509. WriteShort(f, line->type);
  510. WriteLong(f, line->unk4);
  511. len = strlen(line->name);
  512. WriteShort(f, len);
  513. WriteString(f, line->name);
  514. WriteShort(f, (short) line->lineweight);
  515. WriteLong(f, line->linestyle);
  516. WriteLong(f, line->linecolor);
  517. WriteLong(f, line->opacity);
  518. WriteLong(f, line->polyfillcolor);
  519. WriteLong(f, line->unk6);
  520. WriteLong(f, line->unk7);
  521. WriteShort(f, line->unk8);
  522. WriteLong(f, line->pointcount);
  523. }
  524. static void Skip_AN1_IL(gbfile* f)
  525. {
  526. Skip(f, 26);
  527. }
  528. static void Skip_AN1_BM(gbfile* f)
  529. {
  530. unsigned long bmsize;
  531. unsigned long palettesize;
  532. unsigned long bmisize;
  533. unsigned long bitoffset;
  534. Skip(f, 8); /* BITMAPFILEHEADER fields 1-3 */
  535. bitoffset = ReadLong(f);
  536. bmisize = ReadLong(f);
  537. Skip(f, 16); /* BITMAPINFOHEADER fields 2-6 */
  538. bmsize = ReadLong(f);
  539. Skip(f, 16); /* BITMAPINFOHEADER fields 8-11 */
  540. palettesize = bitoffset - bmisize - 14;
  541. Skip(f, bmsize + palettesize);
  542. }
  543. static void Read_AN1_Symbol(gbfile* f, an1_symbol_record* symbol)
  544. {
  545. short len;
  546. /* This is just the high word of a long; we ate the low
  547. * word in the caller. Fortunately, we don't care. */
  548. symbol->hotspotxhi = ReadShort(f);
  549. symbol->hotspoty = ReadLong(f);
  550. symbol->unk1 = ReadLong(f);
  551. ReadGuid(f, &symbol->guid);
  552. len = ReadChar(f);
  553. symbol->name = ReadString(f, len);
  554. }
  555. static void Read_AN1_Header(gbfile* f)
  556. {
  557. unsigned short magic;
  558. unsigned short type;
  559. magic = ReadShort(f);
  560. (void) magic; // hush warning.
  561. type = ReadShort(f);
  562. last_read_type = type;
  563. }
  564. static void Write_AN1_Header(gbfile* f)
  565. {
  566. WriteShort(f, 11557);
  567. WriteShort(f, output_type_num);
  568. }
  569. static void Read_AN1_Bitmaps(gbfile* f)
  570. {
  571. long count;
  572. unsigned short magic;
  573. an1_symbol_record symbol;
  574. count = ReadLong(f);
  575. while (count) {
  576. magic = ReadShort(f);
  577. switch (magic) {
  578. case 0x4d42:
  579. Skip_AN1_BM(f);
  580. break;
  581. case 0x4c49:
  582. Skip_AN1_IL(f);
  583. break;
  584. default:
  585. Read_AN1_Symbol(f, &symbol);
  586. Destroy_AN1_Symbol(&symbol);
  587. count--;
  588. break;
  589. }
  590. }
  591. /* Read the symbol table */
  592. }
  593. static void Write_AN1_Bitmaps(gbfile* f)
  594. {
  595. /* On write, we don't output any bitmaps, so writing them
  596. * is just a matter of writing a count of zero */
  597. WriteLong(f, 0);
  598. }
  599. static void Read_AN1_Waypoints(gbfile* f)
  600. {
  601. unsigned long count = 0;
  602. unsigned long i = 0;
  603. an1_waypoint_record* rec = NULL;
  604. Waypoint* wpt_tmp;
  605. char* icon = NULL;
  606. ReadShort(f);
  607. count = ReadLong(f);
  608. for (i = 0; i < count; i++) {
  609. rec = Alloc_AN1_Waypoint();
  610. Read_AN1_Waypoint(f, rec);
  611. wpt_tmp = new Waypoint;
  612. if (rec->creation_time) {
  613. wpt_tmp->SetCreationTime(rec->creation_time);
  614. }
  615. wpt_tmp->longitude = -DecodeOrd(rec->lon);
  616. wpt_tmp->latitude = DecodeOrd(rec->lat);
  617. wpt_tmp->notes = rec->comment;
  618. wpt_tmp->description = rec->name;
  619. if (rec->url) {
  620. wpt_tmp->AddUrlLink(rec->url);
  621. } else {
  622. int u = wpt_tmp->description.indexOf("{URL=");
  623. if (u != -1) {
  624. QString us = wpt_tmp->description.mid(u);
  625. us.remove(0,5); // throw away anything up to and including "{URL="
  626. us.chop(1); // throw away final character, assumed to be "}"
  627. if (!us.isEmpty()) {
  628. wpt_tmp->AddUrlLink(us);
  629. }
  630. }
  631. }
  632. if (rec->image_name) {
  633. wpt_tmp->icon_descr = rec->image_name;
  634. } else if (FindIconByGuid(&rec->guid, &icon)) {
  635. wpt_tmp->icon_descr = icon;
  636. }
  637. fs_chain_add(&(wpt_tmp->fs), (format_specific_data*)rec);
  638. rec = NULL;
  639. waypt_add(wpt_tmp);
  640. }
  641. }
  642. static void
  643. Write_One_AN1_Waypoint(const Waypoint* wpt)
  644. {
  645. an1_waypoint_record* rec;
  646. int local;
  647. format_specific_data* fs = NULL;
  648. fs = fs_chain_find(wpt->fs, FS_AN1W);
  649. if (fs) {
  650. rec = (an1_waypoint_record*)fs;
  651. xfree(rec->name);
  652. local = 0;
  653. if (opt_zoom) {
  654. rec->visible_zoom = opt_zoom_num;
  655. }
  656. } else {
  657. rec = Alloc_AN1_Waypoint();
  658. local = 1;
  659. rec->magic = 1;
  660. rec->type = wpt_type_num;
  661. rec->unk2 = 3;
  662. rec->unk3 = 18561;
  663. rec->radius = radius;
  664. rec->fillcolor = opt_color_num;
  665. rec->fillflags = 3;
  666. if (wpt_type_num == 5) {
  667. rec->fillflags = 0x8200;
  668. }
  669. rec->height = -50;
  670. rec->width = 20;
  671. rec->fontname = xstrdup("Arial");
  672. FindIconByName(opt_symbol, &rec->guid);
  673. rec->fontsize = 10;
  674. rec->visible_zoom = opt_zoom?opt_zoom_num:10;
  675. rec->unk6_1 = 1;
  676. }
  677. rec->name = xstrdup(wpt->description);
  678. if (!nogc && wpt->gc_data->id) {
  679. #if NEW_STRINGS
  680. char* extra = (char*) xmalloc(25 + wpt->gc_data->placer.length() + wpt->shortname.length());
  681. #else
  682. char* extra = (char*) xmalloc(25 + strlen(CSTR(wpt->gc_data->placer)) + strlen(wpt->shortname));
  683. #endif
  684. sprintf(extra, "\r\nBy %s\r\n%s (%1.1f/%1.1f)",
  685. CSTR(wpt->gc_data->placer),
  686. CSTRc(wpt->shortname), wpt->gc_data->diff/10.0,
  687. wpt->gc_data->terr/10.0);
  688. rec->name = xstrappend(rec->name, extra);
  689. xfree(extra);
  690. }
  691. if (!nourl && wpt->HasUrlLink()) {
  692. UrlLink l = wpt->GetUrlLink();
  693. int len = 7 + l.url_.length();
  694. char* extra = (char*)xmalloc(len);
  695. sprintf(extra, "{URL=%s}", CSTR(l.url_));
  696. rec->name = xstrappend(rec->name, extra);
  697. xfree(extra);
  698. if(rec->url) {
  699. xfree(rec->url);
  700. }
  701. rec->url = xstrdup(l.url_);
  702. }
  703. if (!wpt->notes.isEmpty()) {
  704. if (rec->comment) {
  705. xfree(rec->comment);
  706. }
  707. rec->comment = xstrdup(wpt->notes);
  708. }
  709. rec->creation_time = rec->modification_time = wpt->GetCreationTime().toTime_t();
  710. rec->lat = EncodeOrd(wpt->latitude);
  711. rec->lon = EncodeOrd(-wpt->longitude);
  712. rec->serial = serial++;
  713. if (rec->type == 0x12) { /* image */
  714. if (wpt->icon_descr.contains(":\\")) {
  715. rec->image_name = xstrdup(wpt->icon_descr);
  716. rec->height = -244;
  717. rec->width = -1;
  718. }
  719. }
  720. if (!rec->image_name && !wpt->icon_descr.isNull()) {
  721. FindIconByName(CSTR(wpt->icon_descr), &rec->guid);
  722. }
  723. Write_AN1_Waypoint(outfile, rec);
  724. if (local) {
  725. Destroy_AN1_Waypoint(rec);
  726. }
  727. }
  728. static void Write_AN1_Waypoints(gbfile* f)
  729. {
  730. WriteShort(f, 2);
  731. WriteLong(f, waypt_count());
  732. waypt_disp_all(Write_One_AN1_Waypoint);
  733. }
  734. static void Read_AN1_Lines(gbfile* f)
  735. {
  736. unsigned long count = 0;
  737. unsigned long i = 0;
  738. unsigned long j = 0;
  739. an1_line_record* rec = NULL;
  740. an1_vertex_record* vert = NULL;
  741. route_head* rte_head;
  742. Waypoint* wpt_tmp;
  743. ReadShort(f);
  744. count = ReadLong(f);
  745. for (i = 0; i < count; i++) {
  746. rec = Alloc_AN1_Line();
  747. Read_AN1_Line(f, rec);
  748. /* create route rec */
  749. rte_head = route_head_alloc();
  750. rte_head->line_color.bbggrr = rec->linecolor;
  751. if (rec->opacity == 0x8200) {
  752. rte_head->line_color.opacity = 128;
  753. }
  754. // lineweight isn't set for dashed/dotted lines
  755. // Since we don't have a way to represent this internally yet,
  756. // use leave line_width at the default.
  757. if (rec->lineweight) {
  758. rte_head->line_width = rec->lineweight;
  759. }
  760. rte_head->rte_name = rec->name;
  761. fs_chain_add(&rte_head->fs, (format_specific_data*)rec);
  762. route_add_head(rte_head);
  763. for (j = 0; j < (unsigned) rec->pointcount; j++) {
  764. vert = Alloc_AN1_Vertex();
  765. Read_AN1_Vertex(f, vert);
  766. /* create route point */
  767. wpt_tmp = new Waypoint;
  768. wpt_tmp->latitude = DecodeOrd(vert->lat);
  769. wpt_tmp->longitude = -DecodeOrd(vert->lon);
  770. wpt_tmp->shortname = QString().sprintf("\\%5.5lx", rtserial++);
  771. fs_chain_add(&wpt_tmp->fs,
  772. (format_specific_data*)vert);
  773. route_add_wpt(rte_head, wpt_tmp);
  774. }
  775. }
  776. }
  777. static void
  778. Make_Road_Changes(an1_line_record* rec)
  779. {
  780. int i = 0;
  781. if (!rec) {
  782. return;
  783. }
  784. if (!roadchanges) {
  785. return;
  786. }
  787. while (roadchanges[i].name) {
  788. if (!case_ignore_strcmp(roadchanges[i].name, rec->name)) {
  789. rec->roadtype = roadchanges[i].type;
  790. break;
  791. }
  792. i++;
  793. }
  794. }
  795. static void
  796. Write_One_AN1_Line(const route_head* rte)
  797. {
  798. an1_line_record* rec;
  799. int local;
  800. format_specific_data* fs = NULL;
  801. fs = fs_chain_find(rte->fs, FS_AN1L);
  802. if (fs) {
  803. rec = (an1_line_record*)(void*)fs;
  804. local = 0;
  805. switch (output_type_num) {
  806. case 1:
  807. if (rec->type != 14) {
  808. rec = Alloc_AN1_Line();
  809. memcpy(rec, fs, sizeof(an1_line_record));
  810. local = 1;
  811. rec->roadtype = 0x11100541;
  812. rec->unk2 = 655360;
  813. rec->type = 14;
  814. rec->unk8 = 2;
  815. } // end if
  816. Make_Road_Changes(rec);
  817. break;
  818. case 2:
  819. if (rec->type != 15) {
  820. rec = Alloc_AN1_Line();
  821. memcpy(rec, fs, sizeof(an1_line_record));
  822. local = 1;
  823. rec->type = 15;
  824. } // end if
  825. break;
  826. case 4:
  827. if (rec->type != 16) {
  828. rec = Alloc_AN1_Line();
  829. memcpy(rec, fs, sizeof(an1_line_record));
  830. local = 1;
  831. rec->type = 16;
  832. } // end if
  833. break;
  834. }
  835. } else {
  836. rec = Alloc_AN1_Line();
  837. local = 1;
  838. rec->name = NULL;
  839. switch (output_type_num) {
  840. /* drawing road trail waypoint track */
  841. case 1: /* road */
  842. rec->roadtype = 0x11100541;
  843. rec->unk2 = 655360;
  844. rec->type = 14;
  845. rec->unk8 = 2;
  846. rec->name = xstrdup(rte->rte_name);
  847. break;
  848. case 2: /* trail */
  849. rec->roadtype = 0x11071c50;
  850. rec->unk2 = 917504;
  851. rec->type = 15;
  852. rec->unk8 = 2;
  853. break;
  854. case 4: /* track */
  855. rec->roadtype = 0x48800015;
  856. rec->unk2 = 917504;
  857. rec->type = 16;
  858. rec->unk4 = 2;
  859. rec->unk8 = 2;
  860. break;
  861. case 0: /* drawing */
  862. case 3: /* waypoint - shouldn't have lines */
  863. default:
  864. rec->roadtype = 0x48800015;
  865. rec->unk2 = 1048576;
  866. rec->type = 2;
  867. rec->unk4 = 2;
  868. rec->lineweight = 6;
  869. rec->linecolor = opt_color_num; /* red */
  870. rec->opacity = 3;
  871. rec->unk8 = 2;
  872. break;
  873. }
  874. if (!rec->name) {
  875. rec->name = xstrdup("");
  876. }
  877. }
  878. rec->serial = serial++;
  879. rec->pointcount = rte->rte_waypt_ct;
  880. Write_AN1_Line(outfile, rec);
  881. if (local) {
  882. Destroy_AN1_Line(rec);
  883. }
  884. }
  885. static void
  886. Write_One_AN1_Vertex(const Waypoint* wpt)
  887. {
  888. an1_vertex_record* rec;
  889. int local;
  890. format_specific_data* fs = NULL;
  891. fs = fs_chain_find(wpt->fs, FS_AN1V);
  892. if (fs) {
  893. rec = (an1_vertex_record*)(void*)fs;
  894. local = 0;
  895. } else {
  896. rec = Alloc_AN1_Vertex();
  897. local = 1;
  898. rec->magic = 1;
  899. }
  900. rec->lat = EncodeOrd(wpt->latitude);
  901. rec->lon = EncodeOrd(-wpt->longitude);
  902. Write_AN1_Vertex(outfile, rec);
  903. if (local) {
  904. Destroy_AN1_Vertex(rec);
  905. }
  906. }
  907. static void Write_AN1_Lines(gbfile* f)
  908. {
  909. WriteShort(f, 2);
  910. WriteLong(f, route_count()+track_count());
  911. route_disp_all(Write_One_AN1_Line, NULL, Write_One_AN1_Vertex);
  912. track_disp_all(Write_One_AN1_Line, NULL, Write_One_AN1_Vertex);
  913. }
  914. static void
  915. Init_Wpt_Type(void)
  916. {
  917. if (!opt_wpt_type || !opt_wpt_type[0]) {
  918. wpt_type_num = 1; /* marker */
  919. return;
  920. }
  921. if ((opt_wpt_type[0] & 0xf0) == 0x30) {
  922. wpt_type_num = atoi(opt_wpt_type);
  923. } else {
  924. wpt_type_num = 1; /* marker */
  925. if (!case_ignore_strcmp(opt_wpt_type, "marker")) {
  926. wpt_type_num = 1;
  927. } else if (!case_ignore_strcmp(opt_wpt_type, "symbol")) {
  928. wpt_type_num = 1; /* symbol and marker are synonyms */
  929. } else if (!case_ignore_strcmp(opt_wpt_type, "text")) {
  930. wpt_type_num = 4;
  931. } else if (!case_ignore_strcmp(opt_wpt_type, "mapnote")) {
  932. wpt_type_num = 6;
  933. } else if (!case_ignore_strcmp(opt_wpt_type, "circle")) {
  934. wpt_type_num = 5;
  935. } else if (!case_ignore_strcmp(opt_wpt_type, "image")) {
  936. wpt_type_num = 18;
  937. } else {
  938. fatal(MYNAME ": wpt_type must be "
  939. "symbol, text, mapnote, circle, or image\n");
  940. }
  941. }
  942. }
  943. static void
  944. Init_Output_Type(void)
  945. {
  946. if (!output_type || !output_type[0]) {
  947. output_type_num = last_read_type;
  948. return;
  949. }
  950. if ((output_type[0] & 0xf0) == 0x30) {
  951. output_type_num = atoi(output_type);
  952. } else {
  953. output_type_num = 0;
  954. if (!case_ignore_strcmp(output_type, "drawing")) {
  955. output_type_num = 0;
  956. } else if (!case_ignore_strcmp(output_type, "road")) {
  957. output_type_num = 1;
  958. } else if (!case_ignore_strcmp(output_type, "trail")) {
  959. output_type_num = 2;
  960. } else if (!case_ignore_strcmp(output_type, "waypoint")) {
  961. output_type_num = 3;
  962. } else if (!case_ignore_strcmp(output_type, "track")) {
  963. output_type_num = 4;
  964. } else {
  965. fatal(MYNAME ": type must be "
  966. "drawing, road, trail, waypoint, or track\n");
  967. }
  968. }
  969. last_read_type = output_type_num;
  970. }
  971. static long
  972. Parse_Change_Type(char* type)
  973. {
  974. long retval = 0x11100541;
  975. if (!case_ignore_strcmp(type, "limited")) {
  976. retval = 0x11070430;
  977. } else if (!case_ignore_strcmp(type, "toll")) {
  978. retval = 0x11070470;
  979. } else if (!case_ignore_strcmp(type, "us")) {
  980. retval = 0x11070870;
  981. } else if (!case_ignore_strcmp(type, "state")) {
  982. retval = 0x11070c10;
  983. } else if (!case_ignore_strcmp(type, "primary")) {
  984. /* primary state/provincial routes */
  985. retval = 0x11070840;
  986. } else if (!case_ignore_strcmp(type, "major")) {
  987. retval = 0x11070c30;
  988. } else if (!case_ignore_strcmp(type, "local")) {
  989. retval = 0x11071010;
  990. } else if (!case_ignore_strcmp(type, "ramp")) {
  991. retval = 0x11070cb0;
  992. } else if (!case_ignore_strcmp(type, "ferry")) {
  993. retval = 0x11070ca0;
  994. } else if (!case_ignore_strcmp(type, "editable")) {
  995. retval = 0x11100541;
  996. } else {
  997. fatal(MYNAME ": unknown road type for road changes\n");
  998. }
  999. return retval;
  1000. }
  1001. static void
  1002. Free_Road_Changes(void)
  1003. {
  1004. int i = 0;
  1005. if (roadchanges) {
  1006. while (roadchanges[i].name) {
  1007. xfree(roadchanges[i].name);
  1008. i++;
  1009. }
  1010. xfree(roadchanges);
  1011. }
  1012. roadchanges = NULL;
  1013. }
  1014. static void
  1015. Init_Road_Changes(void)
  1016. {
  1017. int count = 0;
  1018. char* strType = NULL;
  1019. char* name = NULL;
  1020. char* bar = NULL;
  1021. char* copy = NULL;
  1022. Free_Road_Changes();
  1023. if (!road_changes || !road_changes[0]) {
  1024. return;
  1025. }
  1026. bar = strchr(road_changes, '!');
  1027. while (bar) {
  1028. count++;
  1029. bar = strchr(bar+1, '!');
  1030. }
  1031. if (!(count&1)) {
  1032. fatal(MYNAME ": invalid format for road changes\n");
  1033. }
  1034. count = 1 + count / 2;
  1035. roadchanges = (roadchange*)xmalloc((count+1) * sizeof(roadchange));
  1036. roadchanges[count].type = 0;
  1037. roadchanges[count].name = NULL;
  1038. copy = xstrdup(road_changes);
  1039. bar = copy;
  1040. while (count) {
  1041. count--;
  1042. name = bar;
  1043. bar = strchr(name, '!');
  1044. *bar = '\0';
  1045. bar++;
  1046. strType = bar;
  1047. bar = strchr(strType, '!');
  1048. if (bar) {
  1049. *bar = '\0';
  1050. bar++;
  1051. }
  1052. roadchanges[count].name = xstrdup(name);
  1053. roadchanges[count].type = Parse_Change_Type(strType);
  1054. }
  1055. xfree(copy);
  1056. }
  1057. static void
  1058. rd_init(const QString& fname)
  1059. {
  1060. infile = gbfopen_le(fname, "rb", MYNAME);
  1061. }
  1062. static void
  1063. rd_deinit(void)
  1064. {
  1065. gbfclose(infile);
  1066. }
  1067. static void
  1068. my_read(void)
  1069. {
  1070. Read_AN1_Header(infile);
  1071. Read_AN1_Bitmaps(infile);
  1072. Read_AN1_Waypoints(infile);
  1073. Read_AN1_Lines(infile);
  1074. }
  1075. static void
  1076. wr_init(const QString& fname)
  1077. {
  1078. outfile = gbfopen_le(fname, "wb", MYNAME);
  1079. Init_Output_Type();
  1080. Init_Road_Changes();
  1081. opt_color_num = color_to_bbggrr(opt_color);
  1082. Init_Wpt_Type();
  1083. if (opt_zoom) {
  1084. opt_zoom_num = atoi(opt_zoom);
  1085. }
  1086. radius = .1609344; /* 1/10 mi */
  1087. if (opt_radius) {
  1088. radius = atof(opt_radius);
  1089. if (!strchr(opt_radius,'k') && !strchr(opt_radius,'K')) {
  1090. radius *= 5280*12*2.54/100000;
  1091. }
  1092. }
  1093. }
  1094. static void
  1095. wr_deinit(void)
  1096. {
  1097. Free_Road_Changes();
  1098. gbfclose(outfile);
  1099. }
  1100. static void
  1101. my_write(void)
  1102. {
  1103. Write_AN1_Header(outfile);
  1104. Write_AN1_Bitmaps(outfile);
  1105. Write_AN1_Waypoints(outfile);
  1106. Write_AN1_Lines(outfile);
  1107. }
  1108. ff_vecs_t an1_vecs = {
  1109. ff_type_file,
  1110. {
  1111. (ff_cap)(ff_cap_read | ff_cap_write) /* waypoints */,
  1112. ff_cap_write /* tracks */,
  1113. (ff_cap)(ff_cap_read | ff_cap_write) /* routes */,
  1114. },
  1115. rd_init,
  1116. wr_init,
  1117. rd_deinit,
  1118. wr_deinit,
  1119. my_read,
  1120. my_write,
  1121. NULL,
  1122. an1_args,
  1123. CET_CHARSET_ASCII, 0 /* CET-REVIEW */
  1124. };