source: git/src/img.c @ 9baddd7

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 9baddd7 was 5d7280f8, checked in by Olly Betts <olly@…>, 24 years ago

Fixed typos.

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

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