source: git/src/img.c @ 6de36f9

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 6de36f9 was ad9a5cd, checked in by Olly Betts <olly@…>, 24 years ago

check for errors reading and writing files

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

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