static char * getline_alloc(FILE *fh) { int ch; size_t i = 0; size_t len = 16; char *buf = xosmalloc(len); if (!buf) return NULL; ch = getc(fh); while (ch != '\n' && ch != '\r' && ch != EOF) { buf[i++] = ch; if (i == len - 1) { char *p; len += len; p = xosrealloc(buf, len); if (!p) { osfree(buf); return NULL; } buf = p; } ch = getc(fh); } if (ch == '\n' || ch == '\r') { int otherone = ch ^ ('\n' ^ '\r'); ch = getc(fh); /* if it's not the other eol character, put it back */ if (ch != otherone) ungetc(ch, fh); } buf[i++] = '\0'; return buf; }
static char * my_strdup(const char *str) { char *p; size_t len = strlen(str) + 1; p = xosmalloc(len); if (p) memcpy(p, str, len); return p; }
/* malloc with error catching if it fails. Also allows us to write special * versions easily eg for MS Windows. */ void * osmalloc(OSSIZE_T size) { void *p; #ifdef TOMBSTONES size += TOMBSTONE_SIZE * 2; p = malloc(size); #else p = xosmalloc(size); #endif if (p == NULL) outofmem(size); #ifdef TOMBSTONES printf("osmalloc truep=%p truesize=%d\n", p, size); memcpy(p, tombstone, TOMBSTONE_SIZE); memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE); *(size_t *)p = size; p += TOMBSTONE_SIZE; #endif return p; }
static char * baseleaf_from_fnm(const char *fnm) { const char *p; char *q; size_t len; p = fnm; q = strrchr(p, '/'); if (q) p = q + 1; q = strrchr(p, '\\'); if (q) p = q + 1; q = strrchr(p, FNM_SEP_EXT); if (q) len = (const char *)q - p; else len = strlen(p); q = xosmalloc(len + 1); if (!q) return NULL; memcpy(q, p, len); q[len] = '\0'; return q; }
/* realloc with error catching if it fails. */ void * osrealloc(void *p, OSSIZE_T size) { /* some pre-ANSI realloc implementations don't cope with a NULL pointer */ if (p == NULL) { p = xosmalloc(size); } else { #ifdef TOMBSTONES int true_size; size += TOMBSTONE_SIZE * 2; p -= TOMBSTONE_SIZE; true_size = *(size_t *)p; printf("osrealloc (in truep=%p truesize=%d)\n", p, true_size); if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t), TOMBSTONE_SIZE - sizeof(size_t)) != 0) { printf("start tombstone for block %p, size %d corrupted!", p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2); } if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE) != 0) { printf("end tombstone for block %p, size %d corrupted!", p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2); } p = realloc(p, size); if (p == NULL) outofmem(size); printf("osrealloc truep=%p truesize=%d\n", p, size); memcpy(p, tombstone, TOMBSTONE_SIZE); memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE); *(size_t *)p = size; p += TOMBSTONE_SIZE; #else p = xosrealloc(p, size); #endif } if (p == NULL) outofmem(size); return p; }
img * img_open_write(const char *fnm, char *title_buf, bool fBinary) { time_t tm; img *pimg; fBinary = fBinary; if (fDirectory(fnm)) { img_errno = IMG_DIRECTORY; return NULL; } pimg = (img *)xosmalloc(ossizeof(img)); if (pimg == NULL) { img_errno = IMG_OUTOFMEMORY; return NULL; } pimg->buf_len = 257; pimg->label_buf = xosmalloc(pimg->buf_len); if (!pimg->label_buf) { osfree(pimg); img_errno = IMG_OUTOFMEMORY; return NULL; } pimg->fh = fopen(fnm, "wb"); if (!pimg->fh) { osfree(pimg->label_buf); osfree(pimg); img_errno = IMG_CANTOPENOUT; return NULL; } /* Output image file header */ fputs("Survex 3D Image File\n", pimg->fh); /* file identifier string */ if (img_output_version < 2) { pimg->version = 1; fputs("Bv0.01\n", pimg->fh); /* binary file format version number */ } else { pimg->version = (img_output_version > LATEST_IMG_VERSION) ? LATEST_IMG_VERSION : img_output_version; fprintf(pimg->fh, "v%d\n", pimg->version); /* file format version no. */ } fputsnl(title_buf, pimg->fh); tm = time(NULL); if (tm == (time_t)-1) { fputsnl(TIMENA, pimg->fh); } else { char date[256]; /* output current date and time in format specified */ strftime(date, 256, TIMEFMT, localtime(&tm)); fputsnl(date, pimg->fh); } #if 0 if (img_output_version >= 5) { static const unsigned char codelengths[32] = { 4, 8, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; fwrite(codelengths, 32, 1, pimg->fh); } #endif pimg->fRead = fFalse; /* writing to this file */ img_errno = IMG_NONE; /* for version >= 3 we use label_buf to store the prefix for reuse */ pimg->label_buf[0] = '\0'; pimg->label_len = 0; pimg->date1 = 0; pimg->date2 = 0; pimg->olddate1 = 0; pimg->olddate2 = 0; pimg->l = pimg->r = pimg->u = pimg->d = -1.0; pimg->n_legs = 0; pimg->length = 0.0; pimg->E = pimg->H = pimg->V = 0.0; /* Don't check for write errors now - let img_close() report them... */ return pimg; }
img * img_open_survey(const char *fnm, const char *survey) { img *pimg; size_t len; char buf[LITLEN(FILEID) + 9]; int ch; if (fDirectory(fnm)) { img_errno = IMG_DIRECTORY; return NULL; } pimg = (img *)xosmalloc(ossizeof(img)); if (pimg == NULL) { img_errno = IMG_OUTOFMEMORY; return NULL; } pimg->buf_len = 257; pimg->label_buf = xosmalloc(pimg->buf_len); if (!pimg->label_buf) { osfree(pimg); img_errno = IMG_OUTOFMEMORY; return NULL; } pimg->fh = fopenWithPthAndExt("", fnm, EXT_SVX_3D, "rb", &(pimg->filename_opened)); if (pimg->fh == NULL) { osfree(pimg->label_buf); osfree(pimg); img_errno = IMG_FILENOTFOUND; return NULL; } pimg->fRead = fTrue; /* reading from this file */ img_errno = IMG_NONE; pimg->flags = 0; /* for version >= 3 we use label_buf to store the prefix for reuse */ /* for VERSION_COMPASS_PLT, 0 value indicates we haven't * entered a survey yet */ /* for VERSION_CMAP_SHOT, we store the last station here * to detect whether we MOVE or LINE */ pimg->label_len = 0; pimg->label_buf[0] = '\0'; pimg->survey = NULL; pimg->survey_len = 0; pimg->separator = '.'; pimg->date1 = 0; pimg->date2 = 0; pimg->is_extended_elevation = 0; pimg->l = pimg->r = pimg->u = pimg->d = -1.0; pimg->title = pimg->datestamp = NULL; if (survey) { len = strlen(survey); if (len) { if (survey[len - 1] == '.') len--; if (len) { char *p; pimg->survey = xosmalloc(len + 2); if (!pimg->survey) { img_errno = IMG_OUTOFMEMORY; goto error; } memcpy(pimg->survey, survey, len); /* Set title to leaf survey name */ pimg->survey[len] = '\0'; p = strchr(pimg->survey, '.'); if (p) p++; else p = pimg->survey; pimg->title = my_strdup(p); if (!pimg->title) { img_errno = IMG_OUTOFMEMORY; goto error; } pimg->survey[len] = '.'; pimg->survey[len + 1] = '\0'; } } pimg->survey_len = len; } /* [VERSION_COMPASS_PLT, VERSION_CMAP_STATION, VERSION_CMAP_SHOT] pending * IMG_LINE or IMG_MOVE - both have 4 added. * [VERSION_SURVEX_POS] already skipped heading line, or there wasn't one * [version 0] not in the middle of a 'LINE' command * [version >= 3] not in the middle of turning a LINE into a MOVE */ pimg->pending = 0; len = strlen(fnm); if (has_ext(fnm, len, EXT_SVX_POS)) { pos_file: pimg->version = VERSION_SURVEX_POS; if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm); pimg->datestamp = my_strdup(TIMENA); if (!pimg->datestamp) { img_errno = IMG_OUTOFMEMORY; goto error; } pimg->start = 0; return pimg; } if (has_ext(fnm, len, EXT_PLT) || has_ext(fnm, len, EXT_PLF)) { long fpos; plt_file: pimg->version = VERSION_COMPASS_PLT; /* Spaces aren't legal in Compass station names, but dots are, so * use space as the level separator */ pimg->separator = ' '; pimg->start = 0; if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm); pimg->datestamp = my_strdup(TIMENA); if (!pimg->datestamp) { img_errno = IMG_OUTOFMEMORY; goto error; } while (1) { ch = getc(pimg->fh); switch (ch) { case '\x1a': fseek(pimg->fh, -1, SEEK_CUR); /* FALL THRU */ case EOF: pimg->start = ftell(pimg->fh); return pimg; case 'N': { char *line, *q; fpos = ftell(pimg->fh) - 1; if (!pimg->survey) { /* FIXME : if there's only one survey in the file, it'd be nice * to use its description as the title here... */ ungetc('N', pimg->fh); pimg->start = fpos; return pimg; } line = getline_alloc(pimg->fh); if (!line) { img_errno = IMG_OUTOFMEMORY; goto error; } len = 0; while (line[len] > 32) ++len; if (pimg->survey_len != len || memcmp(line, pimg->survey, len) != 0) { osfree(line); continue; } q = strchr(line + len, 'C'); if (q && q[1]) { osfree(pimg->title); pimg->title = my_strdup(q + 1); } else if (!pimg->title) { pimg->title = my_strdup(pimg->label); } osfree(line); if (!pimg->title) { img_errno = IMG_OUTOFMEMORY; goto error; } if (!pimg->start) pimg->start = fpos; fseek(pimg->fh, pimg->start, SEEK_SET); return pimg; } case 'M': case 'D': pimg->start = ftell(pimg->fh) - 1; break; } while (ch != '\n' && ch != '\r') { ch = getc(pimg->fh); } } } if (has_ext(fnm, len, EXT_XYZ)) { char *line; xyz_file: /* Spaces aren't legal in CMAP station names, but dots are, so * use space as the level separator. */ pimg->separator = ' '; line = getline_alloc(pimg->fh); if (!line) { img_errno = IMG_OUTOFMEMORY; goto error; } /* FIXME: reparse date? */ len = strlen(line); if (len > 59) line[59] = '\0'; if (len > 45) { pimg->datestamp = my_strdup(line + 45); } else { pimg->datestamp = my_strdup(TIMENA); } if (strncmp(line, " Cave Survey Data Processed by CMAP ", LITLEN(" Cave Survey Data Processed by CMAP ")) == 0) { len = 0; } else { if (len > 45) { line[45] = '\0'; len = 45; } while (len > 2 && line[len - 1] == ' ') --len; if (len > 2) { line[len] = '\0'; pimg->title = my_strdup(line + 2); } } if (len <= 2) pimg->title = baseleaf_from_fnm(fnm); osfree(line); if (!pimg->datestamp || !pimg->title) { img_errno = IMG_OUTOFMEMORY; goto error; } line = getline_alloc(pimg->fh); if (!line) { img_errno = IMG_OUTOFMEMORY; goto error; } if (line[0] != ' ' || (line[1] != 'S' && line[1] != 'O')) { img_errno = IMG_BADFORMAT; goto error; } if (line[1] == 'S') { pimg->version = VERSION_CMAP_STATION; } else { pimg->version = VERSION_CMAP_SHOT; } osfree(line); line = getline_alloc(pimg->fh); if (!line) { img_errno = IMG_OUTOFMEMORY; goto error; } if (line[0] != ' ' || line[1] != '-') { img_errno = IMG_BADFORMAT; goto error; } osfree(line); pimg->start = ftell(pimg->fh); return pimg; } if (fread(buf, LITLEN(FILEID) + 1, 1, pimg->fh) != 1 || memcmp(buf, FILEID"\n", LITLEN(FILEID) + 1) != 0) { if (fread(buf + LITLEN(FILEID) + 1, 8, 1, pimg->fh) == 1 && memcmp(buf, FILEID"\r\nv0.01\r\n", LITLEN(FILEID) + 9) == 0) { /* v0 3d file with DOS EOLs */ pimg->version = 0; goto v03d; } rewind(pimg->fh); if (buf[1] == ' ') { if (buf[0] == ' ') { /* Looks like a CMAP .xyz file ... */ goto xyz_file; } else if (strchr("ZSNF", buf[0])) { /* Looks like a Compass .plt file ... */ /* Almost certainly it'll start "Z " */ goto plt_file; } } if (buf[0] == '(') { /* Looks like a Survex .pos file ... */ goto pos_file; } img_errno = IMG_BADFORMAT; goto error; } /* check file format version */ ch = getc(pimg->fh); pimg->version = 0; if (tolower(ch) == 'b') { /* binary file iff B/b prefix */ pimg->version = 1; ch = getc(pimg->fh); } if (ch != 'v') { img_errno = IMG_BADFORMAT; goto error; } ch = getc(pimg->fh); if (ch == '0') { if (fread(buf, 4, 1, pimg->fh) != 1 || memcmp(buf, ".01\n", 4) != 0) { img_errno = IMG_BADFORMAT; goto error; } /* nothing special to do */ } else if (pimg->version == 0) { if (ch < '2' || ch > '0' + LATEST_IMG_VERSION || getc(pimg->fh) != '\n') { img_errno = IMG_TOONEW; goto error; } pimg->version = ch - '0'; } else { img_errno = IMG_BADFORMAT; goto error; } v03d: if (!pimg->title) pimg->title = getline_alloc(pimg->fh); else osfree(getline_alloc(pimg->fh)); pimg->datestamp = getline_alloc(pimg->fh); if (!pimg->title || !pimg->datestamp) { img_errno = IMG_OUTOFMEMORY; error: osfree(pimg->title); osfree(pimg->datestamp); fclose(pimg->fh); osfree(pimg); return NULL; } pimg->start = ftell(pimg->fh); len = strlen(pimg->title); if (len > 11 && strcmp(pimg->title + len - 11, " (extended)") == 0) { pimg->title[len - 11] = '\0'; pimg->is_extended_elevation = 1; } return pimg; }