source: git/src/img.c @ 0116e70

RELEASE/1.0RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernloglog-selectstereostereo-2025walls-datawalls-data-hanging-as-warningwarn-only-for-hanging-survey
Last change on this file since 0116e70 was 58ad9da, checked in by Olly Betts <olly@…>, 24 years ago

If loading a subsurvey, override the title in the 3d file with the leafname
of that survey.

git-svn-id: file:///home/survex-svn/survex/trunk@1292 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 22.0 KB
RevLine 
[d1b1380]1/* > img.c
2 * Routines for reading and writing Survex ".3d" image files
[bd1913f]3 * Copyright (C) 1993-2001 Olly Betts
[846746e]4 *
[89231c4]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.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
[d1b1380]18 */
19
[a420b49]20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
[d1b1380]24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <time.h>
28#include <ctype.h>
29
[72af530]30#include "img.h"
31#ifdef IMG_HOSTED
[d69255f]32# include "debug.h"
[d1b1380]33# include "filelist.h"
[d69255f]34# include "filename.h"
35# include "message.h"
36# include "useful.h"
[a420b49]37# define TIMENA msg(/*Date and time not available.*/108)
38# define TIMEFMT msg(/*%a,%Y.%m.%d %H:%M:%S %Z*/107)
[d1b1380]39#else
[72af530]40# define INT32_T long
[d1b1380]41# define TIMENA "Time not available."
42# define TIMEFMT "%a,%Y.%m.%d %H:%M:%S %Z"
43# define EXT_SVX_3D "3d"
44# define xosmalloc(L) malloc((L))
[72af530]45# define xosrealloc(L,S) realloc((L),(S))
[d1b1380]46# define osfree(P) free((P))
47# define ossizeof(T) sizeof(T)
[72af530]48/* in IMG_HOSTED mode, this tests if a filename refers to a directory */
[d1b1380]49# define fDirectory(X) 0
50/* open file FNM with mode MODE, maybe using path PTH and/or extension EXT */
51/* path isn't used in img.c, but EXT is */
52# define fopenWithPthAndExt(PTH,FNM,EXT,MODE,X) fopen(FNM,MODE)
53# define fFalse 0
54# define fTrue 1
55# define bool int
56/* dummy do {...} while(0) hack to permit stuff like
57 * if (s) fputsnl(s,fh); else exit(1);
58 * to work as intended
59 */
[23f7ea7]60# define fputsnl(S, FH) do {fputs((S), (FH)); putc('\n', (FH));} while(0)
[d69255f]61# define ASSERT(X)
[d1b1380]62
[a420b49]63static long
64get32(FILE *fh)
65{
[ad9a5cd]66   long w = getc(fh);
[a420b49]67   w |= (long)getc(fh) << 8l;
68   w |= (long)getc(fh) << 16l;
69   w |= (long)getc(fh) << 24l;
70   return w;
[d1b1380]71}
72
[a420b49]73static void
74put32(long w, FILE *fh)
75{
76   putc((char)(w), fh);
77   putc((char)(w >> 8l), fh);
78   putc((char)(w >> 16l), fh);
79   putc((char)(w >> 24l), fh);
[d1b1380]80}
[5c3c61a]81
82#endif
83
[d69255f]84unsigned int img_output_version = 3;
[5c3c61a]85
[23f7ea7]86#define TMPBUFLEN 256
87static char tmpbuf[TMPBUFLEN];
[5c3c61a]88
[72af530]89#ifdef IMG_HOSTED
[5c3c61a]90static enum {
91   IMG_NONE = 0,
[759fb47]92   IMG_FILENOTFOUND = /*Couldn't open data file `%s'*/24,
[5c3c61a]93   IMG_OUTOFMEMORY  = /*Out of memory %.0s*/38,
[759fb47]94   IMG_DIRECTORY    = /*Filename `%s' refers to directory*/44,
95   IMG_CANTOPENOUT  = /*Failed to open output file `%s'*/47,
[ad9a5cd]96   IMG_BADFORMAT    = /*Bad 3d image file `%s'*/106,
97   IMG_READERROR    = /*Error reading from file `%s'*/109,
[6c1c4f3]98   IMG_WRITEERROR   = /*Error writing to file `%s'*/110,
99   IMG_TOONEW       = /*File `%s' has a newer format than this program can understand*/114
[5c3c61a]100} img_errno = IMG_NONE;
101#else
102static img_errcode img_errno = IMG_NONE;
[c0563da]103#endif
[d1b1380]104
[5c3c61a]105/* Read a line from a stream to a buffer. Any eol chars are removed
106 * from the file and the length of the string excluding '\0' is returned */
[a420b49]107static int
108getline(char *buf, size_t len, FILE *fh)
109{
[eb18f4d]110   size_t i = 0;
[a420b49]111   int ch;
[d1b1380]112
[a420b49]113   ch = getc(fh);
[647407d]114   while (ch != '\n' && ch != '\r' && ch != EOF && i < len - 1) {
[a420b49]115      buf[i++] = ch;
116      ch = getc(fh);
117   }
[647407d]118   if (ch == '\n' || ch == '\r') {
119      /* remove any further eol chars (for DOS text files) */
[a420b49]120      do {
121         ch = getc(fh);
122      } while (ch == '\n' || ch == '\r');
123      ungetc(ch, fh); /* we don't want it, so put it back */
124   }
125   buf[i] = '\0';
[5c3c61a]126   return i;
[d1b1380]127}
[c0563da]128
[72af530]129#ifndef IMG_HOSTED
[a420b49]130img_errcode
131img_error(void)
132{
133   return img_errno;
[d1b1380]134}
135#else
[a420b49]136int
137img_error(void)
138{
139   return (int)img_errno;
[d1b1380]140}
141#endif
142
[a420b49]143img *
[76bbb7c9]144img_open_survey(const char *fnm, char *title_buf, char *date_buf,
145                const char *survey)
[a420b49]146{
147   img *pimg;
148
149   if (fDirectory(fnm)) {
150      img_errno = IMG_DIRECTORY;
151      return NULL;
152   }
[d1b1380]153
[a420b49]154   pimg = (img *)xosmalloc(ossizeof(img));
155   if (pimg == NULL) {
156      img_errno = IMG_OUTOFMEMORY;
157      return NULL;
158   }
[d1b1380]159
[23f7ea7]160   pimg->buf_len = 257;
[0ff23cb]161   pimg->label_buf = xosmalloc(pimg->buf_len);
162   if (!pimg->label_buf) {
[23f7ea7]163      osfree(pimg);
164      img_errno = IMG_OUTOFMEMORY;
165      return NULL;
166   }
167
[a420b49]168   pimg->fh = fopenWithPthAndExt("", fnm, EXT_SVX_3D, "rb", NULL);
169   if (pimg->fh == NULL) {
170      osfree(pimg);
171      img_errno = IMG_FILENOTFOUND;
172      return NULL;
173   }
[d1b1380]174
[23f7ea7]175   getline(tmpbuf, TMPBUFLEN, pimg->fh); /* id string */
176   if (strcmp(tmpbuf, "Survex 3D Image File") != 0) {
[a420b49]177      fclose(pimg->fh);
178      osfree(pimg);
179      img_errno = IMG_BADFORMAT;
180      return NULL;
181   }
[d1b1380]182
[23f7ea7]183   getline(tmpbuf, TMPBUFLEN, pimg->fh); /* file format version */
184   pimg->version = (tolower(*tmpbuf) == 'b'); /* binary file iff B/b prefix */
[a420b49]185   /* knock off the 'B' or 'b' if it's there */
[23f7ea7]186   if (strcmp(tmpbuf + pimg->version, "v0.01") == 0) {
[5c3c61a]187      pimg->flags = 0;
[6c1c4f3]188   } else if (pimg->version == 0 && tmpbuf[0] == 'v') {
189      if (tmpbuf[1] < '2' || tmpbuf[1] > '3' || tmpbuf[2] != '\0') {
190         fclose(pimg->fh);
191         osfree(pimg);
192         img_errno = IMG_TOONEW;
193         return NULL;   
194      }
[d69255f]195      pimg->version = tmpbuf[1] - '0';
[5c3c61a]196   } else {
[a420b49]197      fclose(pimg->fh);
198      osfree(pimg);
[647407d]199      img_errno = IMG_BADFORMAT;
[a420b49]200      return NULL;
201   }
[58ad9da]202
[fe8e80e]203   getline((title_buf ? title_buf : tmpbuf), TMPBUFLEN, pimg->fh);
[95c3272]204   getline((date_buf ? date_buf : tmpbuf), TMPBUFLEN, pimg->fh);
[a420b49]205   pimg->fRead = fTrue; /* reading from this file */
206   img_errno = IMG_NONE;
[f2588ca]207   pimg->start = ftell(pimg->fh);
[d69255f]208
[5d7280f8]209   /* for version 3 we use label_buf to store the prefix for reuse */
[d69255f]210   pimg->label_len = 0;
211
[76bbb7c9]212   pimg->survey = NULL;
213   pimg->survey_len = 0;
214
215   if (survey) {
216      size_t len = strlen(survey);
217      if (len) {
218         if (survey[len - 1] == '.') len--;
219         if (len) {
220            pimg->survey = osmalloc(len + 2);
221            memcpy(pimg->survey, survey, len);
[58ad9da]222            /* Set title to leaf survey name */
223            if (title_buf) {
224               char *p;
225               pimg->survey[len] = '\0';
226               p = strchr(pimg->survey, '.');
227               if (p) p++; else p = pimg->survey;
228               strcpy(title_buf, p);
229            }
[76bbb7c9]230            pimg->survey[len] = '.';
231            pimg->survey[len + 1] = '\0';
232         }
233      }
234      pimg->survey_len = len;
235   }
236
237   /* [version 0] not in the middle of a 'LINE' command
238    * [version 3] not in the middle of turning a LINE into a MOVE */
239   pimg->pending = 0;
240
[a420b49]241   return pimg;
[d1b1380]242}
243
[f2588ca]244void
245img_rewind(img *pimg)
246{
247   fseek(pimg->fh, pimg->start, SEEK_SET);
[76bbb7c9]248
249   /* [version 0] not in the middle of a 'LINE' command
250    * [version 3] not in the middle of turning a LINE into a MOVE */
251   pimg->pending = 0;
[d69255f]252
253   img_errno = IMG_NONE;
[99cf51a]254
[5d7280f8]255   /* for version 3 we use label_buf to store the prefix for reuse */
[d69255f]256   pimg->label_len = 0;
[f2588ca]257}
258
[a420b49]259img *
[fe8e80e]260img_open_write(const char *fnm, char *title_buf, bool fBinary)
[a420b49]261{
262   time_t tm;
263   img *pimg;
[d1b1380]264
[d69255f]265   fBinary = fBinary;
266
[a420b49]267   if (fDirectory(fnm)) {
268      img_errno = IMG_DIRECTORY;
269      return NULL;
270   }
[d1b1380]271
[a420b49]272   pimg = (img *)xosmalloc(ossizeof(img));
273   if (pimg == NULL) {
274      img_errno = IMG_OUTOFMEMORY;
275      return NULL;
276   }
[d1b1380]277
[fe8e80e]278   pimg->buf_len = 257;
[0ff23cb]279   pimg->label_buf = xosmalloc(pimg->buf_len);
280   if (!pimg->label_buf) {
[fe8e80e]281      osfree(pimg);
282      img_errno = IMG_OUTOFMEMORY;
283      return NULL;
284   }
285
[a420b49]286   pimg->fh = fopen(fnm, "wb");
287   if (!pimg->fh) {
288      osfree(pimg);
289      img_errno = IMG_CANTOPENOUT;
290      return NULL;
291   }
[d1b1380]292
[a420b49]293   /* Output image file header */
294   fputs("Survex 3D Image File\n", pimg->fh); /* file identifier string */
[5c3c61a]295   if (img_output_version < 2) {
[d69255f]296      pimg->version = 1;
297      fputs("Bv0.01\n", pimg->fh); /* binary file format version number */
[5c3c61a]298   } else {
[d69255f]299      pimg->version = (img_output_version > 2) ? 3 : 2;
[5c3c61a]300      fprintf(pimg->fh, "v%d\n", pimg->version); /* file format version no. */
301   }
[fe8e80e]302   fputsnl(title_buf, pimg->fh);
[a420b49]303   tm = time(NULL);
304   if (tm == (time_t)-1) {
305      fputsnl(TIMENA, pimg->fh);
306   } else {
307      /* output current date and time in format specified */
[23f7ea7]308      strftime(tmpbuf, TMPBUFLEN, TIMEFMT, localtime(&tm));
309      fputsnl(tmpbuf, pimg->fh);
[a420b49]310   }
311   pimg->fRead = fFalse; /* writing to this file */
312   img_errno = IMG_NONE;
[d69255f]313
[5d7280f8]314   /* for version 3 we use label_buf to store the prefix for reuse */
[0ff23cb]315   pimg->label_buf[0] = '\0';
[d69255f]316   pimg->label_len = 0;
317
[ad9a5cd]318   /* Don't check for write errors now - let img_close() report them... */
[a420b49]319   return pimg;
[d1b1380]320}
321
[ad9a5cd]322static int
323read_coord(FILE *fh, img_point *pt)
324{
325   ASSERT(fh);
326   ASSERT(pt);
327   pt->x = get32(fh) / 100.0;
328   pt->y = get32(fh) / 100.0;
329   pt->z = get32(fh) / 100.0;
330   if (ferror(fh) || feof(fh)) {
331      img_errno = feof(fh) ? IMG_BADFORMAT : IMG_READERROR;
332      return 0;
333   }       
334   return 1;
335}
336
[a420b49]337int
[23f7ea7]338img_read_item(img *pimg, img_point *p)
[a420b49]339{
340   int result;
[95c3272]341   pimg->flags = 0;
[0ff23cb]342   pimg->label = pimg->label_buf;
[d69255f]343
344   if (pimg->version == 3) {
345      int opt;
[76bbb7c9]346      if (pimg->pending >= 0x80) {
347         *p = pimg->mv;
348         pimg->flags = (int)(pimg->pending) & 0x3f;
349         pimg->pending = 0;
[99cf51a]350         return img_LINE;
[76bbb7c9]351      }
[d69255f]352      again3: /* label to goto if we get a prefix */
353      opt = getc(pimg->fh);
[ad9a5cd]354      if (opt == EOF) {
355         img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
356         return img_BAD;
357      }
[d69255f]358      switch (opt >> 6) {
359       case 0:
360         if (opt == 0) {
361            if (!pimg->label_len) return img_STOP; /* end of data marker */
362            pimg->label_len = 0;
363            goto again3;
364         }
365         if (opt < 15) {
366            /* 1-14 mean trim that many levels from current prefix */
367            int c;
368            /* zero prefix using "0" */
369            if (pimg->label_len <= 16) {
370               img_errno = IMG_BADFORMAT;
371               return img_BAD;
372            }
373            c = pimg->label_len - 16;
374            opt &= 0x07;
[0ff23cb]375            while (pimg->label_buf[c] != '.' || --opt > 0) {
[d69255f]376               if (--c < 0) {
377                  /* zero prefix using "0" */
378                  img_errno = IMG_BADFORMAT;
379                  return img_BAD;
380               }
381            }
382            c++;
[0ff23cb]383            pimg->label_buf[c] = '\0';
[d69255f]384            pimg->label_len = c;
385            goto again3;
386         }
387         if (opt == 15) {
388            result = img_MOVE;
389            break;
390         }
391         /* 16-31 mean remove (n - 15) characters from the prefix */
392         pimg->label_len -= (opt - 15);
393         /* zero prefix using 0 */
394         if (pimg->label_len <= 0) {
395            img_errno = IMG_BADFORMAT;
396            return img_BAD;
397         }
398         goto again3;
399       case 1: case 2: {
400         char *q;
[ad9a5cd]401         long len = getc(pimg->fh);
402         if (len == EOF) {
403            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
404            return img_BAD;
405         }
[d69255f]406         if (len == 0xfe) {
407            len += get16(pimg->fh);
[ad9a5cd]408            if (feof(pimg->fh)) {
409               img_errno = IMG_BADFORMAT;
410               return img_BAD;
411            }
412            if (ferror(pimg->fh)) {
413               img_errno = IMG_READERROR;
414               return img_BAD;
415            }
[d69255f]416         } else if (len == 0xff) {
417            len = get32(pimg->fh);
[ad9a5cd]418            if (ferror(pimg->fh)) {
419               img_errno = IMG_READERROR;
420               return img_BAD;
421            }
422            if (feof(pimg->fh) || len < 0xfe + 0xffff) {
[d69255f]423               img_errno = IMG_BADFORMAT;
424               return img_BAD;
425            }
426         }
427
[0ff23cb]428         q = pimg->label_buf + pimg->label_len;
[d69255f]429         pimg->label_len += len;
430         if (pimg->label_len >= pimg->buf_len) {
[0ff23cb]431            pimg->label_buf = xosrealloc(pimg->label_buf, pimg->label_len + 1);
432            if (!pimg->label_buf) {
[d69255f]433               img_errno = IMG_OUTOFMEMORY;
434               return img_BAD;
435            }
436            pimg->buf_len = pimg->label_len + 1;
437         }
438         if (len && fread(q, len, 1, pimg->fh) != 1) {
[ad9a5cd]439            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]440            return img_BAD;
441         }
442         q[len] = '\0';
[76bbb7c9]443
444         result = opt & 0x40 ? img_LABEL : img_LINE;
445
446         if (pimg->survey_len) {
447            size_t l = pimg->survey_len;
[0ff23cb]448            const char *s = pimg->label_buf;
[76bbb7c9]449            if (result == img_LINE) {
450               if (strncmp(pimg->survey, s, l) != 0 ||
451                   !(s[l] == '.' || s[l] == '\0')) {
[ad9a5cd]452                  if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;                   
[76bbb7c9]453                  pimg->pending = 15;
454                  goto again3;
455               }
456            } else {
457               if (strncmp(pimg->survey, s, l + 1) != 0) {
458                  fseek(pimg->fh, 12, SEEK_CUR);
459                  goto again3;
460               }
461            }
[0ff23cb]462            pimg->label += l;
463            /* skip the dot if there */
464            if (*pimg->label) pimg->label++;
[76bbb7c9]465         }
466
467         if (result == img_LINE && pimg->pending) {
468            *p = pimg->mv;
[ad9a5cd]469            if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
[76bbb7c9]470            pimg->pending = opt;
471            return img_MOVE;
472         }
473         pimg->flags = (int)opt & 0x3f;
[d69255f]474         break;
475       }
476       default:
477         img_errno = IMG_BADFORMAT;
478         return img_BAD;
479      }
[ad9a5cd]480      if (!read_coord(pimg->fh, p)) return img_BAD;
[76bbb7c9]481      pimg->pending = 0;
[d69255f]482      return result;
483   } else if (pimg->version > 0) {
484      static long opt_lookahead = 0;
[ad9a5cd]485      static img_point pt = { 0.0, 0.0, 0.0 };
[a420b49]486      long opt;
487      again: /* label to goto if we get a cross */
[5d7280f8]488      pimg->label[0] = '\0';
[ad9a5cd]489
[5c3c61a]490      if (pimg->version == 1) {
[c4d4649]491         if (opt_lookahead) {
492            opt = opt_lookahead;
493            opt_lookahead = 0;
494         } else {
495            opt = get32(pimg->fh);
496         }
[5c3c61a]497      } else {
498         opt = getc(pimg->fh);
499      }
[ad9a5cd]500
501      if (feof(pimg->fh)) {
502         img_errno = IMG_BADFORMAT;
503         return img_BAD;
504      }
505      if (ferror(pimg->fh)) {
506         img_errno = IMG_READERROR;
507         return img_BAD;
508      }
509
[a420b49]510      switch (opt) {
[437caf3]511       case -1: case 0:
[a420b49]512         return img_STOP; /* end of data marker */
513       case 1:
[ad9a5cd]514         /* skip coordinates */
515         if (fseek(pimg->fh, 12, SEEK_CUR) == -1) {
516            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
517            return img_BAD;
518         }
[a420b49]519         goto again;
[23f7ea7]520       case 2: case 3: {
[fe8e80e]521         char *q;
[3a1f8da]522         int ch;
[437caf3]523         result = img_LABEL;
[3a1f8da]524         ch = getc(pimg->fh);
[d69255f]525         if (ch == EOF) {
[ad9a5cd]526            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]527            return img_BAD;
528         }
[3a1f8da]529         if (ch != '\\') ungetc(ch, pimg->fh);
[0ff23cb]530         fgets(pimg->label_buf, 257, pimg->fh);
[ad9a5cd]531         if (feof(pimg->fh)) {
532            img_errno = IMG_BADFORMAT;
533            return img_BAD;
534         }
535         if (ferror(pimg->fh)) {
536            img_errno = IMG_READERROR;
537            return img_BAD;
538         }
[0ff23cb]539         q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[d69255f]540         if (*q != '\n') {
541            img_errno = IMG_BADFORMAT;
542            return img_BAD;
543         }
[9968ebf]544         /* Ignore empty labels in some .3d files (caused by a bug) */
[0ff23cb]545         if (q == pimg->label_buf) goto again;
[fe8e80e]546         *q = '\0';
[509e099]547         pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[437caf3]548         if (opt == 2) goto done;
549         break;
[23f7ea7]550       }
[95c3272]551       case 6: case 7: {
[ad9a5cd]552         long len;
[23f7ea7]553         result = img_LABEL;
[ad9a5cd]554
[509e099]555         if (opt == 7)
556            pimg->flags = getc(pimg->fh);
557         else
558            pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[ad9a5cd]559
[23f7ea7]560         len = get32(pimg->fh);
[ad9a5cd]561
562         if (feof(pimg->fh)) {
563            img_errno = IMG_BADFORMAT;
564            return img_BAD;
565         }
566         if (ferror(pimg->fh)) {
567            img_errno = IMG_READERROR;
568            return img_BAD;
569         }
570
[9968ebf]571         /* Ignore empty labels in some .3d files (caused by a bug) */
572         if (len == 0) goto again;
[23f7ea7]573         if (len >= pimg->buf_len) {
[0ff23cb]574            pimg->label_buf = xosrealloc(pimg->label_buf, len + 1);
575            if (!pimg->label_buf) {
[23f7ea7]576               img_errno = IMG_OUTOFMEMORY;
577               return img_BAD;
578            }
579            pimg->buf_len = len + 1;
580         }
[0ff23cb]581         if (fread(pimg->label_buf, len, 1, pimg->fh) != 1) {
[ad9a5cd]582            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]583            return img_BAD;
584         }
[23f7ea7]585         break;
586       }
[a420b49]587       case 4:
588         result = img_MOVE;
589         break;
590       case 5:
591         result = img_LINE;
592         break;
593       default:
[95c3272]594         switch ((int)opt & 0xc0) {
595          case 0x80:
596            pimg->flags = (int)opt & 0x3f;
597            result = img_LINE;
598            break;
599          case 0x40: {
600            char *q;
601            pimg->flags = (int)opt & 0x3f;
602            result = img_LABEL;
[0ff23cb]603            if (!fgets(pimg->label_buf, 257, pimg->fh)) {
[ad9a5cd]604               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]605               return img_BAD;
606            }
[0ff23cb]607            q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[9968ebf]608            /* Ignore empty-labels in some .3d files (caused by a bug) */
[0ff23cb]609            if (q == pimg->label_buf) goto again;
[d69255f]610            if (*q != '\n') {
611               img_errno = IMG_BADFORMAT;
612               return img_BAD;
613            }
[95c3272]614            *q = '\0';
615            break;
616          }
617          case 0xc0:
618            /* use this for an extra leg or station flag if we need it */
619          default:
[d69255f]620            img_errno = IMG_BADFORMAT;
[95c3272]621            return img_BAD;
622         }
[437caf3]623         break;
[a420b49]624      }
[ad9a5cd]625
626      if (!read_coord(pimg->fh, &pt)) return img_BAD;
[76bbb7c9]627
[ed0f5b6]628      if (result == img_LABEL && pimg->survey_len) {
629         if (strncmp(pimg->label_buf, pimg->survey, pimg->survey_len + 1) != 0)
[0ff23cb]630            goto again;
631         pimg->label += pimg->survey_len + 1;
632      }
[76bbb7c9]633
[a420b49]634      done:
[ad9a5cd]635      *p = pt;
[c4d4649]636
637      if (result == img_MOVE && pimg->version == 1) {
[d69255f]638         /* peek at next code and see if it's an old-style label */
[23f7ea7]639         opt_lookahead = get32(pimg->fh);
[ad9a5cd]640
641         if (feof(pimg->fh)) {
642            img_errno = IMG_BADFORMAT;
643            return img_BAD;
644         }
645         if (ferror(pimg->fh)) {
646            img_errno = IMG_READERROR;
647            return img_BAD;
648         }
649
[d69255f]650         if (opt_lookahead == 2) return img_read_item(pimg, p);
[c4d4649]651      }
[23f7ea7]652
[a420b49]653      return result;
654   } else {
655      ascii_again:
[5d7280f8]656      pimg->label[0] = '\0';
[a420b49]657      if (feof(pimg->fh)) return img_STOP;
[76bbb7c9]658      if (pimg->pending) {
659         pimg->pending = 0;
[a420b49]660         result = img_LINE;
661      } else {
662         /* Stop if nothing found */
[23f7ea7]663         if (fscanf(pimg->fh, "%s", tmpbuf) < 1) return img_STOP;
664         if (strcmp(tmpbuf, "move") == 0)
[a420b49]665            result = img_MOVE;
[23f7ea7]666         else if (strcmp(tmpbuf, "draw") == 0)
[a420b49]667            result = img_LINE;
[23f7ea7]668         else if (strcmp(tmpbuf, "line") == 0) {
[bd1913f]669            /* set flag to indicate to process second triplet as LINE */
[76bbb7c9]670            pimg->pending = 1;
[a420b49]671            result = img_MOVE;
[23f7ea7]672         } else if (strcmp(tmpbuf, "cross") == 0) {
[d69255f]673            if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]674               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[0ed0e16]675               return img_BAD;
[d69255f]676            }
[a420b49]677            goto ascii_again;
[23f7ea7]678         } else if (strcmp(tmpbuf, "name") == 0) {
[3a1f8da]679            int ch;
680            ch = getc(pimg->fh);
[d69255f]681            if (ch == EOF) {
[ad9a5cd]682               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]683               return img_BAD;
684            }
[ad9a5cd]685            if (ch != '\\') {
686               if (ungetc(ch, pimg->fh) == EOF) {
687                  img_errno = IMG_READERROR;
688                  return img_BAD;
689               }
690            }
691            if (fscanf(pimg->fh, "%256s", pimg->label_buf) < 1) {
692               img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
693               return img_BAD;
694            }
695            if (strlen(pimg->label_buf) == 256) {
[d69255f]696               img_errno = IMG_BADFORMAT;
[4ee5fbf]697               return img_BAD;
698            }
[a420b49]699            result = img_LABEL;
[d69255f]700         } else {
701            img_errno = IMG_BADFORMAT;
[a420b49]702            return img_BAD; /* unknown keyword */
[d69255f]703         }
[a420b49]704      }
[d1b1380]705
[d69255f]706      if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]707         img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
[fe8e80e]708         return img_BAD;
[d69255f]709      }
710
[0ff23cb]711      if (result == img_LABEL) {
712         if (pimg->survey_len &&
713          (strncmp(pimg->label_buf, pimg->survey, pimg->survey_len + 1) != 0))
714            goto ascii_again;
715         pimg->label += pimg->survey_len + 1;
716      }
[76bbb7c9]717
[a420b49]718      return result;
719   }
[d1b1380]720}
721
[ad9a5cd]722static int
[d69255f]723write_v3label(img *pimg, int opt, const char *s)
724{
725   size_t len, n, dot;
726
727   /* find length of common prefix */
728   dot = 0;
[0ff23cb]729   for (len = 0; s[len] == pimg->label_buf[len] && s[len] != '\0'; len++) {
[d69255f]730      if (s[len] == '.') dot = len + 1;
731   }
732
733   ASSERT(len <= pimg->label_len);
734   n = pimg->label_len - len;
735   if (len == 0) {
736      if (pimg->label_len) putc(0, pimg->fh);
737   } else if (n <= 16) {
738      if (n) putc(n + 15, pimg->fh);
739   } else if (dot == 0) {
740      if (pimg->label_len) putc(0, pimg->fh);
[99cf51a]741      len = 0;
[d69255f]742   } else {
[0ff23cb]743      const char *p = pimg->label_buf + dot;
[d69255f]744      n = 1;
745      for (len = pimg->label_len - dot - 17; len; len--) {
746         if (*p++ == '.') n++;
747      }
748      if (n <= 14) {
749         putc(n, pimg->fh);
750         len = dot;
751      } else {
752         if (pimg->label_len) putc(0, pimg->fh);
753         len = 0;
754      }
755   }
756
757   n = strlen(s + len);
758   putc(opt, pimg->fh);
759   if (n < 0xfe) {
760      putc(n, pimg->fh);
761   } else if (n < 0xffff + 0xfe) {
762      putc(0xfe, pimg->fh);
763      put16(n - 0xfe, pimg->fh);
764   } else {
765      putc(0xff, pimg->fh);
766      put32(n, pimg->fh);
767   }
768   fwrite(s + len, n, 1, pimg->fh);
769
770   n += len;
771   pimg->label_len = n;
772   if (n >= pimg->buf_len) {
[0ff23cb]773      char *p = xosrealloc(pimg->label_buf, n + 1);
[ad9a5cd]774      if (!p) return 0; /* FIXME: distinguish out of memory... */
775      pimg->label_buf = p;
776      pimg->buf_len = n + 1;
[d69255f]777   }
[0ff23cb]778   memcpy(pimg->label_buf + len, s + len, n - len + 1);
[ad9a5cd]779
780   return !ferror(pimg->fh);
[d69255f]781}
782
[a420b49]783void
[95c3272]784img_write_item(img *pimg, int code, int flags, const char *s,
[a9f5117]785               double x, double y, double z)
[a420b49]786{
[647407d]787   if (!pimg) return;
[d69255f]788   if (pimg->version == 3) {
789      int opt = 0;
790      switch (code) {
791       case img_LABEL:
792         write_v3label(pimg, 0x40 | flags, s);
793         opt = 0;
794         break;
795       case img_MOVE:
796         opt = 15;
797         break;
798       case img_LINE:
799         write_v3label(pimg, 0x80 | flags, s ? s : "");
800         opt = 0;
801         break;
802       default: /* ignore for now */
803         return;
804      }
805      if (opt) putc(opt, pimg->fh);
806      /* Output in cm */
807      put32((INT32_T)(x * 100.0), pimg->fh);
808      put32((INT32_T)(y * 100.0), pimg->fh);
809      put32((INT32_T)(z * 100.0), pimg->fh);
810   } else {
[23f7ea7]811      size_t len;
[badeec8]812      INT32_T opt = 0;
[d69255f]813      ASSERT(pimg->version > 0);
[a420b49]814      switch (code) {
[437caf3]815       case img_LABEL:
816         if (pimg->version == 1) {
817            /* put a move before each label */
[95c3272]818            img_write_item(pimg, img_MOVE, 0, NULL, x, y, z);
[437caf3]819            put32(2, pimg->fh);
[0ed0e16]820            fputsnl(s, pimg->fh);
[437caf3]821            return;
822         }
[23f7ea7]823         len = strlen(s);
[af56069]824         if (len > 255 || strchr(s, '\n')) {
[23f7ea7]825            /* long label - not in early incarnations of v2 format, but few
826             * 3d files will need these, so better not to force incompatibility
827             * with a new version I think... */
[95c3272]828            putc(7, pimg->fh);
829            putc(flags, pimg->fh);
[23f7ea7]830            put32(len, pimg->fh);
831            fputs(s, pimg->fh);
832         } else {
[95c3272]833            putc(0x40 | (flags & 0x3f), pimg->fh);
[23f7ea7]834            fputsnl(s, pimg->fh);
835         }
[437caf3]836         opt = 0;
[23f7ea7]837         break;
[a420b49]838       case img_MOVE:
839         opt = 4;
840         break;
841       case img_LINE:
[5c3c61a]842         if (pimg->version > 1) {
[d69255f]843            opt = 0x80 | (flags & 0x3f);
[437caf3]844            break;
[5c3c61a]845         }
[437caf3]846         opt = 5;
[a420b49]847         break;
[437caf3]848       default: /* ignore for now */
849         return;
[a420b49]850      }
[437caf3]851      if (pimg->version == 1) {
852         put32(opt, pimg->fh);
853      } else {
854         if (opt) putc(opt, pimg->fh);
[a420b49]855      }
[d69255f]856      /* Output in cm */
857      put32((INT32_T)(x * 100.0), pimg->fh);
858      put32((INT32_T)(y * 100.0), pimg->fh);
859      put32((INT32_T)(z * 100.0), pimg->fh);
[a420b49]860   }
[d1b1380]861}
862
[ad9a5cd]863int
[a420b49]864img_close(img *pimg)
865{
[ad9a5cd]866   int result = 1;
[dbb4e19]867   if (pimg) {
868      if (pimg->fh) {
[76bbb7c9]869         if (pimg->fRead) {
870            osfree(pimg->survey);
871         } else {
872            /* write end of data marker */
[d69255f]873            switch (pimg->version) {
874             case 1:
[5c3c61a]875               put32((INT32_T)-1, pimg->fh);
[d69255f]876               break;
877             case 2:
878               putc(0, pimg->fh);
879               break;
880             case 3:
881               if (pimg->label_len) putc(0, pimg->fh);
[437caf3]882               putc(0, pimg->fh);
[d69255f]883               break;
[5c3c61a]884            }
885         }
[ad9a5cd]886         if (ferror(pimg->fh)) result = 0;
887         if (fclose(pimg->fh)) result = 0;
888         img_errno = pimg->fRead ? IMG_READERROR : IMG_WRITEERROR;
[dbb4e19]889      }
[0ff23cb]890      osfree(pimg->label_buf);
[dbb4e19]891      osfree(pimg);
[a420b49]892   }
[ad9a5cd]893   return result;
[d1b1380]894}
Note: See TracBrowser for help on using the repository browser.