/* ** _nrrdKeyValueWrite ** ** writes a given key and value to a file, starting with the given ** prefix (if non-NULL), and ending with "\n" */ int _nrrdKeyValueWrite(FILE *file, char **stringP, const char *prefix, const char *key, const char *value) { if (!( (file || stringP) && key && value )) { return 1; } if (stringP) { /* 2*strlen() because at worst all characters will be escaped */ *stringP = AIR_CALLOC(airStrlen(prefix) + 2*airStrlen(key) + strlen(":=") + 2*airStrlen(value) + strlen("\n") + 1, char); /* HEY error checking? */ } if (prefix) { if (file) { fprintf(file, "%s", prefix); } else { strcat(*stringP, prefix); } } if (file) { _nrrdWriteEscaped(file, NULL, key, "\n\\", _NRRD_WHITESPACE_NOTAB); fprintf(file, ":="); _nrrdWriteEscaped(file, NULL, value, "\n\\", _NRRD_WHITESPACE_NOTAB); fprintf(file, "\n"); } else { _nrrdWriteEscaped(NULL, *stringP, key, "\n\\", _NRRD_WHITESPACE_NOTAB); strcat(*stringP, ":="); _nrrdWriteEscaped(NULL, *stringP, value, "\n\\", _NRRD_WHITESPACE_NOTAB); strcat(*stringP, "\n"); } return 0; }
/* ** _nrrdKeyValueWrite ** ** writes a given key and value to a file, starting with the given ** prefix (if non-NULL), and ending with "\n" */ int _nrrdKeyValueWrite(FILE *file, char **stringP, const char *prefix, const char *key, const char *value) { if (!( (file || stringP) && key && value )) { return 1; } if (stringP) { /* 2*strlen() because at worst all characters will be escaped */ *stringP = (char *)malloc(airStrlen(prefix) + 2*airStrlen(key) + strlen(":=") + 2*airStrlen(value) + strlen("\n") + 1); /* HEY error checking */ strcpy(*stringP, ""); } if (prefix) { if (file) { fprintf(file, "%s", prefix); } else { strcat(*stringP, prefix); } } if (file) { _nrrdWriteEscaped(file, NULL, key); fprintf(file, ":="); _nrrdWriteEscaped(file, NULL, value); fprintf(file, "\n"); } else { _nrrdWriteEscaped(NULL, *stringP, key); strcat(*stringP, ":="); _nrrdWriteEscaped(NULL, *stringP, value); strcat(*stringP, "\n"); } return 0; }
/* ** _nrrdSprintFieldInfo ** ** this prints "<prefix><field>: <info>" into *strP (after allocating it for ** big enough, usually with a stupidly big margin of error), in a form ** suitable to be written to NRRD or other image headers. This will always ** print something (for valid inputs), even stupid <info>s like ** "(unknown endian)". It is up to the caller to decide which fields ** are worth writing, via _nrrdFieldInteresting(). ** ** NOTE: some of these fields make sense in non-NRRD files (e.g. all ** the per-axis information), but many only make sense in NRRD files. ** This is just one example of NRRD-format-specific stuff that is not ** in formatNRRD.c */ void _nrrdSprintFieldInfo(char **strP, const char *prefix, const Nrrd *nrrd, NrrdIoState *nio, int field) { static const char me[]="_nrrdSprintFieldInfo"; char buff[AIR_STRLEN_MED], *fnb, stmp[AIR_STRLEN_SMALL], *strtmp=NULL; double colvec[NRRD_SPACE_DIM_MAX]; const char *fs; unsigned int ii, dd, uintStrlen = 11, size_tStrlen = 33, doubleStrlen = 513; size_t fslen, fdlen, maxl; int endi; if (!( strP && prefix && nrrd && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX) && AIR_IN_OP(nrrdField_unknown, field, nrrdField_last) )) { return; } /* As of Sun Dec 2 01:57:48 CST 2012 (revision 5832) the only places where this function is called is when it has been guarded by "if (_nrrdFieldInteresting())" (except for in formatText.c when its called on the dimension field, which is always interesting). So, the following: if (!_nrrdFieldInteresting(nrrd, nio, field)) { *strP = airStrdup(""); } was redundant and confusingly created the appearance of a memory leak waiting to happen. We now let the default switch statement set *strP to NULL (all the other cases set it), to smoke out errors in how this function is called */ fs = airEnumStr(nrrdField, field); fslen = strlen(prefix) + strlen(fs) + strlen(": ") + 1; switch (field) { case nrrdField_comment: case nrrdField_keyvalue: fprintf(stderr, "%s: CONFUSION: why are you calling me on \"%s\"?\n", me, airEnumStr(nrrdField, nrrdField_comment)); *strP = airStrdup(""); break; case nrrdField_content: strtmp = airOneLinify(airStrdup(nrrd->content)); *strP = AIR_CALLOC(fslen + strlen(strtmp), char); sprintf(*strP, "%s%s: %s", prefix, fs, strtmp); airFree(strtmp); strtmp = NULL; break; case nrrdField_number: *strP = AIR_CALLOC(fslen + size_tStrlen, char); sprintf(*strP, "%s%s: %s", prefix, fs, airSprintSize_t(stmp, nrrdElementNumber(nrrd))); break; case nrrdField_type: *strP = AIR_CALLOC(fslen + strlen(airEnumStr(nrrdType, nrrd->type)), char); sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdType, nrrd->type)); break; case nrrdField_block_size: *strP = AIR_CALLOC(fslen + size_tStrlen, char); sprintf(*strP, "%s%s: %s", prefix, fs, airSprintSize_t(stmp, nrrd->blockSize)); break; case nrrdField_dimension: *strP = AIR_CALLOC(fslen + uintStrlen, char); sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->dim); break; case nrrdField_space: *strP = AIR_CALLOC(fslen + strlen(airEnumStr(nrrdSpace, nrrd->space)), char); sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdSpace, nrrd->space)); break; case nrrdField_space_dimension: *strP = AIR_CALLOC(fslen + uintStrlen, char); sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->spaceDim); break; /* ---- begin per-axis fields ---- */ case nrrdField_sizes: *strP = AIR_CALLOC(fslen + nrrd->dim*(size_tStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { sprintf(buff, " %s", airSprintSize_t(stmp, nrrd->axis[ii].size)); strcat(*strP, buff); } break; case nrrdField_spacings: *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].spacing); strcat(*strP, buff); } break; case nrrdField_thicknesses: *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].thickness); strcat(*strP, buff); } break; case nrrdField_axis_mins: *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].min); strcat(*strP, buff); } break; case nrrdField_axis_maxs: *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].max); strcat(*strP, buff); } break; case nrrdField_space_directions: *strP = AIR_CALLOC(fslen + nrrd->dim*nrrd->spaceDim*(doubleStrlen + strlen("(,) ")), char); sprintf(*strP, "%s%s: ", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, nrrd->axis[ii].spaceDirection); if (ii < nrrd->dim-1) { strcat(*strP, " "); } } break; case nrrdField_centers: fdlen = 0; for (ii=0; ii<nrrd->dim; ii++) { fdlen += 1 + airStrlen(nrrd->axis[ii].center ? airEnumStr(nrrdCenter, nrrd->axis[ii].center) : NRRD_UNKNOWN); } *strP = AIR_CALLOC(fslen + fdlen, char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { sprintf(buff, " %s", (nrrd->axis[ii].center ? airEnumStr(nrrdCenter, nrrd->axis[ii].center) : NRRD_UNKNOWN)); strcat(*strP, buff); } break; case nrrdField_kinds: fdlen = 0; for (ii=0; ii<nrrd->dim; ii++) { fdlen += 1 + airStrlen(nrrd->axis[ii].kind ? airEnumStr(nrrdKind, nrrd->axis[ii].kind) : NRRD_UNKNOWN); } *strP = AIR_CALLOC(fslen + fdlen, char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { sprintf(buff, " %s", (nrrd->axis[ii].kind ? airEnumStr(nrrdKind, nrrd->axis[ii].kind) : NRRD_UNKNOWN)); strcat(*strP, buff); } break; case nrrdField_labels: case nrrdField_units: #define LABEL_OR_UNITS (nrrdField_labels == field \ ? nrrd->axis[ii].label \ : nrrd->axis[ii].units) fdlen = 0; for (ii=0; ii<nrrd->dim; ii++) { /* The "2*" is because at worst every character needs escaping. The "+ 3" for the |" "| between each part */ fdlen += 2*airStrlen(LABEL_OR_UNITS) + 3; } fdlen += 1; /* for '\0' */ *strP = AIR_CALLOC(fslen + fdlen, char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->dim; ii++) { strcat(*strP, " \""); if (airStrlen(nrrd->axis[ii].label)) { _nrrdWriteEscaped(NULL, *strP, LABEL_OR_UNITS, "\"", _NRRD_WHITESPACE_NOTAB); } strcat(*strP, "\""); } #undef LABEL_OR_UNITS break; /* ---- end per-axis fields ---- */ case nrrdField_min: case nrrdField_max: /* we're basically a no-op, now that these fields became meaningless */ *strP = AIR_CALLOC(fslen + doubleStrlen, char); sprintf(*strP, "%s%s: 0.0", prefix, fs); strcat(*strP, buff); break; case nrrdField_old_min: *strP = AIR_CALLOC(fslen + doubleStrlen, char); sprintf(*strP, "%s%s: ", prefix, fs); airSinglePrintf(NULL, buff, "%.17g", nrrd->oldMin); strcat(*strP, buff); break; case nrrdField_old_max: *strP = AIR_CALLOC(fslen + doubleStrlen, char); sprintf(*strP, "%s%s: ", prefix, fs); airSinglePrintf(NULL, buff, "%.17g", nrrd->oldMax); strcat(*strP, buff); break; case nrrdField_endian: if (airEndianUnknown != nio->endian) { /* we know a specific endianness because either it was recorded as part of "unu make -h", or it was set (and data was possibly altered) as part of "unu save" */ endi = nio->endian; } else { /* we record our current architecture's endian because we're going to writing out data */ endi = airMyEndian(); } *strP = AIR_CALLOC(fslen + strlen(airEnumStr(airEndian, endi)), char); sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(airEndian, endi)); break; case nrrdField_encoding: *strP = AIR_CALLOC(fslen + strlen(nio->encoding->name), char); sprintf(*strP, "%s%s: %s", prefix, fs, nio->encoding->name); break; case nrrdField_line_skip: *strP = AIR_CALLOC(fslen + uintStrlen, char); sprintf(*strP, "%s%s: %d", prefix, fs, nio->lineSkip); break; case nrrdField_byte_skip: *strP = AIR_CALLOC(fslen + uintStrlen, char); sprintf(*strP, "%s%s: %ld", prefix, fs, nio->byteSkip); break; case nrrdField_sample_units: strtmp = airOneLinify(airStrdup(nrrd->sampleUnits)); *strP = AIR_CALLOC(fslen + strlen(strtmp), char); sprintf(*strP, "%s%s: \"%s\"", prefix, fs, strtmp); airFree(strtmp); strtmp = NULL; break; case nrrdField_space_units: fdlen = 0; for (ii=0; ii<nrrd->spaceDim; ii++) { /* The "2*" is because at worst every character needs escaping. See note in formatNRRD.c about how even though its not part of the format, we have worst-case scenario of having to escape a space units which is nothing but ". The "+ 3" for the |" "| between each part */ fdlen += 2*airStrlen(nrrd->spaceUnits[ii]) + 3; } fdlen += 1; /* for '\0' */ *strP = AIR_CALLOC(fslen + fdlen, char); sprintf(*strP, "%s%s:", prefix, fs); for (ii=0; ii<nrrd->spaceDim; ii++) { strcat(*strP, " \""); if (airStrlen(nrrd->spaceUnits[ii])) { _nrrdWriteEscaped(NULL, *strP, nrrd->spaceUnits[ii], "\"", _NRRD_WHITESPACE_NOTAB); } strcat(*strP, "\""); } break; case nrrdField_space_origin: *strP = AIR_CALLOC(fslen + nrrd->spaceDim*(doubleStrlen + strlen("(,) ")), char); sprintf(*strP, "%s%s: ", prefix, fs); _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, nrrd->spaceOrigin); break; case nrrdField_measurement_frame: *strP = AIR_CALLOC(fslen + (nrrd->spaceDim* nrrd->spaceDim*(doubleStrlen + strlen("(,) "))), char); sprintf(*strP, "%s%s: ", prefix, fs); for (dd=0; dd<nrrd->spaceDim; dd++) { for (ii=0; ii<nrrd->spaceDim; ii++) { colvec[ii] = nrrd->measurementFrame[dd][ii]; } _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, colvec); if (dd < nrrd->spaceDim-1) { strcat(*strP, " "); } } break; case nrrdField_data_file: /* NOTE: this comes last (nrrdField_data_file is the highest-valued member of the nrrdField* enum) because the "LIST" form of the data file specification requires that the following lines be the filenames */ /* error checking elsewhere: assumes there is data file info */ if (nio->dataFNFormat) { *strP = AIR_CALLOC(fslen + strlen(nio->dataFNFormat) + 4*uintStrlen, char); if (nio->dataFileDim == nrrd->dim-1) { sprintf(*strP, "%s%s: %s %d %d %d", prefix, fs, nio->dataFNFormat, nio->dataFNMin, nio->dataFNMax, nio->dataFNStep); } else { sprintf(*strP, "%s%s: %s %d %d %d %u", prefix, fs, nio->dataFNFormat, nio->dataFNMin, nio->dataFNMax, nio->dataFNStep, nio->dataFileDim); } } else if (nio->dataFNArr->len > 1) {