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