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 */
1908 while (fscanf(pimg
->fh
, "(%lf,%lf,%lf )", &p
->x
, &p
->y
, &p
->z
) != 3) {
1909 if (ferror(pimg
->fh
)) {
1910 img_errno
= IMG_READERROR
;
1913 if (feof(pimg
->fh
)) return img_STOP
;
1914 if (pimg
->pending
) {
1915 img_errno
= IMG_BADFORMAT
;
1919 /* ignore rest of line */
1921 ch
= GETC(pimg
->fh
);
1922 } while (ch
!= '\n' && ch
!= '\r' && ch
!= EOF
);
1925 pimg
->label_buf
[0] = '\0';
1927 ch
= GETC(pimg
->fh
);
1928 } while (ch
== ' ' || ch
== '\t');
1929 if (ch
== '\n' || ch
== EOF
) {
1930 /* If there's no label, set img_SFLAG_ANON. */
1931 pimg
->flags
|= img_SFLAG_ANON
;
1934 pimg
->label_buf
[0] = ch
;
1936 while (!feof(pimg
->fh
)) {
1937 if (!fgets(pimg
->label_buf
+ off
, pimg
->buf_len
- off
, pimg
->fh
)) {
1938 img_errno
= IMG_READERROR
;
1942 off
+= strlen(pimg
->label_buf
+ off
);
1943 if (off
&& pimg
->label_buf
[off
- 1] == '\n') {
1944 pimg
->label_buf
[off
- 1] = '\0';
1947 if (!check_label_space(pimg
, pimg
->buf_len
* 2)) {
1948 img_errno
= IMG_OUTOFMEMORY
;
1953 pimg
->label
= pimg
->label_buf
;
1955 if (pimg
->label
[0] == '\\') pimg
->label
++;
1957 if (pimg
->survey_len
) {
1958 size_t l
= pimg
->survey_len
+ 1;
1959 if (strncmp(pimg
->survey
, pimg
->label
, l
) != 0) goto againpos
;
1964 } else if (pimg
->version
== VERSION_COMPASS_PLT
) {
1965 /* Compass .plt file */
1966 if (pimg
->pending
> 0) {
1967 /* -1 signals we've entered the first survey we want to
1968 * read, and need to fudge lots if the first action is 'D'...
1970 /* pending MOVE or LINE */
1971 int r
= pimg
->pending
- 4;
1974 pimg
->label
[pimg
->label_len
] = '\0';
1982 int ch
= GETC(pimg
->fh
);
1985 case '\x1a': case EOF
: /* Don't insist on ^Z at end of file */
1987 case 'X': case 'F': case 'S':
1988 /* bounding boX (marks end of survey), Feature survey, or
1989 * new Section - skip to next survey */
1990 if (pimg
->survey
) return img_STOP
;
1994 ch
= GETC(pimg
->fh
);
1995 } while (ch
!= '\n' && ch
!= '\r' && ch
!= EOF
);
1996 while (ch
== '\n' || ch
== '\r') ch
= GETC(pimg
->fh
);
1997 if (ch
== 'N') break;
1998 if (ch
== '\x1a' || ch
== EOF
) return img_STOP
;
2002 line
= getline_alloc(pimg
->fh
);
2004 img_errno
= IMG_OUTOFMEMORY
;
2007 while (line
[len
] > 32) ++len
;
2008 if (pimg
->label_len
== 0) pimg
->pending
= -1;
2009 if (!check_label_space(pimg
, len
+ 1)) {
2011 img_errno
= IMG_OUTOFMEMORY
;
2014 pimg
->label_len
= len
;
2015 pimg
->label
= pimg
->label_buf
;
2016 memcpy(pimg
->label
, line
, len
);
2017 pimg
->label
[len
] = '\0';
2020 case 'M': case 'D': {
2023 if (pimg
->survey
&& pimg
->label_len
== 0) {
2024 /* We're only holding onto this line in case the first line
2025 * of the 'N' is a 'D', so skip it for now...
2029 if (ch
== 'D' && pimg
->pending
== -1) {
2031 fpos
= ftell(pimg
->fh
) - 1;
2032 fseek(pimg
->fh
, pimg
->start
, SEEK_SET
);
2033 ch
= GETC(pimg
->fh
);
2036 /* If a file actually has a 'D' before any 'M', then
2037 * pretend the 'D' is an 'M' - one of the examples
2038 * in the docs was like this! */
2042 line
= getline_alloc(pimg
->fh
);
2044 img_errno
= IMG_OUTOFMEMORY
;
2047 /* Compass stores coordinates as North, East, Up = (y,x,z)! */
2048 if (sscanf(line
, "%lf%lf%lf", &p
->y
, &p
->x
, &p
->z
) != 3) {
2050 if (ferror(pimg
->fh
)) {
2051 img_errno
= IMG_READERROR
;
2053 img_errno
= IMG_BADFORMAT
;
2057 p
->x
*= METRES_PER_FOOT
;
2058 p
->y
*= METRES_PER_FOOT
;
2059 p
->z
*= METRES_PER_FOOT
;
2060 q
= strchr(line
, 'S');
2063 img_errno
= IMG_BADFORMAT
;
2068 while (q
[len
] > ' ') ++len
;
2070 len
+= 2; /* ' ' and '\0' */
2071 if (!check_label_space(pimg
, pimg
->label_len
+ len
)) {
2072 img_errno
= IMG_OUTOFMEMORY
;
2075 pimg
->label
= pimg
->label_buf
;
2076 if (pimg
->label_len
) {
2077 pimg
->label
[pimg
->label_len
] = ' ';
2078 memcpy(pimg
->label
+ pimg
->label_len
+ 1, q
, len
- 1);
2080 memcpy(pimg
->label
, q
, len
- 1);
2083 /* Now read LRUD. Technically, this is optional but virtually
2084 * all PLT files have it (with dummy negative values if no LRUD
2085 * was measured) and some versions of Compass can't read PLT
2088 while (*q
&& *q
<= ' ') q
++;
2090 if (sscanf(q
+ 1, "%lf%lf%lf%lf",
2091 &pimg
->l
, &pimg
->r
, &pimg
->u
, &pimg
->d
) != 4) {
2093 if (ferror(pimg
->fh
)) {
2094 img_errno
= IMG_READERROR
;
2096 img_errno
= IMG_BADFORMAT
;
2100 pimg
->l
*= METRES_PER_FOOT
;
2101 pimg
->r
*= METRES_PER_FOOT
;
2102 pimg
->u
*= METRES_PER_FOOT
;
2103 pimg
->d
*= METRES_PER_FOOT
;
2105 pimg
->l
= pimg
->r
= pimg
->u
= pimg
->d
= -1;
2108 pimg
->flags
= img_SFLAG_UNDERGROUND
; /* default flags */
2110 fseek(pimg
->fh
, fpos
, SEEK_SET
);
2112 pimg
->pending
= (ch
== 'M' ? img_MOVE
: img_LINE
) + 4;
2117 img_errno
= IMG_BADFORMAT
;
2122 /* CMAP .xyz file */
2127 if (pimg
->pending
) {
2128 /* pending MOVE or LINE or LABEL or STOP */
2129 int r
= pimg
->pending
- 4;
2130 /* Set label to empty - don't use "" as we adjust label relative
2131 * to label_buf when label_buf is reallocated. */
2132 pimg
->label
= pimg
->label_buf
+ strlen(pimg
->label_buf
);
2134 if (r
== img_LABEL
) {
2136 read_xyz_shot_coords(p
, pimg
->label_buf
+ 16);
2137 subtract_xyz_shot_deltas(p
, pimg
->label_buf
+ 16);
2138 pimg
->pending
= img_STOP
+ 4;
2144 if (r
== img_STOP
) {
2146 read_xyz_shot_coords(p
, pimg
->label_buf
+ 16);
2153 pimg
->label
= pimg
->label_buf
;
2156 if (feof(pimg
->fh
)) return img_STOP
;
2157 line
= getline_alloc(pimg
->fh
);
2159 img_errno
= IMG_OUTOFMEMORY
;
2162 } while (line
[0] == ' ' || line
[0] == '\0');
2163 if (line
[0] == '\x1a') return img_STOP
;
2166 if (pimg
->version
== VERSION_CMAP_STATION
) {
2167 /* station variant */
2170 img_errno
= IMG_BADFORMAT
;
2173 memcpy(pimg
->label
, line
, 6);
2174 q
= (char *)memchr(pimg
->label
, ' ', 6);
2175 if (!q
) q
= pimg
->label
+ 6;
2178 read_xyz_station_coords(p
, line
);
2180 /* FIXME: look at prev for lines (line + 32, 5) */
2181 /* FIXME: duplicate stations... */
2184 /* Shot variant (VERSION_CMAP_SHOT) */
2185 char old
[8], new_
[8];
2188 img_errno
= IMG_BADFORMAT
;
2192 memcpy(old
, line
, 7);
2193 q
= (char *)memchr(old
, ' ', 7);
2194 if (!q
) q
= old
+ 7;
2197 memcpy(new_
, line
+ 7, 7);
2198 q
= (char *)memchr(new_
, ' ', 7);
2199 if (!q
) q
= new_
+ 7;
2202 pimg
->flags
= img_SFLAG_UNDERGROUND
;
2204 if (strcmp(old
, new_
) == 0) {
2205 pimg
->pending
= img_MOVE
+ 4;
2206 read_xyz_shot_coords(p
, line
);
2207 strcpy(pimg
->label
, new_
);
2212 if (strcmp(old
, pimg
->label
) == 0) {
2213 pimg
->pending
= img_LINE
+ 4;
2214 read_xyz_shot_coords(p
, line
);
2215 strcpy(pimg
->label
, new_
);
2220 pimg
->pending
= img_LABEL
+ 4;
2221 read_xyz_shot_coords(p
, line
);
2222 strcpy(pimg
->label
, new_
);
2223 memcpy(pimg
->label
+ 16, line
, 70);
2232 write_coord(FILE *fh
, double x
, double y
, double z
)
2236 static INT32_T X_
, Y_
, Z_
;
2237 INT32_T X
= my_lround(x
* 100.0);
2238 INT32_T Y
= my_lround(y
* 100.0);
2239 INT32_T Z
= my_lround(z
* 100.0);
2247 X_
= X
; Y_
= Y
; Z_
= Z
;
2251 write_v3label(img
*pimg
, int opt
, const char *s
)
2255 /* find length of common prefix */
2257 for (len
= 0; s
[len
] == pimg
->label_buf
[len
] && s
[len
] != '\0'; len
++) {
2258 if (s
[len
] == '.') dot
= len
+ 1;
2261 SVX_ASSERT(len
<= pimg
->label_len
);
2262 n
= pimg
->label_len
- len
;
2264 if (pimg
->label_len
) PUTC(0, pimg
->fh
);
2265 } else if (n
<= 16) {
2266 if (n
) PUTC(n
+ 15, pimg
->fh
);
2267 } else if (dot
== 0) {
2268 if (pimg
->label_len
) PUTC(0, pimg
->fh
);
2271 const char *p
= pimg
->label_buf
+ dot
;
2273 for (len
= pimg
->label_len
- dot
- 17; len
; len
--) {
2274 if (*p
++ == '.') n
++;
2280 if (pimg
->label_len
) PUTC(0, pimg
->fh
);
2285 n
= strlen(s
+ len
);
2286 PUTC(opt
, pimg
->fh
);
2289 } else if (n
< 0xffff + 0xfe) {
2290 PUTC(0xfe, pimg
->fh
);
2291 put16((short)(n
- 0xfe), pimg
->fh
);
2293 PUTC(0xff, pimg
->fh
);
2296 fwrite(s
+ len
, n
, 1, pimg
->fh
);
2299 pimg
->label_len
= n
;
2300 if (!check_label_space(pimg
, n
+ 1))
2301 return 0; /* FIXME: distinguish out of memory... */
2302 memcpy(pimg
->label_buf
+ len
, s
+ len
, n
- len
+ 1);
2304 return !ferror(pimg
->fh
);
2308 write_v8label(img
*pimg
, int opt
, int common_flag
, size_t common_val
,
2311 size_t len
, del
, add
;
2313 /* find length of common prefix */
2314 for (len
= 0; s
[len
] == pimg
->label_buf
[len
] && s
[len
] != '\0'; len
++) {
2317 SVX_ASSERT(len
<= pimg
->label_len
);
2318 del
= pimg
->label_len
- len
;
2319 add
= strlen(s
+ len
);
2321 if (add
== common_val
&& del
== common_val
) {
2322 PUTC(opt
| common_flag
, pimg
->fh
);
2324 PUTC(opt
, pimg
->fh
);
2325 if (del
<= 15 && add
<= 15 && (del
|| add
)) {
2326 PUTC((del
<< 4) | add
, pimg
->fh
);
2328 PUTC(0x00, pimg
->fh
);
2330 PUTC(del
, pimg
->fh
);
2332 PUTC(0xff, pimg
->fh
);
2333 put32(del
, pimg
->fh
);
2336 PUTC(add
, pimg
->fh
);
2338 PUTC(0xff, pimg
->fh
);
2339 put32(add
, pimg
->fh
);
2345 fwrite(s
+ len
, add
, 1, pimg
->fh
);
2347 pimg
->label_len
= len
+ add
;
2348 if (add
> del
&& !check_label_space(pimg
, pimg
->label_len
+ 1))
2349 return 0; /* FIXME: distinguish out of memory... */
2351 memcpy(pimg
->label_buf
+ len
, s
+ len
, add
+ 1);
2353 return !ferror(pimg
->fh
);
2357 img_write_item_date_new(img
*pimg
)
2360 /* Only write dates when they've changed. */
2361 #if IMG_API_VERSION == 0
2362 if (pimg
->date1
== pimg
->olddate1
&& pimg
->date2
== pimg
->olddate2
)
2365 same
= (pimg
->date1
== pimg
->date2
);
2366 unset
= (pimg
->date1
== 0);
2367 #else /* IMG_API_VERSION == 1 */
2368 if (pimg
->days1
== pimg
->olddays1
&& pimg
->days2
== pimg
->olddays2
)
2371 same
= (pimg
->days1
== pimg
->days2
);
2372 unset
= (pimg
->days1
== -1);
2377 PUTC(0x10, pimg
->fh
);
2379 PUTC(0x11, pimg
->fh
);
2380 #if IMG_API_VERSION == 0
2381 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2382 #else /* IMG_API_VERSION == 1 */
2383 put16(pimg
->days1
, pimg
->fh
);
2387 #if IMG_API_VERSION == 0
2388 int diff
= (pimg
->date2
- pimg
->date1
) / 86400;
2389 if (diff
> 0 && diff
<= 256) {
2390 PUTC(0x12, pimg
->fh
);
2391 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2392 PUTC(diff
- 1, pimg
->fh
);
2394 PUTC(0x13, pimg
->fh
);
2395 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2396 put16(pimg
->date2
/ 86400 + 25567, pimg
->fh
);
2398 #else /* IMG_API_VERSION == 1 */
2399 int diff
= pimg
->days2
- pimg
->days1
;
2400 if (diff
> 0 && diff
<= 256) {
2401 PUTC(0x12, pimg
->fh
);
2402 put16(pimg
->days1
, pimg
->fh
);
2403 PUTC(diff
- 1, pimg
->fh
);
2405 PUTC(0x13, pimg
->fh
);
2406 put16(pimg
->days1
, pimg
->fh
);
2407 put16(pimg
->days2
, pimg
->fh
);
2411 #if IMG_API_VERSION == 0
2412 pimg
->olddate1
= pimg
->date1
;
2413 pimg
->olddate2
= pimg
->date2
;
2414 #else /* IMG_API_VERSION == 1 */
2415 pimg
->olddays1
= pimg
->days1
;
2416 pimg
->olddays2
= pimg
->days2
;
2421 img_write_item_date(img
*pimg
)
2424 /* Only write dates when they've changed. */
2425 #if IMG_API_VERSION == 0
2426 if (pimg
->date1
== pimg
->olddate1
&& pimg
->date2
== pimg
->olddate2
)
2429 same
= (pimg
->date1
== pimg
->date2
);
2430 unset
= (pimg
->date1
== 0);
2431 #else /* IMG_API_VERSION == 1 */
2432 if (pimg
->days1
== pimg
->olddays1
&& pimg
->days2
== pimg
->olddays2
)
2435 same
= (pimg
->days1
== pimg
->days2
);
2436 unset
= (pimg
->days1
== -1);
2440 if (img_output_version
< 7) {
2441 PUTC(0x20, pimg
->fh
);
2442 #if IMG_API_VERSION == 0
2443 put32(pimg
->date1
, pimg
->fh
);
2444 #else /* IMG_API_VERSION == 1 */
2445 put32((pimg
->days1
- 25567) * 86400, pimg
->fh
);
2449 PUTC(0x24, pimg
->fh
);
2451 PUTC(0x20, pimg
->fh
);
2452 #if IMG_API_VERSION == 0
2453 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2454 #else /* IMG_API_VERSION == 1 */
2455 put16(pimg
->days1
, pimg
->fh
);
2460 if (img_output_version
< 7) {
2461 PUTC(0x21, pimg
->fh
);
2462 #if IMG_API_VERSION == 0
2463 put32(pimg
->date1
, pimg
->fh
);
2464 put32(pimg
->date2
, pimg
->fh
);
2465 #else /* IMG_API_VERSION == 1 */
2466 put32((pimg
->days1
- 25567) * 86400, pimg
->fh
);
2467 put32((pimg
->days2
- 25567) * 86400, pimg
->fh
);
2470 #if IMG_API_VERSION == 0
2471 int diff
= (pimg
->date2
- pimg
->date1
) / 86400;
2472 if (diff
> 0 && diff
<= 256) {
2473 PUTC(0x21, pimg
->fh
);
2474 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2475 PUTC(diff
- 1, pimg
->fh
);
2477 PUTC(0x23, pimg
->fh
);
2478 put16(pimg
->date1
/ 86400 + 25567, pimg
->fh
);
2479 put16(pimg
->date2
/ 86400 + 25567, pimg
->fh
);
2481 #else /* IMG_API_VERSION == 1 */
2482 int diff
= pimg
->days2
- pimg
->days1
;
2483 if (diff
> 0 && diff
<= 256) {
2484 PUTC(0x21, pimg
->fh
);
2485 put16(pimg
->days1
, pimg
->fh
);
2486 PUTC(diff
- 1, pimg
->fh
);
2488 PUTC(0x23, pimg
->fh
);
2489 put16(pimg
->days1
, pimg
->fh
);
2490 put16(pimg
->days2
, pimg
->fh
);
2495 #if IMG_API_VERSION == 0
2496 pimg
->olddate1
= pimg
->date1
;
2497 pimg
->olddate2
= pimg
->date2
;
2498 #else /* IMG_API_VERSION == 1 */
2499 pimg
->olddays1
= pimg
->days1
;
2500 pimg
->olddays2
= pimg
->days2
;
2505 img_write_item_new(img
*pimg
, int code
, int flags
, const char *s
,
2506 double x
, double y
, double z
);
2508 img_write_item_v3to7(img
*pimg
, int code
, int flags
, const char *s
,
2509 double x
, double y
, double z
);
2511 img_write_item_ancient(img
*pimg
, int code
, int flags
, const char *s
,
2512 double x
, double y
, double z
);
2515 img_write_item(img
*pimg
, int code
, int flags
, const char *s
,
2516 double x
, double y
, double z
)
2519 if (pimg
->version
>= 8) {
2520 img_write_item_new(pimg
, code
, flags
, s
, x
, y
, z
);
2521 } else if (pimg
->version
>= 3) {
2522 img_write_item_v3to7(pimg
, code
, flags
, s
, x
, y
, z
);
2524 img_write_item_ancient(pimg
, code
, flags
, s
, x
, y
, z
);
2529 img_write_item_new(img
*pimg
, int code
, int flags
, const char *s
,
2530 double x
, double y
, double z
)
2534 write_v8label(pimg
, 0x80 | flags
, 0, -1, s
);
2537 INT32_T l
, r
, u
, d
, max_dim
;
2538 img_write_item_date_new(pimg
);
2539 l
= (INT32_T
)my_lround(pimg
->l
* 100.0);
2540 r
= (INT32_T
)my_lround(pimg
->r
* 100.0);
2541 u
= (INT32_T
)my_lround(pimg
->u
* 100.0);
2542 d
= (INT32_T
)my_lround(pimg
->d
* 100.0);
2547 max_dim
= max(max(l
, r
), max(u
, d
));
2548 flags
= (flags
& img_XFLAG_END
) ? 1 : 0;
2549 if (max_dim
>= 32768) flags
|= 2;
2550 write_v8label(pimg
, 0x30 | flags
, 0, -1, s
);
2552 /* Big passage! Need to use 4 bytes. */
2569 img_write_item_date_new(pimg
);
2570 if (pimg
->style
!= pimg
->oldstyle
) {
2571 switch (pimg
->style
) {
2572 case img_STYLE_NORMAL
:
2573 case img_STYLE_DIVING
:
2574 case img_STYLE_CARTESIAN
:
2575 case img_STYLE_CYLPOLAR
:
2576 case img_STYLE_NOSURVEY
:
2577 PUTC(pimg
->style
, pimg
->fh
);
2580 pimg
->oldstyle
= pimg
->style
;
2582 write_v8label(pimg
, 0x40 | flags
, 0x20, 0x00, s
? s
: "");
2584 default: /* ignore for now */
2587 write_coord(pimg
->fh
, x
, y
, z
);
2591 img_write_item_v3to7(img
*pimg
, int code
, int flags
, const char *s
,
2592 double x
, double y
, double z
)
2596 write_v3label(pimg
, 0x40 | flags
, s
);
2599 INT32_T l
, r
, u
, d
, max_dim
;
2600 /* Need at least version 5 for img_XSECT. */
2601 if (pimg
->version
< 5) return;
2602 img_write_item_date(pimg
);
2603 l
= (INT32_T
)my_lround(pimg
->l
* 100.0);
2604 r
= (INT32_T
)my_lround(pimg
->r
* 100.0);
2605 u
= (INT32_T
)my_lround(pimg
->u
* 100.0);
2606 d
= (INT32_T
)my_lround(pimg
->d
* 100.0);
2611 max_dim
= max(max(l
, r
), max(u
, d
));
2612 flags
= (flags
& img_XFLAG_END
) ? 1 : 0;
2613 if (max_dim
>= 32768) flags
|= 2;
2614 write_v3label(pimg
, 0x30 | flags
, s
);
2616 /* Big passage! Need to use 4 bytes. */
2633 if (pimg
->version
>= 4) {
2634 img_write_item_date(pimg
);
2636 write_v3label(pimg
, 0x80 | flags
, s
? s
: "");
2638 default: /* ignore for now */
2641 write_coord(pimg
->fh
, x
, y
, z
);
2645 img_write_item_ancient(img
*pimg
, int code
, int flags
, const char *s
,
2646 double x
, double y
, double z
)
2650 SVX_ASSERT(pimg
->version
> 0);
2653 if (pimg
->version
== 1) {
2654 /* put a move before each label */
2655 img_write_item_ancient(pimg
, img_MOVE
, 0, NULL
, x
, y
, z
);
2657 fputsnl(s
, pimg
->fh
);
2661 if (len
> 255 || strchr(s
, '\n')) {
2662 /* long label - not in early incarnations of v2 format, but few
2663 * 3d files will need these, so better not to force incompatibility
2664 * with a new version I think... */
2666 PUTC(flags
, pimg
->fh
);
2667 put32(len
, pimg
->fh
);
2670 PUTC(0x40 | (flags
& 0x3f), pimg
->fh
);
2671 fputsnl(s
, pimg
->fh
);
2679 if (pimg
->version
> 1) {
2680 opt
= 0x80 | (flags
& 0x3f);
2685 default: /* ignore for now */
2688 if (pimg
->version
== 1) {
2689 put32(opt
, pimg
->fh
);
2691 if (opt
) PUTC(opt
, pimg
->fh
);
2693 write_coord(pimg
->fh
, x
, y
, z
);
2696 /* Write error information for the current traverse
2697 * n_legs is the number of legs in the traverse
2698 * length is the traverse length (in m)
2699 * E is the ratio of the observed misclosure to the theoretical one
2700 * H is the ratio of the observed horizontal misclosure to the theoretical one
2701 * V is the ratio of the observed vertical misclosure to the theoretical one
2704 img_write_errors(img
*pimg
, int n_legs
, double length
,
2705 double E
, double H
, double V
)
2707 PUTC((pimg
->version
>= 8 ? 0x1f : 0x22), pimg
->fh
);
2708 put32(n_legs
, pimg
->fh
);
2709 put32((INT32_T
)my_lround(length
* 100.0), pimg
->fh
);
2710 put32((INT32_T
)my_lround(E
* 100.0), pimg
->fh
);
2711 put32((INT32_T
)my_lround(H
* 100.0), pimg
->fh
);
2712 put32((INT32_T
)my_lround(V
* 100.0), pimg
->fh
);
2716 img_close(img
*pimg
)
2722 osfree(pimg
->survey
);
2723 osfree(pimg
->title
);
2725 osfree(pimg
->datestamp
);
2727 /* write end of data marker */
2728 switch (pimg
->version
) {
2730 put32((INT32_T
)-1, pimg
->fh
);
2733 if (pimg
->version
<= 7 ?
2734 (pimg
->label_len
!= 0) :
2735 (pimg
->style
!= img_STYLE_NORMAL
)) {
2744 if (ferror(pimg
->fh
)) result
= 0;
2745 if (fclose(pimg
->fh
)) result
= 0;
2746 if (!result
) img_errno
= pimg
->fRead
? IMG_READERROR
: IMG_WRITEERROR
;
2748 osfree(pimg
->label_buf
);
2749 osfree(pimg
->filename_opened
);