2 * Routines for reading and writing Survex ".3d" image files
3 * Copyright (C) 1993-2004,2005,2006,2010,2011,2013,2014 Olly Betts
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
37 # define INT32_T int32_t
39 # include "filelist.h"
40 # include "filename.h"
43 # define TIMEFMT msg(/*%a,%Y.%m.%d %H:%M:%S %Z*/107)
47 # define INT32_T int32_t
50 # if INT_MAX >= 2147483647
56 # define TIMEFMT "%a,%Y.%m.%d %H:%M:%S %Z"
57 # define EXT_SVX_3D "3d"
58 # define EXT_SVX_POS "pos"
59 # define FNM_SEP_EXT '.'
60 # define METRES_PER_FOOT 0.3048 /* exact value */
61 # define xosmalloc(L) malloc((L))
62 # define xosrealloc(L,S) realloc((L),(S))
63 # define osfree(P) free((P))
64 # define osnew(T) (T*)malloc(sizeof(T))
66 /* in IMG_HOSTED mode, this tests if a filename refers to a directory */
67 # define fDirectory(X) 0
68 /* open file FNM with mode MODE, maybe using path PTH and/or extension EXT */
69 /* path isn't used in img.c, but EXT is */
70 # define fopenWithPthAndExt(PTH,FNM,EXT,MODE,X) \
71 ((*(X) = NULL), fopen(FNM,MODE))
73 # define PUTC(C, FH) putc(C, FH)
76 # define GETC(FH) getc(FH)
78 # define fputsnl(S, FH) (fputs((S), (FH)) == EOF ? EOF : putc('\n', (FH)))
79 # define SVX_ASSERT(X)
86 /* Return max/min of two numbers. */
87 /* May be defined already (e.g. by Borland C in stdlib.h) */
88 /* NB Bad news if X or Y has side-effects... */
90 # define max(X, Y) ((X) > (Y) ? (X) : (Y))
93 # define min(X, Y) ((X) < (Y) ? (X) : (Y))
100 INT32_T w
= GETC(fh
);
101 w
|= (INT32_T
)GETC(fh
) << 8l;
102 w
|= (INT32_T
)GETC(fh
) << 16l;
103 w
|= (INT32_T
)GETC(fh
) << 24l;
108 put32(long w
, FILE *fh
)
111 PUTC((char)(w
>> 8l), fh
);
112 PUTC((char)(w
>> 16l), fh
);
113 PUTC((char)(w
>> 24l), fh
);
120 w
|= (short)GETC(fh
) << 8l;
125 put16(short w
, FILE *fh
)
128 PUTC((char)(w
>> 8l), fh
);
132 baseleaf_from_fnm(const char *fnm
)
142 q
= strrchr(p
, '\\');
145 q
= strrchr(p
, FNM_SEP_EXT
);
146 if (q
) len
= (const char *)q
- p
; else len
= strlen(p
);
148 res
= (char *)xosmalloc(len
+ 1);
149 if (!res
) return NULL
;
156 static char * my_strdup(const char *str
);
159 mktime_with_tz(struct tm
* tm
, const char * tz
)
162 char * old_tz
= getenv("TZ");
165 old_tz
= my_strdup(old_tz
);
169 if (_putenv_s("TZ", tz
) != 0) {
173 #elif defined HAVE_SETENV
175 old_tz
= my_strdup(old_tz
);
179 if (setenv("TZ", tz
, 1) < 0) {
186 size_t len
= strlen(old_tz
) + 1;
187 p
= (char *)xosmalloc(len
+ 3);
191 memcpy(p
+ 3, tz
, len
);
194 p
= (char *)xosmalloc(strlen(tz
) + 4);
201 if (putenv(p
) != 0) {
206 #define CLEANUP() osfree(p)
212 _putenv_s("TZ", old_tz
);
213 #elif !defined HAVE_SETENV
216 setenv("TZ", old_tz
, 1);
222 #elif !defined HAVE_UNSETENV
235 static unsigned short
238 return (unsigned short)get16(fh
);
243 #if !defined HAVE_LROUND && !defined HAVE_DECL_LROUND
244 /* The autoconf tests are not in use, but C99 and C++11 both added lround(),
245 * so set HAVE_LROUND and HAVE_DECL_LROUND conservatively based on the language
246 * standard version the compiler claims to support. */
247 # if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) || \
248 (defined __cplusplus && __cplusplus >= 201103L)
249 # define HAVE_LROUND 1
250 # define HAVE_DECL_LROUND 1
255 # if defined HAVE_DECL_LROUND && !HAVE_DECL_LROUND
256 /* On older systems, the prototype may be missing. */
257 extern long lround(double);
259 # define my_lround lround
262 my_lround(double x
) {
263 return (x
>= 0.0) ? (long)(x
+ 0.5) : -(long)(0.5 - x
);
267 /* portable case insensitive string compare */
268 #if defined(strcasecmp) || defined(HAVE_STRCASECMP)
269 # define my_strcasecmp strcasecmp
271 static int my_strcasecmp(const char *s1
, const char *s2
) {
272 unsigned char c1
, c2
;
276 } while (c1
&& toupper(c1
) == toupper(c2
));
277 /* now calculate real difference */
282 unsigned int img_output_version
= IMG_VERSION_MAX
;
284 static img_errcode img_errno
= IMG_NONE
;
286 #define FILEID "Survex 3D Image File"
288 #define EXT_PLT "plt"
289 #define EXT_PLF "plf"
291 /* Attempt to string paste to ensure we are passed a literal string */
292 #define LITLEN(S) (sizeof(S"") - 1)
294 /* Fake "version numbers" for non-3d formats we can read. */
295 #define VERSION_CMAP_SHOT -4
296 #define VERSION_CMAP_STATION -3
297 #define VERSION_COMPASS_PLT -2
298 #define VERSION_SURVEX_POS -1
301 my_strdup(const char *str
)
304 size_t len
= strlen(str
) + 1;
305 p
= (char *)xosmalloc(len
);
306 if (p
) memcpy(p
, str
, len
);
310 #define getline_alloc(FH) getline_alloc_len(FH, NULL)
313 getline_alloc_len(FILE *fh
, size_t * p_len
)
318 char *buf
= (char *)xosmalloc(len
);
319 if (!buf
) return NULL
;
322 while (ch
!= '\n' && ch
!= '\r' && ch
!= EOF
) {
327 p
= (char *)xosrealloc(buf
, len
);
336 if (ch
== '\n' || ch
== '\r') {
337 int otherone
= ch
^ ('\n' ^ '\r');
339 /* if it's not the other eol character, put it back */
340 if (ch
!= otherone
) ungetc(ch
, fh
);
343 if (p_len
) *p_len
= i
;
354 check_label_space(img
*pimg
, size_t len
)
356 if (len
> pimg
->buf_len
) {
357 char *b
= (char *)xosrealloc(pimg
->label_buf
, len
);
359 pimg
->label
= (pimg
->label
- pimg
->label_buf
) + b
;
366 #define has_ext(F,L,E) ((L) > LITLEN(E) + 1 &&\
367 (F)[(L) - LITLEN(E) - 1] == FNM_SEP_EXT &&\
368 my_strcasecmp((F) + (L) - LITLEN(E), E) == 0)
371 img_open_survey(const char *fnm
, const char *survey
)
375 char buf
[LITLEN(FILEID
) + 9];
378 if (fDirectory(fnm
)) {
379 img_errno
= IMG_DIRECTORY
;
385 img_errno
= IMG_OUTOFMEMORY
;
390 pimg
->label_buf
= (char *)xosmalloc(pimg
->buf_len
);
391 if (!pimg
->label_buf
) {
393 img_errno
= IMG_OUTOFMEMORY
;
397 pimg
->fh
= fopenWithPthAndExt("", fnm
, EXT_SVX_3D
, "rb", &(pimg
->filename_opened
));
398 if (pimg
->fh
== NULL
) {
399 osfree(pimg
->label_buf
);
401 img_errno
= IMG_FILENOTFOUND
;
405 pimg
->fRead
= 1; /* reading from this file */
406 img_errno
= IMG_NONE
;
410 /* for version >= 3 we use label_buf to store the prefix for reuse */
411 /* for VERSION_COMPASS_PLT, 0 value indicates we haven't
412 * entered a survey yet */
413 /* for VERSION_CMAP_SHOT, we store the last station here
414 * to detect whether we MOVE or LINE */
416 pimg
->label_buf
[0] = '\0';
419 pimg
->survey_len
= 0;
420 pimg
->separator
= '.';
421 #if IMG_API_VERSION == 0
422 pimg
->date1
= pimg
->date2
= 0;
423 #else /* IMG_API_VERSION == 1 */
424 pimg
->days1
= pimg
->days2
= -1;
426 pimg
->is_extended_elevation
= 0;
428 pimg
->style
= pimg
->oldstyle
= img_STYLE_UNKNOWN
;
430 pimg
->l
= pimg
->r
= pimg
->u
= pimg
->d
= -1.0;
432 pimg
->title
= pimg
->datestamp
= pimg
->cs
= NULL
;
433 pimg
->datestamp_numeric
= (time_t)-1;
436 len
= strlen(survey
);
438 if (survey
[len
- 1] == '.') len
--;
441 pimg
->survey
= (char *)xosmalloc(len
+ 2);
443 img_errno
= IMG_OUTOFMEMORY
;
446 memcpy(pimg
->survey
, survey
, len
);
447 /* Set title to leaf survey name */
448 pimg
->survey
[len
] = '\0';
449 p
= strchr(pimg
->survey
, '.');
450 if (p
) p
++; else p
= pimg
->survey
;
451 pimg
->title
= my_strdup(p
);
453 img_errno
= IMG_OUTOFMEMORY
;
456 pimg
->survey
[len
] = '.';
457 pimg
->survey
[len
+ 1] = '\0';
460 pimg
->survey_len
= len
;
463 /* [VERSION_COMPASS_PLT, VERSION_CMAP_STATION, VERSION_CMAP_SHOT] pending
464 * IMG_LINE or IMG_MOVE - both have 4 added.
465 * [VERSION_SURVEX_POS] already skipped heading line, or there wasn't one
466 * [version 0] not in the middle of a 'LINE' command
467 * [version >= 3] not in the middle of turning a LINE into a MOVE
472 if (has_ext(fnm
, len
, EXT_SVX_POS
)) {
474 pimg
->version
= VERSION_SURVEX_POS
;
475 if (!pimg
->survey
) pimg
->title
= baseleaf_from_fnm(fnm
);
476 pimg
->datestamp
= my_strdup(TIMENA
);
477 if (!pimg
->datestamp
) {
478 img_errno
= IMG_OUTOFMEMORY
;
485 if (has_ext(fnm
, len
, EXT_PLT
) || has_ext(fnm
, len
, EXT_PLF
)) {
488 pimg
->version
= VERSION_COMPASS_PLT
;
489 /* Spaces aren't legal in Compass station names, but dots are, so
490 * use space as the level separator */
491 pimg
->separator
= ' ';
493 if (!pimg
->survey
) pimg
->title
= baseleaf_from_fnm(fnm
);
494 pimg
->datestamp
= my_strdup(TIMENA
);
495 if (!pimg
->datestamp
) {
496 img_errno
= IMG_OUTOFMEMORY
;
503 fseek(pimg
->fh
, -1, SEEK_CUR
);
506 pimg
->start
= ftell(pimg
->fh
);
510 fpos
= ftell(pimg
->fh
) - 1;
512 /* FIXME : if there's only one survey in the file, it'd be nice
513 * to use its description as the title here...
515 ungetc('N', pimg
->fh
);
519 line
= getline_alloc(pimg
->fh
);
521 img_errno
= IMG_OUTOFMEMORY
;
525 while (line
[len
] > 32) ++len
;
526 if (pimg
->survey_len
!= len
||
527 memcmp(line
, pimg
->survey
, len
) != 0) {
531 q
= strchr(line
+ len
, 'C');
534 pimg
->title
= my_strdup(q
+ 1);
535 } else if (!pimg
->title
) {
536 pimg
->title
= my_strdup(pimg
->label
);
540 img_errno
= IMG_OUTOFMEMORY
;
543 if (!pimg
->start
) pimg
->start
= fpos
;
544 fseek(pimg
->fh
, pimg
->start
, SEEK_SET
);
548 pimg
->start
= ftell(pimg
->fh
) - 1;
551 while (ch
!= '\n' && ch
!= '\r') {
557 /* Although these are often referred to as "CMAP .XYZ files", it seems
558 * that actually, the extension .XYZ isn't used, rather .SHT (shot
559 * variant, produced by CMAP v16 and later), .UNA (unadjusted) and
560 * .ADJ (adjusted) extensions are. Since img has long checked for
561 * .XYZ, we continue to do so in case anyone is relying on it.
563 if (has_ext(fnm
, len
, "sht") ||
564 has_ext(fnm
, len
, "adj") ||
565 has_ext(fnm
, len
, "una") ||
566 has_ext(fnm
, len
, "xyz")) {
569 /* Spaces aren't legal in CMAP station names, but dots are, so
570 * use space as the level separator. */
571 pimg
->separator
= ' ';
572 line
= getline_alloc(pimg
->fh
);
574 img_errno
= IMG_OUTOFMEMORY
;
577 /* There doesn't seem to be a spec for what happens after 1999 with cmap
578 * files, so this code allows for:
579 * * 21xx -> xx (up to 2150)
580 * * 21xx -> 1xx (up to 2199)
581 * * full year being specified instead of 2 digits
585 /* Don't just truncate at column 59, allow for a > 2 digit year. */
586 char * p
= strstr(line
+ len
, "Page");
588 while (p
> line
&& p
[-1] == ' ')
601 pimg
->datestamp
= my_strdup(line
+ 45);
603 v
= strtoul(p
, &p
, 10);
605 /* In the absence of a spec for cmap files, assume <= 50 means 21st
608 } else if (v
< 200) {
609 /* Map 100-199 to 21st century. */
612 if (v
== ULONG_MAX
|| *p
++ != '/')
614 tm
.tm_year
= v
- 1900;
615 v
= strtoul(p
, &p
, 10);
616 if (v
< 1 || v
> 12 || *p
++ != '/')
619 v
= strtoul(p
, &p
, 10);
620 if (v
< 1 || v
> 31 || *p
++ != ' ')
623 v
= strtoul(p
, &p
, 10);
624 if (v
>= 24 || *p
++ != ':')
627 v
= strtoul(p
, &p
, 10);
632 v
= strtoul(p
+ 1, &p
, 10);
640 /* We have no indication of what timezone this timestamp is in. It's
641 * probably local time for whoever processed the data, so just assume
642 * UTC, which is at least fairly central in the possibilities.
644 pimg
->datestamp_numeric
= mktime_with_tz(&tm
, "");
646 pimg
->datestamp
= my_strdup(TIMENA
);
649 if (strncmp(line
, " Cave Survey Data Processed by CMAP ",
650 LITLEN(" Cave Survey Data Processed by CMAP ")) == 0) {
657 while (len
> 2 && line
[len
- 1] == ' ') --len
;
660 pimg
->title
= my_strdup(line
+ 2);
663 if (len
<= 2) pimg
->title
= baseleaf_from_fnm(fnm
);
665 if (!pimg
->datestamp
|| !pimg
->title
) {
666 img_errno
= IMG_OUTOFMEMORY
;
669 line
= getline_alloc(pimg
->fh
);
671 img_errno
= IMG_OUTOFMEMORY
;
674 if (line
[0] != ' ' || (line
[1] != 'S' && line
[1] != 'O')) {
675 img_errno
= IMG_BADFORMAT
;
678 if (line
[1] == 'S') {
679 pimg
->version
= VERSION_CMAP_STATION
;
681 pimg
->version
= VERSION_CMAP_SHOT
;
684 line
= getline_alloc(pimg
->fh
);
686 img_errno
= IMG_OUTOFMEMORY
;
689 if (line
[0] != ' ' || line
[1] != '-') {
690 img_errno
= IMG_BADFORMAT
;
694 pimg
->start
= ftell(pimg
->fh
);
698 if (fread(buf
, LITLEN(FILEID
) + 1, 1, pimg
->fh
) != 1 ||
699 memcmp(buf
, FILEID
"\n", LITLEN(FILEID
) + 1) != 0) {
700 if (fread(buf
+ LITLEN(FILEID
) + 1, 8, 1, pimg
->fh
) == 1 &&
701 memcmp(buf
, FILEID
"\r\nv0.01\r\n", LITLEN(FILEID
) + 9) == 0) {
702 /* v0 3d file with DOS EOLs */
709 /* Looks like a CMAP .xyz file ... */
711 } else if (strchr("ZSNF", buf
[0])) {
712 /* Looks like a Compass .plt file ... */
713 /* Almost certainly it'll start "Z " */
718 /* Looks like a Survex .pos file ... */
721 img_errno
= IMG_BADFORMAT
;
725 /* check file format version */
728 if (tolower(ch
) == 'b') {
729 /* binary file iff B/b prefix */
734 img_errno
= IMG_BADFORMAT
;
739 if (fread(buf
, 4, 1, pimg
->fh
) != 1 || memcmp(buf
, ".01\n", 4) != 0) {
740 img_errno
= IMG_BADFORMAT
;
743 /* nothing special to do */
744 } else if (pimg
->version
== 0) {
745 if (ch
< '2' || ch
> '0' + IMG_VERSION_MAX
|| GETC(pimg
->fh
) != '\n') {
746 img_errno
= IMG_TOONEW
;
749 pimg
->version
= ch
- '0';
751 img_errno
= IMG_BADFORMAT
;
758 char * title
= getline_alloc_len(pimg
->fh
, &title_len
);
759 if (pimg
->version
== 8 && title
) {
760 /* We sneak in an extra field after a zero byte here, containing the
761 * specified coordinate system (if any). Older readers will just
762 * not see it (which is fine), and this trick avoids us having to
763 * bump the 3d format version.
765 size_t real_len
= strlen(title
);
766 if (real_len
!= title_len
) {
767 pimg
->cs
= my_strdup(title
+ real_len
+ 1);
776 pimg
->datestamp
= getline_alloc(pimg
->fh
);
777 if (!pimg
->title
|| !pimg
->datestamp
) {
778 img_errno
= IMG_OUTOFMEMORY
;
782 osfree(pimg
->datestamp
);
783 osfree(pimg
->filename_opened
);
789 if (pimg
->version
>= 8) {
790 int flags
= GETC(pimg
->fh
);
791 if (flags
& img_FFLAG_EXTENDED
) pimg
->is_extended_elevation
= 1;
793 len
= strlen(pimg
->title
);
794 if (len
> 11 && strcmp(pimg
->title
+ len
- 11, " (extended)") == 0) {
795 pimg
->title
[len
- 11] = '\0';
796 pimg
->is_extended_elevation
= 1;
800 if (pimg
->datestamp
[0] == '@') {
804 v
= strtoul(pimg
->datestamp
+ 1, &p
, 10);
805 if (errno
== 0 && *p
== '\0')
806 pimg
->datestamp_numeric
= v
;
807 /* FIXME: We're assuming here that the C time_t epoch is 1970, which is
808 * true for Unix-like systems, Mac OS X and Windows, but isn't guaranteed
812 /* %a,%Y.%m.%d %H:%M:%S %Z */
815 char * p
= pimg
->datestamp
;
816 while (isalpha((unsigned char)*p
)) ++p
;
818 while (isspace((unsigned char)*p
)) ++p
;
819 v
= strtoul(p
, &p
, 10);
820 if (v
== ULONG_MAX
|| *p
++ != '.')
822 tm
.tm_year
= v
- 1900;
823 v
= strtoul(p
, &p
, 10);
824 if (v
< 1 || v
> 12 || *p
++ != '.')
827 v
= strtoul(p
, &p
, 10);
828 if (v
< 1 || v
> 31 || *p
++ != ' ')
831 v
= strtoul(p
, &p
, 10);
832 if (v
>= 24 || *p
++ != ':')
835 v
= strtoul(p
, &p
, 10);
836 if (v
>= 60 || *p
++ != ':')
839 v
= strtoul(p
, &p
, 10);
844 while (isspace((unsigned char)*p
)) ++p
;
845 /* p now points to the timezone string.
847 * However, it's likely to be a string like "BST", and such strings can
848 * be ambiguous (BST could be UTC+1 or UTC+6), so it is impossible to
849 * reliably convert in all cases. Just pass what we have to tzset() - if
850 * it doesn't handle it, UTC will be used.
852 pimg
->datestamp_numeric
= mktime_with_tz(&tm
, p
);
856 pimg
->start
= ftell(pimg
->fh
);
862 img_rewind(img
*pimg
)
865 img_errno
= IMG_WRITEERROR
;
868 if (fseek(pimg
->fh
, pimg
->start
, SEEK_SET
) != 0) {
869 img_errno
= IMG_READERROR
;
873 /* [VERSION_SURVEX_POS] already skipped heading line, or there wasn't one
874 * [version 0] not in the middle of a 'LINE' command
875 * [version >= 3] not in the middle of turning a LINE into a MOVE */
878 img_errno
= IMG_NONE
;
880 /* for version >= 3 we use label_buf to store the prefix for reuse */
881 /* for VERSION_COMPASS_PLT, 0 value indicates we haven't entered a survey
883 /* for VERSION_CMAP_SHOT, we store the last station here to detect whether
886 pimg
->style
= img_STYLE_UNKNOWN
;
891 img_open_write_cs(const char *fnm
, const char *title
, const char * cs
, int flags
)
896 if (fDirectory(fnm
)) {
897 img_errno
= IMG_DIRECTORY
;
903 img_errno
= IMG_OUTOFMEMORY
;
908 pimg
->label_buf
= (char *)xosmalloc(pimg
->buf_len
);
909 if (!pimg
->label_buf
) {
911 img_errno
= IMG_OUTOFMEMORY
;
915 pimg
->fh
= fopen(fnm
, "wb");
917 osfree(pimg
->label_buf
);
919 img_errno
= IMG_CANTOPENOUT
;
923 pimg
->filename_opened
= NULL
;
925 /* Output image file header */
926 fputs("Survex 3D Image File\n", pimg
->fh
); /* file identifier string */
927 if (img_output_version
< 2) {
929 fputs("Bv0.01\n", pimg
->fh
); /* binary file format version number */
931 pimg
->version
= (img_output_version
> IMG_VERSION_MAX
) ? IMG_VERSION_MAX
: img_output_version
;
932 fprintf(pimg
->fh
, "v%d\n", pimg
->version
); /* file format version no. */
935 fputs(title
, pimg
->fh
);
936 if (pimg
->version
< 8 && (flags
& img_FFLAG_EXTENDED
)) {
937 /* Older format versions append " (extended)" to the title to mark
938 * extended elevations. */
939 size_t len
= strlen(title
);
940 if (len
< 11 || strcmp(title
+ len
- 11, " (extended)") != 0)
941 fputs(" (extended)", pimg
->fh
);
943 if (pimg
->version
== 8 && cs
&& *cs
) {
944 /* We sneak in an extra field after a zero byte here, containing the
945 * specified coordinate system (if any). Older readers will just not
946 * see it (which is fine), and this trick avoids us having to bump the
949 PUTC('\0', pimg
->fh
);
952 PUTC('\n', pimg
->fh
);
955 if (tm
== (time_t)-1) {
956 fputsnl(TIMENA
, pimg
->fh
);
957 } else if (pimg
->version
<= 7) {
959 /* output current date and time in format specified */
960 strftime(date
, 256, TIMEFMT
, localtime(&tm
));
961 fputsnl(date
, pimg
->fh
);
963 fprintf(pimg
->fh
, "@%ld\n", (long)tm
);
966 if (pimg
->version
>= 8) {
967 /* Clear bit one in case anyone has been passing true for fBinary. */
969 PUTC(flags
, pimg
->fh
);
973 if (img_output_version
>= 5) {
974 static const unsigned char codelengths
[32] = {
975 4, 8, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
976 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
978 fwrite(codelengths
, 32, 1, pimg
->fh
);
981 pimg
->fRead
= 0; /* writing to this file */
982 img_errno
= IMG_NONE
;
984 /* for version >= 3 we use label_buf to store the prefix for reuse */
985 pimg
->label_buf
[0] = '\0';
988 #if IMG_API_VERSION == 0
989 pimg
->date1
= pimg
->date2
= 0;
990 pimg
->olddate1
= pimg
->olddate2
= 0;
991 #else /* IMG_API_VERSION == 1 */
992 pimg
->days1
= pimg
->days2
= -1;
993 pimg
->olddays1
= pimg
->olddays2
= -1;
995 pimg
->style
= pimg
->oldstyle
= img_STYLE_UNKNOWN
;
997 pimg
->l
= pimg
->r
= pimg
->u
= pimg
->d
= -1.0;
1001 pimg
->E
= pimg
->H
= pimg
->V
= 0.0;
1003 /* Don't check for write errors now - let img_close() report them... */
1008 read_xyz_station_coords(img_point
*pt
, const char *line
)
1011 memcpy(num
, line
+ 6, 9);
1013 pt
->x
= atof(num
) / METRES_PER_FOOT
;
1014 memcpy(num
, line
+ 15, 9);
1015 pt
->y
= atof(num
) / METRES_PER_FOOT
;
1016 memcpy(num
, line
+ 24, 8);
1018 pt
->z
= atof(num
) / METRES_PER_FOOT
;
1022 read_xyz_shot_coords(img_point
*pt
, const char *line
)
1025 memcpy(num
, line
+ 40, 10);
1027 pt
->x
= atof(num
) / METRES_PER_FOOT
;
1028 memcpy(num
, line
+ 50, 10);
1029 pt
->y
= atof(num
) / METRES_PER_FOOT
;
1030 memcpy(num
, line
+ 60, 9);
1032 pt
->z
= atof(num
) / METRES_PER_FOOT
;
1036 subtract_xyz_shot_deltas(img_point
*pt
, const char *line
)
1039 memcpy(num
, line
+ 15, 9);
1041 pt
->x
-= atof(num
) / METRES_PER_FOOT
;
1042 memcpy(num
, line
+ 24, 8);
1044 pt
->y
-= atof(num
) / METRES_PER_FOOT
;
1045 memcpy(num
, line
+ 32, 8);
1046 pt
->z
-= atof(num
) / METRES_PER_FOOT
;
1050 read_coord(FILE *fh
, img_point
*pt
)
1054 pt
->x
= get32(fh
) / 100.0;
1055 pt
->y
= get32(fh
) / 100.0;
1056 pt
->z
= get32(fh
) / 100.0;
1057 if (ferror(fh
) || feof(fh
)) {
1058 img_errno
= feof(fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1065 skip_coord(FILE *fh
)
1067 return (fseek(fh
, 12, SEEK_CUR
) == 0);
1071 read_v3label(img
*pimg
)
1074 long len
= GETC(pimg
->fh
);
1076 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1080 len
+= get16(pimg
->fh
);
1081 if (feof(pimg
->fh
)) {
1082 img_errno
= IMG_BADFORMAT
;
1085 if (ferror(pimg
->fh
)) {
1086 img_errno
= IMG_READERROR
;
1089 } else if (len
== 0xff) {
1090 len
= get32(pimg
->fh
);
1091 if (ferror(pimg
->fh
)) {
1092 img_errno
= IMG_READERROR
;
1095 if (feof(pimg
->fh
) || len
< 0xfe + 0xffff) {
1096 img_errno
= IMG_BADFORMAT
;
1101 if (!check_label_space(pimg
, pimg
->label_len
+ len
+ 1)) {
1102 img_errno
= IMG_OUTOFMEMORY
;
1105 q
= pimg
->label_buf
+ pimg
->label_len
;
1106 pimg
->label_len
+= len
;
1107 if (len
&& fread(q
, len
, 1, pimg
->fh
) != 1) {
1108 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1116 read_v8label(img
*pimg
, int common_flag
, size_t common_val
)
1121 if (common_val
== 0) return 0;
1122 add
= del
= common_val
;
1124 int ch
= GETC(pimg
->fh
);
1126 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1133 ch
= GETC(pimg
->fh
);
1135 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1141 del
= get32(pimg
->fh
);
1142 if (ferror(pimg
->fh
)) {
1143 img_errno
= IMG_READERROR
;
1147 ch
= GETC(pimg
->fh
);
1149 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1155 add
= get32(pimg
->fh
);
1156 if (ferror(pimg
->fh
)) {
1157 img_errno
= IMG_READERROR
;
1163 if (add
> del
&& !check_label_space(pimg
, pimg
->label_len
+ add
- del
+ 1)) {
1164 img_errno
= IMG_OUTOFMEMORY
;
1168 if (del
> pimg
->label_len
) {
1169 img_errno
= IMG_BADFORMAT
;
1172 pimg
->label_len
-= del
;
1173 q
= pimg
->label_buf
+ pimg
->label_len
;
1174 pimg
->label_len
+= add
;
1175 if (add
&& fread(q
, add
, 1, pimg
->fh
) != 1) {
1176 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1183 static int img_read_item_new(img
*pimg
, img_point
*p
);
1184 static int img_read_item_v3to7(img
*pimg
, img_point
*p
);
1185 static int img_read_item_ancient(img
*pimg
, img_point
*p
);
1186 static int img_read_item_ascii_wrapper(img
*pimg
, img_point
*p
);
1187 static int img_read_item_ascii(img
*pimg
, img_point
*p
);
1190 img_read_item(img
*pimg
, img_point
*p
)
1194 if (pimg
->version
>= 8) {
1195 return img_read_item_new(pimg
, p
);
1196 } else if (pimg
->version
>= 3) {
1197 return img_read_item_v3to7(pimg
, p
);
1198 } else if (pimg
->version
>= 1) {
1199 return img_read_item_ancient(pimg
, p
);
1201 return img_read_item_ascii_wrapper(pimg
, p
);
1206 img_read_item_new(img
*pimg
, img_point
*p
)
1210 pimg
->l
= pimg
->r
= pimg
->u
= pimg
->d
= -1.0;
1211 if (pimg
->pending
>= 0x40) {
1212 if (pimg
->pending
== 256) {
1214 return img_XSECT_END
;
1217 pimg
->flags
= (int)(pimg
->pending
) & 0x3f;
1221 again3
: /* label to goto if we get a prefix, date, or lrud */
1222 pimg
->label
= pimg
->label_buf
;
1223 opt
= GETC(pimg
->fh
);
1225 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1228 if (opt
>> 6 == 0) {
1230 if (opt
== 0 && pimg
->style
== 0)
1231 return img_STOP
; /* end of data marker */
1238 case 0x10: { /* No date info */
1239 #if IMG_API_VERSION == 0
1240 pimg
->date1
= pimg
->date2
= 0;
1241 #else /* IMG_API_VERSION == 1 */
1242 pimg
->days1
= pimg
->days2
= -1;
1246 case 0x11: { /* Single date */
1247 int days1
= (int)getu16(pimg
->fh
);
1248 #if IMG_API_VERSION == 0
1249 pimg
->date2
= pimg
->date1
= (days1
- 25567) * 86400;
1250 #else /* IMG_API_VERSION == 1 */
1251 pimg
->days2
= pimg
->days1
= days1
;
1255 case 0x12: { /* Date range (short) */
1256 int days1
= (int)getu16(pimg
->fh
);
1257 int days2
= days1
+ GETC(pimg
->fh
) + 1;
1258 #if IMG_API_VERSION == 0
1259 pimg
->date1
= (days1
- 25567) * 86400;
1260 pimg
->date2
= (days2
- 25567) * 86400;
1261 #else /* IMG_API_VERSION == 1 */
1262 pimg
->days1
= days1
;
1263 pimg
->days2
= days2
;
1267 case 0x13: { /* Date range (long) */
1268 int days1
= (int)getu16(pimg
->fh
);
1269 int days2
= (int)getu16(pimg
->fh
);
1270 #if IMG_API_VERSION == 0
1271 pimg
->date1
= (days1
- 25567) * 86400;
1272 pimg
->date2
= (days2
- 25567) * 86400;
1273 #else /* IMG_API_VERSION == 1 */
1274 pimg
->days1
= days1
;
1275 pimg
->days2
= days2
;
1279 case 0x1f: /* Error info */
1280 pimg
->n_legs
= get32(pimg
->fh
);
1281 pimg
->length
= get32(pimg
->fh
) / 100.0;
1282 pimg
->E
= get32(pimg
->fh
) / 100.0;
1283 pimg
->H
= get32(pimg
->fh
) / 100.0;
1284 pimg
->V
= get32(pimg
->fh
) / 100.0;
1285 return img_ERROR_INFO
;
1286 case 0x30: case 0x31: /* LRUD */
1287 case 0x32: case 0x33: /* Big LRUD! */
1288 if (read_v8label(pimg
, 0, 0) == img_BAD
) return img_BAD
;
1289 pimg
->flags
= (int)opt
& 0x01;
1291 pimg
->l
= get16(pimg
->fh
) / 100.0;
1292 pimg
->r
= get16(pimg
->fh
) / 100.0;
1293 pimg
->u
= get16(pimg
->fh
) / 100.0;
1294 pimg
->d
= get16(pimg
->fh
) / 100.0;
1296 pimg
->l
= get32(pimg
->fh
) / 100.0;
1297 pimg
->r
= get32(pimg
->fh
) / 100.0;
1298 pimg
->u
= get32(pimg
->fh
) / 100.0;
1299 pimg
->d
= get32(pimg
->fh
) / 100.0;
1301 if (pimg
->survey_len
) {
1302 size_t l
= pimg
->survey_len
;
1303 const char *s
= pimg
->label_buf
;
1304 if (strncmp(pimg
->survey
, s
, l
+ 1) != 0) {
1305 return img_XSECT_END
;
1308 /* skip the dot if there */
1309 if (*pimg
->label
) pimg
->label
++;
1311 /* If this is the last cross-section in this passage, set
1312 * pending so we return img_XSECT_END next time. */
1313 if (pimg
->flags
& 0x01) {
1314 pimg
->pending
= 256;
1315 pimg
->flags
&= ~0x01;
1318 default: /* 0x25 - 0x2f and 0x34 - 0x3f are currently unallocated. */
1319 img_errno
= IMG_BADFORMAT
;
1325 /* 1-14 and 16-31 reserved */
1326 img_errno
= IMG_BADFORMAT
;
1330 } else if (opt
>= 0x80) {
1331 if (read_v8label(pimg
, 0, 0) == img_BAD
) return img_BAD
;
1335 if (pimg
->survey_len
) {
1336 size_t l
= pimg
->survey_len
;
1337 const char *s
= pimg
->label_buf
;
1338 if (strncmp(pimg
->survey
, s
, l
+ 1) != 0) {
1339 if (!skip_coord(pimg
->fh
)) return img_BAD
;
1344 /* skip the dot if there */
1345 if (*pimg
->label
) pimg
->label
++;
1348 pimg
->flags
= (int)opt
& 0x7f;
1349 } else if ((opt
>> 6) == 1) {
1350 if (read_v8label(pimg
, opt
& 0x20, 0) == img_BAD
) return img_BAD
;
1354 if (pimg
->survey_len
) {
1355 size_t l
= pimg
->survey_len
;
1356 const char *s
= pimg
->label_buf
;
1357 if (strncmp(pimg
->survey
, s
, l
) != 0 ||
1358 !(s
[l
] == '.' || s
[l
] == '\0')) {
1359 if (!read_coord(pimg
->fh
, &(pimg
->mv
))) return img_BAD
;
1364 /* skip the dot if there */
1365 if (*pimg
->label
) pimg
->label
++;
1368 if (pimg
->pending
) {
1370 if (!read_coord(pimg
->fh
, &(pimg
->mv
))) return img_BAD
;
1371 pimg
->pending
= opt
;
1374 pimg
->flags
= (int)opt
& 0x1f;
1376 img_errno
= IMG_BADFORMAT
;
1379 if (!read_coord(pimg
->fh
, p
)) return img_BAD
;
1385 img_read_item_v3to7(img
*pimg
, img_point
*p
)
1389 pimg
->l
= pimg
->r
= pimg
->u
= pimg
->d
= -1.0;
1390 if (pimg
->pending
== 256) {
1392 return img_XSECT_END
;
1394 if (pimg
->pending
>= 0x80) {
1396 pimg
->flags
= (int)(pimg
->pending
) & 0x3f;
1400 again3
: /* label to goto if we get a prefix, date, or lrud */
1401 pimg
->label
= pimg
->label_buf
;
1402 opt
= GETC(pimg
->fh
);
1404 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1410 if (!pimg
->label_len
) return img_STOP
; /* end of data marker */
1411 pimg
->label_len
= 0;
1415 /* 1-14 mean trim that many levels from current prefix */
1417 if (pimg
->label_len
<= 17) {
1418 /* zero prefix using "0" */
1419 img_errno
= IMG_BADFORMAT
;
1422 /* extra - 1 because label_len points to one past the end */
1423 c
= pimg
->label_len
- 17 - 1;
1424 while (pimg
->label_buf
[c
] != '.' || --opt
> 0) {
1426 /* zero prefix using "0" */
1427 img_errno
= IMG_BADFORMAT
;
1432 pimg
->label_len
= c
;
1441 case 0x20: /* Single date */
1442 if (pimg
->version
< 7) {
1443 int date1
= get32(pimg
->fh
);
1444 #if IMG_API_VERSION == 0
1445 pimg
->date2
= pimg
->date1
= date1
;
1446 #else /* IMG_API_VERSION == 1 */
1448 pimg
->days2
= pimg
->days1
= (date1
/ 86400) + 25567;
1450 pimg
->days2
= pimg
->days1
= -1;
1454 int days1
= (int)getu16(pimg
->fh
);
1455 #if IMG_API_VERSION == 0
1456 pimg
->date2
= pimg
->date1
= (days1
- 25567) * 86400;
1457 #else /* IMG_API_VERSION == 1 */
1458 pimg
->days2
= pimg
->days1
= days1
;
1462 case 0x21: /* Date range (short for v7+) */
1463 if (pimg
->version
< 7) {
1464 INT32_T date1
= get32(pimg
->fh
);
1465 INT32_T date2
= get32(pimg
->fh
);
1466 #if IMG_API_VERSION == 0
1467 pimg
->date1
= date1
;
1468 pimg
->date2
= date2
;
1469 #else /* IMG_API_VERSION == 1 */
1470 pimg
->days1
= (date1
/ 86400) + 25567;
1471 pimg
->days2
= (date2
/ 86400) + 25567;
1474 int days1
= (int)getu16(pimg
->fh
);
1475 int days2
= days1
+ GETC(pimg
->fh
) + 1;
1476 #if IMG_API_VERSION == 0
1477 pimg
->date1
= (days1
- 25567) * 86400;
1478 pimg
->date2
= (days2
- 25567) * 86400;
1479 #else /* IMG_API_VERSION == 1 */
1480 pimg
->days1
= days1
;
1481 pimg
->days2
= days2
;
1485 case 0x22: /* Error info */
1486 pimg
->n_legs
= get32(pimg
->fh
);
1487 pimg
->length
= get32(pimg
->fh
) / 100.0;
1488 pimg
->E
= get32(pimg
->fh
) / 100.0;
1489 pimg
->H
= get32(pimg
->fh
) / 100.0;
1490 pimg
->V
= get32(pimg
->fh
) / 100.0;
1491 if (feof(pimg
->fh
)) {
1492 img_errno
= IMG_BADFORMAT
;
1495 if (ferror(pimg
->fh
)) {
1496 img_errno
= IMG_READERROR
;
1499 return img_ERROR_INFO
;
1500 case 0x23: { /* v7+: Date range (long) */
1501 if (pimg
->version
< 7) {
1502 img_errno
= IMG_BADFORMAT
;
1505 int days1
= (int)getu16(pimg
->fh
);
1506 int days2
= (int)getu16(pimg
->fh
);
1507 if (feof(pimg
->fh
)) {
1508 img_errno
= IMG_BADFORMAT
;
1511 if (ferror(pimg
->fh
)) {
1512 img_errno
= IMG_READERROR
;
1515 #if IMG_API_VERSION == 0
1516 pimg
->date1
= (days1
- 25567) * 86400;
1517 pimg
->date2
= (days2
- 25567) * 86400;
1518 #else /* IMG_API_VERSION == 1 */
1519 pimg
->days1
= days1
;
1520 pimg
->days2
= days2
;
1524 case 0x24: { /* v7+: No date info */
1525 #if IMG_API_VERSION == 0
1526 pimg
->date1
= pimg
->date2
= 0;
1527 #else /* IMG_API_VERSION == 1 */
1528 pimg
->days1
= pimg
->days2
= -1;
1532 case 0x30: case 0x31: /* LRUD */
1533 case 0x32: case 0x33: /* Big LRUD! */
1534 if (read_v3label(pimg
) == img_BAD
) return img_BAD
;
1535 pimg
->flags
= (int)opt
& 0x01;
1537 pimg
->l
= get16(pimg
->fh
) / 100.0;
1538 pimg
->r
= get16(pimg
->fh
) / 100.0;
1539 pimg
->u
= get16(pimg
->fh
) / 100.0;
1540 pimg
->d
= get16(pimg
->fh
) / 100.0;
1542 pimg
->l
= get32(pimg
->fh
) / 100.0;
1543 pimg
->r
= get32(pimg
->fh
) / 100.0;
1544 pimg
->u
= get32(pimg
->fh
) / 100.0;
1545 pimg
->d
= get32(pimg
->fh
) / 100.0;
1547 if (feof(pimg
->fh
)) {
1548 img_errno
= IMG_BADFORMAT
;
1551 if (ferror(pimg
->fh
)) {
1552 img_errno
= IMG_READERROR
;
1555 if (pimg
->survey_len
) {
1556 size_t l
= pimg
->survey_len
;
1557 const char *s
= pimg
->label_buf
;
1558 if (strncmp(pimg
->survey
, s
, l
+ 1) != 0) {
1559 return img_XSECT_END
;
1562 /* skip the dot if there */
1563 if (*pimg
->label
) pimg
->label
++;
1565 /* If this is the last cross-section in this passage, set
1566 * pending so we return img_XSECT_END next time. */
1567 if (pimg
->flags
& 0x01) {
1568 pimg
->pending
= 256;
1569 pimg
->flags
&= ~0x01;
1572 default: /* 0x25 - 0x2f and 0x34 - 0x3f are currently unallocated. */
1573 img_errno
= IMG_BADFORMAT
;
1576 if (feof(pimg
->fh
)) {
1577 img_errno
= IMG_BADFORMAT
;
1580 if (ferror(pimg
->fh
)) {
1581 img_errno
= IMG_READERROR
;
1586 /* 16-31 mean remove (n - 15) characters from the prefix */
1587 /* zero prefix using 0 */
1588 if (pimg
->label_len
<= (size_t)(opt
- 15)) {
1589 img_errno
= IMG_BADFORMAT
;
1592 pimg
->label_len
-= (opt
- 15);
1595 if (read_v3label(pimg
) == img_BAD
) return img_BAD
;
1599 if (pimg
->survey_len
) {
1600 size_t l
= pimg
->survey_len
;
1601 const char *s
= pimg
->label_buf
;
1602 if (strncmp(pimg
->survey
, s
, l
+ 1) != 0) {
1603 if (!skip_coord(pimg
->fh
)) return img_BAD
;
1608 /* skip the dot if there */
1609 if (*pimg
->label
) pimg
->label
++;
1612 pimg
->flags
= (int)opt
& 0x3f;
1615 if (read_v3label(pimg
) == img_BAD
) return img_BAD
;
1619 if (pimg
->survey_len
) {
1620 size_t l
= pimg
->survey_len
;
1621 const char *s
= pimg
->label_buf
;
1622 if (strncmp(pimg
->survey
, s
, l
) != 0 ||
1623 !(s
[l
] == '.' || s
[l
] == '\0')) {
1624 if (!read_coord(pimg
->fh
, &(pimg
->mv
))) return img_BAD
;
1629 /* skip the dot if there */
1630 if (*pimg
->label
) pimg
->label
++;
1633 if (pimg
->pending
) {
1635 if (!read_coord(pimg
->fh
, &(pimg
->mv
))) return img_BAD
;
1636 pimg
->pending
= opt
;
1639 pimg
->flags
= (int)opt
& 0x3f;
1642 img_errno
= IMG_BADFORMAT
;
1645 if (!read_coord(pimg
->fh
, p
)) return img_BAD
;
1651 img_read_item_ancient(img
*pimg
, img_point
*p
)
1654 static long opt_lookahead
= 0;
1655 static img_point pt
= { 0.0, 0.0, 0.0 };
1658 again
: /* label to goto if we get a cross */
1659 pimg
->label
= pimg
->label_buf
;
1660 pimg
->label
[0] = '\0';
1662 if (pimg
->version
== 1) {
1663 if (opt_lookahead
) {
1664 opt
= opt_lookahead
;
1667 opt
= get32(pimg
->fh
);
1670 opt
= GETC(pimg
->fh
);
1673 if (feof(pimg
->fh
)) {
1674 img_errno
= IMG_BADFORMAT
;
1677 if (ferror(pimg
->fh
)) {
1678 img_errno
= IMG_READERROR
;
1684 return img_STOP
; /* end of data marker */
1686 /* skip coordinates */
1687 if (!skip_coord(pimg
->fh
)) {
1688 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1695 if (!fgets(pimg
->label_buf
, pimg
->buf_len
, pimg
->fh
)) {
1696 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1699 if (pimg
->label
[0] == '\\') pimg
->label
++;
1700 len
= strlen(pimg
->label
);
1701 if (len
== 0 || pimg
->label
[len
- 1] != '\n') {
1702 img_errno
= IMG_BADFORMAT
;
1705 /* Ignore empty labels in some .3d files (caused by a bug) */
1706 if (len
== 1) goto again
;
1707 pimg
->label
[len
- 1] = '\0';
1708 pimg
->flags
= img_SFLAG_UNDERGROUND
; /* no flags given... */
1709 if (opt
== 2) goto done
;
1717 pimg
->flags
= GETC(pimg
->fh
);
1719 pimg
->flags
= img_SFLAG_UNDERGROUND
; /* no flags given... */
1721 len
= get32(pimg
->fh
);
1723 if (feof(pimg
->fh
)) {
1724 img_errno
= IMG_BADFORMAT
;
1727 if (ferror(pimg
->fh
)) {
1728 img_errno
= IMG_READERROR
;
1732 /* Ignore empty labels in some .3d files (caused by a bug) */
1733 if (len
== 0) goto again
;
1734 if (!check_label_space(pimg
, len
+ 1)) {
1735 img_errno
= IMG_OUTOFMEMORY
;
1738 if (fread(pimg
->label_buf
, len
, 1, pimg
->fh
) != 1) {
1739 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1742 pimg
->label_buf
[len
] = '\0';
1752 switch ((int)opt
& 0xc0) {
1754 pimg
->flags
= (int)opt
& 0x3f;
1759 pimg
->flags
= (int)opt
& 0x3f;
1761 if (!fgets(pimg
->label_buf
, pimg
->buf_len
, pimg
->fh
)) {
1762 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1765 q
= pimg
->label_buf
+ strlen(pimg
->label_buf
) - 1;
1766 /* Ignore empty-labels in some .3d files (caused by a bug) */
1767 if (q
== pimg
->label_buf
) goto again
;
1769 img_errno
= IMG_BADFORMAT
;
1776 img_errno
= IMG_BADFORMAT
;
1782 if (!read_coord(pimg
->fh
, &pt
)) return img_BAD
;
1784 if (result
== img_LABEL
&& pimg
->survey_len
) {
1785 if (strncmp(pimg
->label
, pimg
->survey
, pimg
->survey_len
+ 1) != 0)
1787 pimg
->label
+= pimg
->survey_len
+ 1;
1793 if (result
== img_MOVE
&& pimg
->version
== 1) {
1794 /* peek at next code and see if it's an old-style label */
1795 opt_lookahead
= get32(pimg
->fh
);
1797 if (feof(pimg
->fh
)) {
1798 img_errno
= IMG_BADFORMAT
;
1801 if (ferror(pimg
->fh
)) {
1802 img_errno
= IMG_READERROR
;
1806 if (opt_lookahead
== 2) return img_read_item_ancient(pimg
, p
);
1813 img_read_item_ascii_wrapper(img
*pimg
, img_point
*p
)
1815 /* We need to set the default locale for fscanf() to work on
1816 * numbers with "." as decimal point. */
1818 char * current_locale
= my_strdup(setlocale(LC_NUMERIC
, NULL
));
1819 setlocale(LC_NUMERIC
, "C");
1820 result
= img_read_item_ascii(pimg
, p
);
1821 setlocale(LC_NUMERIC
, current_locale
);
1822 free(current_locale
);
1826 /* Handle all ASCII formats. */
1828 img_read_item_ascii(img
*pimg
, img_point
*p
)
1831 pimg
->label
= pimg
->label_buf
;
1832 if (pimg
->version
== 0) {
1834 pimg
->label
[0] = '\0';
1835 if (feof(pimg
->fh
)) return img_STOP
;
1836 if (pimg
->pending
) {
1841 /* Stop if nothing found */
1842 if (fscanf(pimg
->fh
, "%6s", cmd
) < 1) return img_STOP
;
1843 if (strcmp(cmd
, "move") == 0)
1845 else if (strcmp(cmd
, "draw") == 0)
1847 else if (strcmp(cmd
, "line") == 0) {
1848 /* set flag to indicate to process second triplet as LINE */
1851 } else if (strcmp(cmd
, "cross") == 0) {
1852 if (fscanf(pimg
->fh
, "%lf%lf%lf", &p
->x
, &p
->y
, &p
->z
) < 3) {
1853 img_errno
= feof(pimg
->fh
) ? IMG_BADFORMAT
: IMG_READERROR
;
1857 } else if (strcmp(cmd
, "name") == 0) {
1859 int ch
= GETC(pimg
->fh
);
1860 if (ch
== ' ') ch
= GETC(pimg
->fh
);
1862 if (ch
== '\n' || ch
== EOF
) {
1863 img_errno
= ferror(pimg
->fh
) ? IMG_READERROR
: IMG_BADFORMAT
;
1866 if (off
== pimg
->buf_len
) {
1867 if (!check_label_space(pimg
, pimg
->buf_len
* 2)) {
1868 img_errno
= IMG_OUTOFMEMORY
;
1872 pimg
->label_buf
[off
++] = ch
;
1873 ch
= GETC(pimg
->fh
);
1875 pimg
->label_buf
[off
] = '\0';
1877 pimg
->label
= pimg
->label_buf
;
1878 if (pimg
->label
[0] == '\\') pimg
->label
++;
1880 pimg
->flags
= img_SFLAG_UNDERGROUND
; /* default flags */
1884 img_errno
= IMG_BADFORMAT
;
1885 return img_BAD
; /* unknown keyword */
1889 if (fscanf(pimg
->fh
, "%lf%lf%lf", &p
->x
, &p
->y
, &p
->z
) < 3) {
1890 img_errno
= ferror(pimg
->fh
) ? IMG_READERROR
: IMG_BADFORMAT
;
1894 if (result
== img_LABEL
&& pimg
->survey_len
) {
1895 if (strncmp(pimg
->label
, pimg
->survey
, pimg
->survey_len
+ 1) != 0)
1897 pimg
->label
+= pimg
->survey_len
+ 1;
1901 } else if (pimg
->version
== VERSION_SURVEX_POS
) {
1902 /* Survex .pos file */
1905 pimg
->flags
= img_SFLAG_UNDERGROUND
; /* default flags */
1907 while (fscanf(pimg
->fh
, "(%lf,%lf,%lf )", &p
->x
, &p
->y
, &p
->z
) != 3) {
1908 if (ferror(pimg
->fh
)) {
1909 img_errno
= IMG_READERROR
;
1912 if (feof(pimg
->fh
)) return img_STOP
;
1913 if (pimg
->pending
) {
1914 img_errno
= IMG_BADFORMAT
;
1918 /* ignore rest of line */
1920 ch
= GETC(pimg
->fh
);
1921 } while (ch
!= '\n' && ch
!= '\r' && ch
!= EOF
);
1924 pimg
->label_buf
[0] = '\0';
1926 ch
= GETC(pimg
->fh
);
1927 } while (ch
== ' ' || ch
== '\t');
1928 if (ch
== '\n' || ch
== EOF
) {
1929 /* If there's no label, set img_SFLAG_ANON. */
1930 pimg
->flags
|= img_SFLAG_ANON
;
1933 pimg
->label_buf
[0] = ch
;
1935 while (!feof(pimg
->fh
)) {
1936 if (!fgets(pimg
->label_buf
+ off
, pimg
->buf_len
- off
, pimg
->fh
)) {
1937 img_errno
= IMG_READERROR
;
1941 off
+= strlen(pimg
->label_buf
+ off
);
1942 if (off
&& pimg
->label_buf
[off
- 1] == '\n') {
1943 pimg
->label_buf
[off
- 1] = '\0';
1946 if (!check_label_space(pimg
, pimg
->buf_len
* 2)) {
1947 img_errno
= IMG_OUTOFMEMORY
;
1952 pimg
->label
= pimg
->label_buf
;
1954 if (pimg
->label
[0] == '\\') pimg
->label
++;
1956 if (pimg
->survey_len
) {
1957 size_t l
= pimg
->survey_len
+ 1;
1958 if (strncmp(pimg
->survey
, pimg
->label
, l
) != 0) goto againpos
;
1963 } else if (pimg
->version
== VERSION_COMPASS_PLT
) {
1964 /* Compass .plt file */
1965 if (pimg
->pending
> 0) {
1966 /* -1 signals we've entered the first survey we want to
1967 * read, and need to fudge lots if the first action is 'D'...
1969 /* pending MOVE or LINE */
1970 int r
= pimg
->pending
- 4;
1973 pimg
->label
[pimg
->label_len
] = '\0';
1981 int ch
= GETC(pimg
->fh
);
1984 case '\x1a': case EOF
: /* Don't insist on ^Z at end of file */
1986 case 'X': case 'F': case 'S':
1987 /* bounding boX (marks end of survey), Feature survey, or
1988 * new Section - skip to next survey */
1989 if (pimg
->survey
) return img_STOP
;
1993 ch
= GETC(pimg
->fh
);
1994 } while (ch
!= '\n' && ch
!= '\r' && ch
!= EOF
);
1995 while (ch
== '\n' || ch
== '\r') ch
= GETC(pimg
->fh
);
1996 if (ch
== 'N') break;
1997 if (ch
== '\x1a' || ch
== EOF
) return img_STOP
;
2001 line
= getline_alloc(pimg
->fh
);
2003 img_errno
= IMG_OUTOFMEMORY
;
2006 while (line
[len
] > 32) ++len
;
2007 if (pimg
->label_len
== 0) pimg
->pending
= -1;
2008 if (!check_label_space(pimg
, len
+ 1)) {
2010 img_errno
= IMG_OUTOFMEMORY
;
2013 pimg
->label_len
= len
;
2014 pimg
->label
= pimg
->label_buf
;
2015 memcpy(pimg
->label
, line
, len
);
2016 pimg
->label
[len
] = '\0';
2019 case 'M': case 'D': {
2022 if (pimg
->survey
&& pimg
->label_len
== 0) {
2023 /* We're only holding onto this line in case the first line
2024 * of the 'N' is a 'D', so skip it for now...
2028 if (ch
== 'D' && pimg
->pending
== -1) {
2030 fpos
= ftell(pimg
->fh
) - 1;
2031 fseek(pimg
->fh
, pimg
->start
, SEEK_SET
);
2032 ch
= GETC(pimg
->fh
);
2035 /* If a file actually has a 'D' before any 'M', then
2036 * pretend the 'D' is an 'M' - one of the examples
2037 * in the docs was like this! */
2041 line
= getline_alloc(pimg
->fh
);
2043 img_errno
= IMG_OUTOFMEMORY
;
2046 /* Compass stores coordinates as North, East, Up = (y,x,z)! */
2047 if (sscanf(line
, "%lf%lf%lf", &p
->y
, &p
->x
, &p
->z
) != 3) {
2049 if (ferror(pimg
->fh
)) {
2050 img_errno
= IMG_READERROR
;
2052 img_errno
= IMG_BADFORMAT
;
2056 p
->x
*= METRES_PER_FOOT
;
2057 p
->y
*= METRES_PER_FOOT
;
2058 p
->z
*= METRES_PER_FOOT
;
2059 q
= strchr(line
, 'S');
2062 img_errno
= IMG_BADFORMAT
;
2067 while (q
[len
] > ' ') ++len
;
2069 len
+= 2; /* ' ' and '\0' */
2070 if (!check_label_space(pimg
, pimg
->label_len
+ len
)) {
2071 img_errno
= IMG_OUTOFMEMORY
;
2074 pimg
->label
= pimg
->label_buf
;
2075 if (pimg
->label_len
) {
2076 pimg
->label
[pimg
->label_len
] = ' ';
2077 memcpy(pimg
->label
+ pimg
->label_len
+ 1, q
, len
- 1);
2079 memcpy(pimg
->label
, q
, len
- 1);
2082 /* Now read LRUD. Technically, this is optional but virtually
2083 * all PLT files have it (with dummy negative values if no LRUD
2084 * was measured) and some versions of Compass can't read PLT
2087 while (*q
&& *q
<= ' ') q
++;
2089 if (sscanf(q
+ 1, "%lf%lf%lf%lf",
2090 &pimg
->l
, &pimg
->r
, &pimg
->u
, &pimg
->d
) != 4) {
2092 if (ferror(pimg
->fh
)) {
2093 img_errno
= IMG_READERROR
;
2095 img_errno
= IMG_BADFORMAT
;
2099 pimg
->l
*= METRES_PER_FOOT
;
2100 pimg
->r
*= METRES_PER_FOOT
;
2101 pimg
->u
*= METRES_PER_FOOT
;
2102 pimg
->d
*= METRES_PER_FOOT
;
2104 pimg
->l
= pimg
->r
= pimg
->u
= pimg
->d
= -1;
2107 pimg
->flags
= img_SFLAG_UNDERGROUND
; /* default flags */
2109 fseek(pimg
->fh
, fpos
, SEEK_SET
);
2111 pimg
->pending
= (ch
== 'M' ? img_MOVE
: img_LINE
) + 4;
2116 img_errno
= IMG_BADFORMAT
;
2121 /* CMAP .xyz file */
2126 if (pimg
->pending
) {
2127 /* pending MOVE or LINE or LABEL or STOP */
2128 int r
= pimg
->pending
- 4;
2129 /* Set label to empty - don't use "" as we adjust label relative
2130 * to label_buf when label_buf is reallocated. */
2131 pimg
->label
= pimg
->label_buf
+ strlen(pimg
->label_buf
);
2133 if (r
== img_LABEL
) {
2135 read_xyz_shot_coords(p
, pimg
->label_buf
+ 16);
2136 subtract_xyz_shot_deltas(p
, pimg
->label_buf
+ 16);
2137 pimg
->pending
= img_STOP
+ 4;
2143 if (r
== img_STOP
) {
2145 read_xyz_shot_coords(p
, pimg
->label_buf
+ 16);
2152 pimg
->label
= pimg
->label_buf
;
2155 if (feof(pimg
->fh
)) return img_STOP
;
2156 line
= getline_alloc(pimg
->fh
);
2158 img_errno
= IMG_OUTOFMEMORY
;
2161 } while (line
[0] == ' ' || line
[0] == '\0');
2162 if (line
[0] == '\x1a') return img_STOP
;
2165 if (pimg
->version
== VERSION_CMAP_STATION
) {
2166 /* station variant */
2169 img_errno
= IMG_BADFORMAT
;
2172 memcpy(pimg
->label
, line
, 6);
2173 q
= (char *)memchr(pimg
->label
, ' ', 6);
2174 if (!q
) q
= pimg
->label
+ 6;
2177 read_xyz_station_coords(p
, line
);
2179 /* FIXME: look at prev for lines (line + 32, 5) */
2180 /* FIXME: duplicate stations... */
2183 /* Shot variant (VERSION_CMAP_SHOT) */
2184 char old
[8], new_
[8];
2187 img_errno
= IMG_BADFORMAT
;
2191 memcpy(old
, line
, 7);
2192 q
= (char *)memchr(old
, ' ', 7);
2193 if (!q
) q
= old
+ 7;
2196 memcpy(new_
, line
+ 7, 7);
2197 q
= (char *)memchr(new_
, ' ', 7);
2198 if (!q
) q
= new_
+ 7;
2201 pimg
->flags
= img_SFLAG_UNDERGROUND
;
2203 if (strcmp(old
, new_
) == 0) {
2204 pimg
->pending
= img_MOVE
+ 4;
2205 read_xyz_shot_coords(p
, line
);
2206 strcpy(pimg
->label
, new_
);
2211 if (strcmp(old
, pimg
->label
) == 0) {
2212 pimg
->pending
= img_LINE
+ 4;
2213 read_xyz_shot_coords(p
, line
);
2214 strcpy(pimg
->label
, new_
);
2219 pimg
->pending
= img_LABEL
+ 4;
2220 read_xyz_shot_coords(p
, line
);
2221 strcpy(pimg
->label
, new_
);
2222 memcpy(pimg
->label
+ 16, line
, 70);
2231 write_coord(FILE *fh
, double x
, double y
, double z
)
2235 static INT32_T X_
, Y_
, Z_
;
2236 INT32_T X
= my_lround(x
* 100.0);
2237 INT32_T Y
= my_lround(y
* 100.0);
2238 INT32_T Z
= my_lround(z
* 100.0);
2246 X_
= X
; Y_
= Y
; Z_
= Z
;
2250 write_v3label(img
*pimg
, int opt
, const char *s
)
2254 /* find length of common prefix */
2256 for (len
= 0; s
[len
] == pimg
->label_buf
[len
] && s
[len
] != '\0'; len
++) {
2257 if (s
[len
] == '.') dot
= len
+ 1;
2260 SVX_ASSERT(len
<= pimg
->label_len
);
2261 n
= pimg
->label_len
- len
;
2263 if (pimg
->label_len
) PUTC(0, pimg
->fh
);
2264 } else if (n
<= 16) {
2265 if (n
) PUTC(n
+ 15, pimg
->fh
);
2266 } else if (dot
== 0) {
2267 if (pimg
->label_len
) PUTC(0, pimg
->fh
);
2270 const char *p
= pimg
->label_buf
+ dot
;
2272 for (len
= pimg
->label_len
- dot
- 17; len
; len
--) {
2273 if (*p
++ == '.') n
++;
2279 if (pimg
->label_len
) PUTC(0, pimg
->fh
);
2284 n
= strlen(s
+ len
);
2285 PUTC(opt
, pimg
->fh
);
2288 } else if (n
< 0xffff + 0xfe) {
2289 PUTC(0xfe, pimg
->fh
);
2290 put16((short)(n
- 0xfe), pimg
->fh
);
2292 PUTC(0xff, pimg
->fh
);
2295 fwrite(s
+ len
, n
, 1, pimg
->fh
);
2298 pimg
->label_len
= n
;
2299 if (!check_label_space(pimg
, n
+ 1))
2300 return 0; /* FIXME: distinguish out of memory... */
2301 memcpy(pimg
->label_buf
+ len
, s
+ len
, n
- len
+ 1);
2303 return !ferror(pimg
->fh
);
2307 write_v8label(img
*pimg
, int opt
, int common_flag
, size_t common_val
,
2310 size_t len
, del
, add
;
2312 /* find length of common prefix */
2313 for (len
= 0; s
[len
] == pimg
->label_buf
[len
] && s
[len
] != '\0'; len
++) {
2316 SVX_ASSERT(len
<= pimg
->label_len
);
2317 del
= pimg
->label_len
- len
;
2318 add
= strlen(s
+ len
);
2320 if (add
== common_val
&& del
== common_val
) {
2321 PUTC(opt
| common_flag
, pimg
->fh
);
2323 PUTC(opt
, pimg
->fh
);
2324 if (del
<= 15 && add
<= 15 && (del
|| add
)) {
2325 PUTC((del
<< 4) | add
, pimg
->fh
);
2327 PUTC(0x00, pimg
->fh
);
2329 PUTC(del
, pimg
->fh
);
2331 PUTC(0xff, pimg
->fh
);
2332 put32(del
, pimg
->fh
);
2335 PUTC(add
, pimg
->fh
);
2337 PUTC(0xff, pimg
->fh
);
2338 put32(add
, pimg
->fh
);
2344 fwrite(s
+ len
, add
, 1, pimg
->fh
);
2346 pimg
->label_len
= len
+ add
;
2347 if (add
> del
&& !check_label_space(pimg
, pimg
->label_len
+ 1))
2348 return 0; /* FIXME: distinguish out of memory... */
2350 memcpy(pimg
->label_buf
+ len
, s
+ len
, add
+ 1);
2352 return !ferror(pimg
->fh
);
2356 img_write_item_date_new(img
*pimg
)
2359 /* Only write dates when they've changed. */
2360 #if IMG_API_VERSION == 0
2361 if (pimg
->date1
== pimg
->olddate1
&& pimg
->date2
== pimg
->olddate2
)
2364 same
= (pimg
->date1
== pimg
->date2
);
2365 unset
= (pimg
->date1
== 0);
2366 #else /* IMG_API_VERSION == 1 */
2367 if (pimg
->days1
== pimg
->olddays1
&& pimg
->days2
== pimg
->olddays2
)
2370 same
= (pimg
->days1
== pimg
->days2
);
2371 unset
= (pimg
->days1
== -1);
2376 PUTC(0x10, pimg
->fh
);
2378 PUTC(0x11, pimg
->fh
);
2379 #if IMG_API_VERSION == 0
2380 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2381 #else /* IMG_API_VERSION == 1 */
2382 put16(pimg
->days1
, pimg
->fh
);
2386 #if IMG_API_VERSION == 0
2387 int diff
= (pimg
->date2
- pimg
->date1
) / 86400;
2388 if (diff
> 0 && diff
<= 256) {
2389 PUTC(0x12, pimg
->fh
);
2390 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2391 PUTC(diff
- 1, pimg
->fh
);
2393 PUTC(0x13, pimg
->fh
);
2394 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2395 put16(pimg
->date2
/ 86400 + 25567, pimg
->fh
);
2397 #else /* IMG_API_VERSION == 1 */
2398 int diff
= pimg
->days2
- pimg
->days1
;
2399 if (diff
> 0 && diff
<= 256) {
2400 PUTC(0x12, pimg
->fh
);
2401 put16(pimg
->days1
, pimg
->fh
);
2402 PUTC(diff
- 1, pimg
->fh
);
2404 PUTC(0x13, pimg
->fh
);
2405 put16(pimg
->days1
, pimg
->fh
);
2406 put16(pimg
->days2
, pimg
->fh
);
2410 #if IMG_API_VERSION == 0
2411 pimg
->olddate1
= pimg
->date1
;
2412 pimg
->olddate2
= pimg
->date2
;
2413 #else /* IMG_API_VERSION == 1 */
2414 pimg
->olddays1
= pimg
->days1
;
2415 pimg
->olddays2
= pimg
->days2
;
2420 img_write_item_date(img
*pimg
)
2423 /* Only write dates when they've changed. */
2424 #if IMG_API_VERSION == 0
2425 if (pimg
->date1
== pimg
->olddate1
&& pimg
->date2
== pimg
->olddate2
)
2428 same
= (pimg
->date1
== pimg
->date2
);
2429 unset
= (pimg
->date1
== 0);
2430 #else /* IMG_API_VERSION == 1 */
2431 if (pimg
->days1
== pimg
->olddays1
&& pimg
->days2
== pimg
->olddays2
)
2434 same
= (pimg
->days1
== pimg
->days2
);
2435 unset
= (pimg
->days1
== -1);
2439 if (img_output_version
< 7) {
2440 PUTC(0x20, pimg
->fh
);
2441 #if IMG_API_VERSION == 0
2442 put32(pimg
->date1
, pimg
->fh
);
2443 #else /* IMG_API_VERSION == 1 */
2444 put32((pimg
->days1
- 25567) * 86400, pimg
->fh
);
2448 PUTC(0x24, pimg
->fh
);
2450 PUTC(0x20, pimg
->fh
);
2451 #if IMG_API_VERSION == 0
2452 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2453 #else /* IMG_API_VERSION == 1 */
2454 put16(pimg
->days1
, pimg
->fh
);
2459 if (img_output_version
< 7) {
2460 PUTC(0x21, pimg
->fh
);
2461 #if IMG_API_VERSION == 0
2462 put32(pimg
->date1
, pimg
->fh
);
2463 put32(pimg
->date2
, pimg
->fh
);
2464 #else /* IMG_API_VERSION == 1 */
2465 put32((pimg
->days1
- 25567) * 86400, pimg
->fh
);
2466 put32((pimg
->days2
- 25567) * 86400, pimg
->fh
);
2469 #if IMG_API_VERSION == 0
2470 int diff
= (pimg
->date2
- pimg
->date1
) / 86400;
2471 if (diff
> 0 && diff
<= 256) {
2472 PUTC(0x21, pimg
->fh
);
2473 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2474 PUTC(diff
- 1, pimg
->fh
);
2476 PUTC(0x23, pimg
->fh
);
2477 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2478 put16(pimg
->date2
/ 86400 + 25567, pimg
->fh
);
2480 #else /* IMG_API_VERSION == 1 */
2481 int diff
= pimg
->days2
- pimg
->days1
;
2482 if (diff
> 0 && diff
<= 256) {
2483 PUTC(0x21, pimg
->fh
);
2484 put16(pimg
->days1
, pimg
->fh
);
2485 PUTC(diff
- 1, pimg
->fh
);
2487 PUTC(0x23, pimg
->fh
);
2488 put16(pimg
->days1
, pimg
->fh
);
2489 put16(pimg
->days2
, pimg
->fh
);
2494 #if IMG_API_VERSION == 0
2495 pimg
->olddate1
= pimg
->date1
;
2496 pimg
->olddate2
= pimg
->date2
;
2497 #else /* IMG_API_VERSION == 1 */
2498 pimg
->olddays1
= pimg
->days1
;
2499 pimg
->olddays2
= pimg
->days2
;
2504 img_write_item_new(img
*pimg
, int code
, int flags
, const char *s
,
2505 double x
, double y
, double z
);
2507 img_write_item_v3to7(img
*pimg
, int code
, int flags
, const char *s
,
2508 double x
, double y
, double z
);
2510 img_write_item_ancient(img
*pimg
, int code
, int flags
, const char *s
,
2511 double x
, double y
, double z
);
2514 img_write_item(img
*pimg
, int code
, int flags
, const char *s
,
2515 double x
, double y
, double z
)
2518 if (pimg
->version
>= 8) {
2519 img_write_item_new(pimg
, code
, flags
, s
, x
, y
, z
);
2520 } else if (pimg
->version
>= 3) {
2521 img_write_item_v3to7(pimg
, code
, flags
, s
, x
, y
, z
);
2523 img_write_item_ancient(pimg
, code
, flags
, s
, x
, y
, z
);
2528 img_write_item_new(img
*pimg
, int code
, int flags
, const char *s
,
2529 double x
, double y
, double z
)
2533 write_v8label(pimg
, 0x80 | flags
, 0, -1, s
);
2536 INT32_T l
, r
, u
, d
, max_dim
;
2537 img_write_item_date_new(pimg
);
2538 l
= (INT32_T
)my_lround(pimg
->l
* 100.0);
2539 r
= (INT32_T
)my_lround(pimg
->r
* 100.0);
2540 u
= (INT32_T
)my_lround(pimg
->u
* 100.0);
2541 d
= (INT32_T
)my_lround(pimg
->d
* 100.0);
2546 max_dim
= max(max(l
, r
), max(u
, d
));
2547 flags
= (flags
& img_XFLAG_END
) ? 1 : 0;
2548 if (max_dim
>= 32768) flags
|= 2;
2549 write_v8label(pimg
, 0x30 | flags
, 0, -1, s
);
2551 /* Big passage! Need to use 4 bytes. */
2568 img_write_item_date_new(pimg
);
2569 if (pimg
->style
!= pimg
->oldstyle
) {
2570 switch (pimg
->style
) {
2571 case img_STYLE_NORMAL
:
2572 case img_STYLE_DIVING
:
2573 case img_STYLE_CARTESIAN
:
2574 case img_STYLE_CYLPOLAR
:
2575 case img_STYLE_NOSURVEY
:
2576 PUTC(pimg
->style
, pimg
->fh
);
2579 pimg
->oldstyle
= pimg
->style
;
2581 write_v8label(pimg
, 0x40 | flags
, 0x20, 0x00, s
? s
: "");
2583 default: /* ignore for now */
2586 write_coord(pimg
->fh
, x
, y
, z
);
2590 img_write_item_v3to7(img
*pimg
, int code
, int flags
, const char *s
,
2591 double x
, double y
, double z
)
2595 write_v3label(pimg
, 0x40 | flags
, s
);
2598 INT32_T l
, r
, u
, d
, max_dim
;
2599 /* Need at least version 5 for img_XSECT. */
2600 if (pimg
->version
< 5) return;
2601 img_write_item_date(pimg
);
2602 l
= (INT32_T
)my_lround(pimg
->l
* 100.0);
2603 r
= (INT32_T
)my_lround(pimg
->r
* 100.0);
2604 u
= (INT32_T
)my_lround(pimg
->u
* 100.0);
2605 d
= (INT32_T
)my_lround(pimg
->d
* 100.0);
2610 max_dim
= max(max(l
, r
), max(u
, d
));
2611 flags
= (flags
& img_XFLAG_END
) ? 1 : 0;
2612 if (max_dim
>= 32768) flags
|= 2;
2613 write_v3label(pimg
, 0x30 | flags
, s
);
2615 /* Big passage! Need to use 4 bytes. */
2632 if (pimg
->version
>= 4) {
2633 img_write_item_date(pimg
);
2635 write_v3label(pimg
, 0x80 | flags
, s
? s
: "");
2637 default: /* ignore for now */
2640 write_coord(pimg
->fh
, x
, y
, z
);
2644 img_write_item_ancient(img
*pimg
, int code
, int flags
, const char *s
,
2645 double x
, double y
, double z
)
2649 SVX_ASSERT(pimg
->version
> 0);
2652 if (pimg
->version
== 1) {
2653 /* put a move before each label */
2654 img_write_item_ancient(pimg
, img_MOVE
, 0, NULL
, x
, y
, z
);
2656 fputsnl(s
, pimg
->fh
);
2660 if (len
> 255 || strchr(s
, '\n')) {
2661 /* long label - not in early incarnations of v2 format, but few
2662 * 3d files will need these, so better not to force incompatibility
2663 * with a new version I think... */
2665 PUTC(flags
, pimg
->fh
);
2666 put32(len
, pimg
->fh
);
2669 PUTC(0x40 | (flags
& 0x3f), pimg
->fh
);
2670 fputsnl(s
, pimg
->fh
);
2678 if (pimg
->version
> 1) {
2679 opt
= 0x80 | (flags
& 0x3f);
2684 default: /* ignore for now */
2687 if (pimg
->version
== 1) {
2688 put32(opt
, pimg
->fh
);
2690 if (opt
) PUTC(opt
, pimg
->fh
);
2692 write_coord(pimg
->fh
, x
, y
, z
);
2695 /* Write error information for the current traverse
2696 * n_legs is the number of legs in the traverse
2697 * length is the traverse length (in m)
2698 * E is the ratio of the observed misclosure to the theoretical one
2699 * H is the ratio of the observed horizontal misclosure to the theoretical one
2700 * V is the ratio of the observed vertical misclosure to the theoretical one
2703 img_write_errors(img
*pimg
, int n_legs
, double length
,
2704 double E
, double H
, double V
)
2706 PUTC((pimg
->version
>= 8 ? 0x1f : 0x22), pimg
->fh
);
2707 put32(n_legs
, pimg
->fh
);
2708 put32((INT32_T
)my_lround(length
* 100.0), pimg
->fh
);
2709 put32((INT32_T
)my_lround(E
* 100.0), pimg
->fh
);
2710 put32((INT32_T
)my_lround(H
* 100.0), pimg
->fh
);
2711 put32((INT32_T
)my_lround(V
* 100.0), pimg
->fh
);
2715 img_close(img
*pimg
)
2721 osfree(pimg
->survey
);
2722 osfree(pimg
->title
);
2724 osfree(pimg
->datestamp
);
2726 /* write end of data marker */
2727 switch (pimg
->version
) {
2729 put32((INT32_T
)-1, pimg
->fh
);
2732 if (pimg
->version
<= 7 ?
2733 (pimg
->label_len
!= 0) :
2734 (pimg
->style
!= img_STYLE_NORMAL
)) {
2743 if (ferror(pimg
->fh
)) result
= 0;
2744 if (fclose(pimg
->fh
)) result
= 0;
2745 if (!result
) img_errno
= pimg
->fRead
? IMG_READERROR
: IMG_WRITEERROR
;
2747 osfree(pimg
->label_buf
);
2748 osfree(pimg
->filename_opened
);