int main(int argc, char *argv[]) { int aret; char *me; AIR_UNUSED(argc); me = argv[0]; aret = airSanity(); if (airInsane_not == aret) { char stmp[AIR_STRLEN_SMALL]; fprintf(stderr, "%s: air sanity check passed.\n", me); fprintf(stderr, "\n"); fprintf(stderr, "airMyEndian() == %d\n", airMyEndian()); fprintf(stderr, "AIR_QNANHIBIT == %d\n", AIR_QNANHIBIT); fprintf(stderr, "AIR_DIO == %d\n", AIR_DIO); fprintf(stderr, "sizeof(size_t) = %s\n", airSprintSize_t(stmp, sizeof(size_t))); fprintf(stderr, "sizeof(void*) = %s\n", airSprintSize_t(stmp, sizeof(void*))); return 0; } /* else */ fprintf(stderr, "%s: air sanity check FAILED:\n%s\n", me, airInsaneErr(aret)); return 1; }
unsigned int nrrdCRC32(const Nrrd *nin, int endian) { size_t nn; /* NULL nrrd or data */ if (!nin || !(nin->data) || !(nn = nrrdElementSize(nin)*nrrdElementNumber(nin)) || airEnumValCheck(airEndian, endian)) { return 0; } return airCRC32(AIR_CAST(const unsigned char *, nin->data), nn, nrrdElementSize(nin), endian == airMyEndian() ? AIR_FALSE : AIR_TRUE); }
int unrrdu_cksumMain(int argc, const char **argv, const char *me, hestParm *hparm) { hestOpt *opt = NULL; char *err, **inS; airArray *mop; int pret, endian, printend; unsigned int ni, ninLen; mop = airMopNew(); hestOptAdd(&opt, "en,endian", "end", airTypeEnum, 1, 1, &endian, airEnumStr(airEndian, airMyEndian()), "Endianness in which to compute CRC; \"little\" for Intel and " "friends; \"big\" for everyone else. " "Defaults to endianness of this machine", NULL, airEndian); hestOptAdd(&opt, "pen,printendian", "bool", airTypeBool, 1, 1, &printend, "false", "whether or not to indicate after the CRC value the endianness " "with which the CRC was computed; doing so clarifies " "that the CRC result depends on endianness and may remove " "confusion in comparing results on platforms of different " "endianness"); hestOptAdd(&opt, NULL, "nin1", airTypeString, 1, -1, &inS, NULL, "input nrrd(s)", &ninLen); airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways); USAGE(_unrrdu_cksumInfoL); PARSE(); airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways); for (ni=0; ni<ninLen; ni++) { if (unrrdu_cksumDoit(me, inS[ni], endian, printend, stdout)) { airMopAdd(mop, err = biffGetDone(me), airFree, airMopAlways); fprintf(stderr, "%s: trouble with \"%s\":\n%s", me, inS[ni], err); /* continue working on the remaining files */ } } airMopOkay(mop); return 0; }
int _nrrdFormatVTK_read(FILE *file, Nrrd *nrrd, NrrdIoState *nio) { static const char me[]="_nrrdReadVTK"; char *three[3]; int sx, sy, sz, ret, N; double xm=0.0, ym=0.0, zm=0.0, xs=1.0, ys=1.0, zs=1.0; airArray *mop; unsigned int llen; if (!_nrrdFormatVTK_contentStartsLike(nio)) { biffAddf(NRRD, "%s: this doesn't look like a %s file", me, nrrdFormatVTK->name); return 1; } #define GETLINE(what) \ do { \ ret = _nrrdOneLine(&llen, nio, file); \ } while (!ret && (1 == llen)); \ if (ret || !llen) { \ biffAddf(NRRD, "%s: couldn't get " #what " line", me); \ return 1; \ } /* read in content */ GETLINE(content); if (strcmp(NRRD_UNKNOWN, nio->line)) { if (!(nrrd->content = airStrdup(nio->line))) { biffAddf(NRRD, "%s: couldn't read or copy content string", me); return 1; } } GETLINE(encoding); airToUpper(nio->line); if (!strcmp("ASCII", nio->line)) { nio->encoding = nrrdEncodingAscii; } else if (!strcmp("BINARY", nio->line)) { nio->encoding = nrrdEncodingRaw; } else { biffAddf(NRRD, "%s: encoding \"%s\" wasn't \"ASCII\" or \"BINARY\"", me, nio->line); return 1; } GETLINE(DATASET); airToUpper(nio->line); if (!strstr(nio->line, "STRUCTURED_POINTS")) { biffAddf(NRRD, "%s: sorry, only STRUCTURED_POINTS data is nrrd-ready", me); return 1; } GETLINE(DIMENSIONS); airToUpper(nio->line); if (!strstr(nio->line, "DIMENSIONS") || 3 != sscanf(nio->line, "DIMENSIONS %d %d %d", &sx, &sy, &sz)) { biffAddf(NRRD, "%s: couldn't parse DIMENSIONS line (\"%s\")", me, nio->line); return 1; } GETLINE(next); airToUpper(nio->line); while (!strstr(nio->line, "POINT_DATA")) { if (strstr(nio->line, "ORIGIN")) { if (3 != sscanf(nio->line, "ORIGIN %lf %lf %lf", &xm, &ym, &zm)) { biffAddf(NRRD, "%s: couldn't parse ORIGIN line (\"%s\")", me, nio->line); return 1; } } else if (strstr(nio->line, "SPACING")) { if (3 != sscanf(nio->line, "SPACING %lf %lf %lf", &xs, &ys, &zs)) { biffAddf(NRRD, "%s: couldn't parse SPACING line (\"%s\")", me, nio->line); return 1; } } else if (strstr(nio->line, "ASPECT_RATIO")) { if (3 != sscanf(nio->line, "ASPECT_RATIO %lf %lf %lf", &xs, &ys, &zs)) { biffAddf(NRRD, "%s: couldn't parse ASPECT_RATIO line (\"%s\")", me, nio->line); return 1; } } GETLINE(next); airToUpper(nio->line); } if (1 != sscanf(nio->line, "POINT_DATA %d", &N)) { biffAddf(NRRD, "%s: couldn't parse POINT_DATA line (\"%s\")", me, nio->line); return 1; } if (N != sx*sy*sz) { biffAddf(NRRD, "%s: product of sizes (%d*%d*%d == %d) != # elements (%d)", me, sx, sy, sz, sx*sy*sz, N); return 1; } GETLINE(attribute declaration); mop = airMopNew(); if (3 != airParseStrS(three, nio->line, AIR_WHITESPACE, 3, AIR_FALSE)) { biffAddf(NRRD, "%s: didn't see three words in attribute declaration \"%s\"", me, nio->line); return 1; } airMopAdd(mop, three[0], airFree, airMopAlways); airMopAdd(mop, three[1], airFree, airMopAlways); airMopAdd(mop, three[2], airFree, airMopAlways); airToLower(three[2]); if (!strcmp(three[2], "bit")) { if (nrrdEncodingAscii == nio->encoding) { fprintf(stderr, "%s: WARNING: \"bit\"-type data will be read in as " "unsigned char\n", me); nrrd->type = nrrdTypeUChar; } else { biffAddf(NRRD, "%s: can't read in \"bit\"-type data as BINARY", me); return 1; } } else if (!strcmp(three[2], "unsigned_char")) { nrrd->type = nrrdTypeUChar; } else if (!strcmp(three[2], "char")) { nrrd->type = nrrdTypeChar; } else if (!strcmp(three[2], "unsigned_short")) { nrrd->type = nrrdTypeUShort; } else if (!strcmp(three[2], "short")) { nrrd->type = nrrdTypeShort; } else if (!strcmp(three[2], "unsigned_int")) { nrrd->type = nrrdTypeUInt; } else if (!strcmp(three[2], "int")) { nrrd->type = nrrdTypeInt; } else if (!strcmp(three[2], "float")) { nrrd->type = nrrdTypeFloat; } else if (!strcmp(three[2], "double")) { nrrd->type = nrrdTypeDouble; } else { /* "unsigned_long" and "long" fall in here- I don't know what the VTK people mean by these types, since always mean different things on 32-bit versus 64-bit architectures */ biffAddf(NRRD, "%s: type \"%s\" not recognized", me, three[2]); airMopError(mop); return 1; } airToUpper(three[0]); if (!strncmp("SCALARS", three[0], strlen("SCALARS"))) { GETLINE(LOOKUP_TABLE); airToUpper(nio->line); if (strcmp(nio->line, "LOOKUP_TABLE DEFAULT")) { biffAddf(NRRD, "%s: sorry, can only deal with default LOOKUP_TABLE", me); airMopError(mop); return 1; } nrrd->dim = 3; nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize, AIR_CAST(size_t, sx), AIR_CAST(size_t, sy), AIR_CAST(size_t, sz)); nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, xs, ys, zs); nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, xm, ym, zm); } else if (!strncmp("VECTORS", three[0], strlen("VECTORS"))) { nrrd->dim = 4; nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize, AIR_CAST(size_t, 3), AIR_CAST(size_t, sx), AIR_CAST(size_t, sy), AIR_CAST(size_t, sz)); nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, AIR_NAN, xs, ys, zs); nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, AIR_NAN, xm, ym, zm); nrrd->axis[0].kind = nrrdKind3Vector; } else if (!strncmp("TENSORS", three[0], strlen("TENSORS"))) { nrrd->dim = 4; nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize, AIR_CAST(size_t, 9), AIR_CAST(size_t, sx), AIR_CAST(size_t, sy), AIR_CAST(size_t, sz)); nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, AIR_NAN, xs, ys, zs); nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, AIR_NAN, xm, ym, zm); nrrd->axis[0].kind = nrrdKind3DMatrix; } else { biffAddf(NRRD, "%s: sorry, can only deal with SCALARS, VECTORS, and TENSORS " "currently, so couldn't parse attribute declaration \"%s\"", me, nio->line); airMopError(mop); return 1; } if (!nio->skipData) { if (_nrrdCalloc(nrrd, nio, file)) { biffAddf(NRRD, "%s: couldn't allocate memory for data", me); return 1; } if (nio->encoding->read(file, nrrd->data, nrrdElementNumber(nrrd), nrrd, nio)) { biffAddf(NRRD, "%s:", me); return 1; } if (1 < nrrdElementSize(nrrd) && nio->encoding->endianMatters && airMyEndian() != airEndianBig) { /* encoding exposes endianness, and its big, but we aren't */ nrrdSwapEndian(nrrd); } } else { nrrd->data = NULL; } airMopOkay(mop); return 0; }
/* this strongly assumes that nrrdFitsInFormat() was true */ int _nrrdFormatVTK_write(FILE *file, const Nrrd *_nrrd, NrrdIoState *nio) { static const char me[]="_nrrdFormatVTK_write"; int i, sx, sy, sz, sax; double xs, ys, zs, xm, ym, zm; char type[AIR_STRLEN_MED], name[AIR_STRLEN_SMALL]; Nrrd *nrrd; airArray *mop; /* HEY: should this copy be done more conservatively */ mop = airMopNew(); airMopAdd(mop, nrrd=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); if (nrrdCopy(nrrd, _nrrd)) { biffAddf(NRRD, "%s: couldn't make private copy", me); airMopError(mop); return 1; } if (!( 3 == nrrd->dim || (4 == nrrd->dim && (3 == nrrd->axis[0].size || 9 == nrrd->axis[0].size)) )) { biffAddf(NRRD, "%s: doesn't seem to be scalar, vector, or matrix", me); airMopError(mop); return 1; } sax = nrrd->dim - 3; xs = nrrd->axis[sax+0].spacing; ys = nrrd->axis[sax+1].spacing; zs = nrrd->axis[sax+2].spacing; if (!( AIR_EXISTS(xs) && AIR_EXISTS(ys) && AIR_EXISTS(zs) )) { xs = ys = zs = 1.0; } xm = nrrd->axis[sax+0].min; ym = nrrd->axis[sax+1].min; zm = nrrd->axis[sax+2].min; if (!( AIR_EXISTS(xm) && AIR_EXISTS(ym) && AIR_EXISTS(zm) )) { xm = ym = zm = 0.0; } sx = AIR_CAST(int, nrrd->axis[sax+0].size); sy = AIR_CAST(int, nrrd->axis[sax+1].size); sz = AIR_CAST(int, nrrd->axis[sax+2].size); switch(nrrd->type) { case nrrdTypeUChar: strcpy(type, "unsigned_char"); break; case nrrdTypeChar: strcpy(type, "char"); break; case nrrdTypeUShort: strcpy(type, "unsigned_short"); break; case nrrdTypeShort: strcpy(type, "short"); break; case nrrdTypeUInt: strcpy(type, "unsigned_int"); break; case nrrdTypeInt: strcpy(type, "int"); break; case nrrdTypeFloat: strcpy(type, "float"); break; case nrrdTypeDouble: strcpy(type, "double"); break; default: biffAddf(NRRD, "%s: can't put %s-type nrrd into VTK", me, airEnumStr(nrrdType, nrrd->type)); airMopError(mop); return 1; } fprintf(file, "%s\n", MAGIC3); /* there is a file-format-imposed limit on the length of the "content" */ if (nrrd->content) { /* when the "250" below was previously "255", vtk didn't deal */ for (i=0; i<=250 && nrrd->content[i]; i++) { fputc(nrrd->content[i], file); } fputc('\n', file); } else { fprintf(file, NRRD_UNKNOWN "\n"); } if (nrrdEncodingRaw == nio->encoding) { fprintf(file, "BINARY\n"); } else { fprintf(file, "ASCII\n"); } fprintf(file, "DATASET STRUCTURED_POINTS\n"); fprintf(file, "DIMENSIONS %d %d %d\n", sx, sy, sz); fprintf(file, "ORIGIN %g %g %g\n", xm, ym, zm); fprintf(file, "SPACING %g %g %g\n", xs, ys, zs); fprintf(file, "POINT_DATA %d\n", sx*sy*sz); airSrandMT(AIR_CAST(unsigned int, airTime())); sprintf(name, "nrrd%05d", airRandInt(100000)); if (3 == nrrd->dim) { fprintf(file, "SCALARS %s %s\n", name, type); fprintf(file, "LOOKUP_TABLE default\n"); } else { /* 4 == nrrd->dim */ if (3 == nrrd->axis[0].size) { fprintf(file, "VECTORS %s %s\n", name, type); } else { fprintf(file, "TENSORS %s %s\n", name, type); } } if (1 < nrrdElementSize(nrrd) && nio->encoding->endianMatters && airMyEndian() != airEndianBig) { /* encoding exposes endianness, and we're not big, as req.d by VTK */ nrrdSwapEndian(nrrd); } if (nio->encoding->write(file, nrrd->data, nrrdElementNumber(nrrd), nrrd, nio)) { biffAddf(NRRD, "%s:", me); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
/* ******** airSanity() ** ** Does run-time checks to see if the compile-time constants are correct. ** Returns a value from the airInsane* enum; airInsane_not means all ** the checks came back without detecting any problems. */ int airSanity(void) { double nanValue, pinf, ninf; float nanF, pinfF, ninfF; unsigned int sign, expvalue, mant; int tmpI; char endian; unsigned char uc0, uc1; static int _airSanity=0; if (_airSanity) { return airInsane_not; } /* now that there is no more compile-time endian info, this is merely double checking that airMyEndian() works, and returns the constants (either 1234, pronounced "little endian", or 4321, "big endian") that are defined in air.h */ tmpI = 1; endian = !(*((char*)(&tmpI))); if (endian) { /* big endian */ if (4321 != airMyEndian()) { return airInsane_endian; } } else { if (1234 != airMyEndian()) { return airInsane_endian; } } /* checks on sizes of uchar, float, int, double, airLLong */ uc0 = 255; uc1 = AIR_CAST(unsigned char, AIR_INT(uc0) + 1); /* want to overflow */ if (!( 255 == uc0 && 0 == uc1 )) { return airInsane_UCSize; } /* these justify the AIR_EXISTS_F and AIR_EXISTS_D macros */ if (!( (sizeof(float) == sizeof(int)) && (4 == sizeof(int)) )) { return airInsane_FISize; } if (!( (sizeof(double) == sizeof(airLLong)) && (8 == sizeof(airLLong)) )) { return airInsane_DLSize; } /* run-time NaN checks */ pinf = DBL_MAX; pinf = _airSanityHelper(pinf); pinf = _airSanityHelper(pinf); pinf = _airSanityHelper(pinf); if (AIR_EXISTS(pinf)) { return airInsane_pInfExists; } ninf = -pinf; if (AIR_EXISTS(ninf)) { return airInsane_nInfExists; } nanValue = pinf / pinf; if (AIR_EXISTS(nanValue)) { return airInsane_NaNExists; } nanF = (float)nanValue; pinfF = (float)pinf; ninfF = (float)ninf; airFPValToParts_f(&sign, &expvalue, &mant, nanF); mant >>= 22; if (AIR_QNANHIBIT != (int)mant) { return airInsane_QNaNHiBit; } if (!( airFP_QNAN == airFPClass_f(AIR_NAN) && airFP_QNAN == airFPClass_f(AIR_QNAN) /* As of July 4 2012 GLK decides that the signalling NaN tests are more trouble than they're worth: the signal-ness of the NaN is not preserved in double-float conversion for some platforms (so airFP_SNAN == airFPClass_d(AIR_SNAN) has never been enforced), and there are more platforms for which (apparently) passing AIR_SNAN to airFPClass_d changes it to a quiet NaN, which defeats the purpose of the test. To summarize, given that: ** AIR_NAN and AIR_QNAN are checked here to be quiet NaN, after casting to both float and double, ** quiet NaN "hi bit" is tested above, and that ** quiet and signalling NaN are mutually exclusive, skipping the signalling NaN tests is unlikely to undermine knowing the correctness of the compile-time representation of NaNs. So the following line is now commented out for all platforms. */ /* && airFP_SNAN == airFPClass_f(AIR_SNAN) */ && airFP_QNAN == airFPClass_d(AIR_NAN) && airFP_QNAN == airFPClass_d(AIR_QNAN) )) { return airInsane_AIR_NAN; } if (!(airFP_QNAN == airFPClass_f(nanF) && airFP_POS_INF == airFPClass_f(pinfF) && airFP_NEG_INF == airFPClass_f(ninfF))) { /* really, this is verifying that assigning from a double to a float maintains the FPClass for non-existent values */ return airInsane_FltDblFPClass; } /* just make sure AIR_DIO is reasonably set (actually, this should be done by include/teemDio.h) */ switch (AIR_DIO) { case 0: break; case 1: break; default: return airInsane_dio; } _airSanity = 1; return airInsane_not; }
/* ** _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) {
int main(int argc, const char **argv) { /* stock variables */ char me[] = BKEY; hestOpt *hopt=NULL; hestParm *hparm; airArray *mop; /* variables specific to this program */ int negskip, progress; Nrrd *nref, *nin; size_t *size, ii, nn, tick, pad[2]; unsigned int axi, refCRC, gotCRC, sizeNum; char *berr, *outS[2], stmp[AIR_STRLEN_SMALL], doneStr[AIR_STRLEN_SMALL]; airRandMTState *rng; unsigned int seed, *rdata, printbytes; unsigned char *dataUC; double time0, time1; FILE *fout; /* start-up */ mop = airMopNew(); hparm = hestParmNew(); airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways); /* learn things from hest */ hestOptAdd(&hopt, "seed", "N", airTypeUInt, 1, 1, &seed, "42", "seed for RNG"); hestOptAdd(&hopt, "s", "sz0", airTypeSize_t, 1, -1, &size, NULL, "sizes of desired output", &sizeNum); hestOptAdd(&hopt, "p", "pb pa", airTypeSize_t, 2, 2, pad, "0 0", "bytes of padding before, and after, the data segment " "in the written data"); hestOptAdd(&hopt, "ns", "bool", airTypeInt, 0, 0, &negskip, NULL, "skipping should be relative to end of file"); hestOptAdd(&hopt, "pb", "print", airTypeUInt, 1, 1, &printbytes, "0", "bytes to print at beginning and end of data, to help " "debug problems"); hestOptAdd(&hopt, "o", "out.data out.nhdr", airTypeString, 2, 2, outS, NULL, "output filenames of data and header"); hestParseOrDie(hopt, argc-1, argv+1, hparm, me, tskipInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); /* generate reference nrrd data */ nref = nrrdNew(); airMopAdd(mop, nref, (airMopper)nrrdNuke, airMopAlways); if (nrrdMaybeAlloc_nva(nref, nrrdTypeUInt, sizeNum, size)) { airMopAdd(mop, berr=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error allocating data: %s\n", me, berr); airMopError(mop); return 1; } rng = airRandMTStateNew(seed); airMopAdd(mop, rng, (airMopper)airRandMTStateNix, airMopAlways); nn = nrrdElementNumber(nref); rdata = AIR_CAST(unsigned int *, nref->data); fprintf(stderr, "generating data: . . . "); fflush(stderr); time0 = airTime(); progress = AIR_FALSE; tick = nn/100; for (ii=0; ii<nn; ii++) { rdata[ii] = airUIrandMT_r(rng); if (ii && tick && !(ii % tick)) { time1 = airTime(); if (time1 - time0 > 1.0) { /* if it took more than a second to do 1% of the thing, would be good to generate some progress indication */ progress = AIR_TRUE; } if (progress) { fprintf(stderr, "%s", airDoneStr(0, ii, nn, doneStr)); fflush(stderr); } } } if (progress) { fprintf(stderr, "%s\n", airDoneStr(0, ii, nn, doneStr)); fflush(stderr); } else { fprintf(stderr, "\n"); } fprintf(stderr, "finding reference (big-endian) CRC: "); fflush(stderr); refCRC = nrrdCRC32(nref, airEndianBig); fprintf(stderr, "%u\n", refCRC); /* write data, with padding */ fprintf(stderr, "saving data . . . "); fflush(stderr); if (!(fout = fopen(outS[0], "wb" COMMIT))) { fprintf(stderr, "\n%s: couldn't open %s for writing: %s\n", me, outS[0], strerror(errno)); airMopError(mop); return 1; } airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways); for (ii=0; ii<pad[0]; ii++) { if (EOF == fputc(1, fout)) { fprintf(stderr, "\n%s: error doing pre-padding\n", me); airMopError(mop); return 1; } } if (nn != fwrite(nref->data, nrrdElementSize(nref), nn, fout)) { fprintf(stderr, "\n%s: error writing data\n", me); airMopError(mop); return 1; } for (ii=0; ii<pad[1]; ii++) { if (EOF == fputc(2, fout)) { fprintf(stderr, "\n%s: error doing post-padding\n", me); airMopError(mop); return 1; } } if (EOF == fflush(fout)) { fprintf(stderr, "\n%s: error fflushing data: %s\n", me, strerror(errno)); } fprintf(stderr, "\n"); if (printbytes) { size_t bi, rpb, nn; char stmp[AIR_STRLEN_SMALL]; nn = nrrdElementSize(nref)*nrrdElementNumber(nref); rpb = AIR_MIN(printbytes, nn); dataUC = AIR_CAST(unsigned char *, nref->data); fprintf(stderr, "CORRECT %s bytes at beginning:\n", airSprintSize_t(stmp, rpb)); for (bi=0; bi<rpb; bi++) { fprintf(stderr, "%x ", dataUC[bi]); } fprintf(stderr, "...\n"); fprintf(stderr, "CORRECT %s bytes at end:\n", airSprintSize_t(stmp, rpb)); fprintf(stderr, "..."); for (bi=nn - rpb; bi<nn; bi++) { fprintf(stderr, " %x", dataUC[bi]); } fprintf(stderr, "\n"); } airMopSingleOkay(mop, fout); airMopSingleOkay(mop, nref); nref = NULL; /* write header; for now just writing the header directly */ fprintf(stderr, "writing header . . . \n"); if (!(fout = fopen(outS[1], "w"))) { fprintf(stderr, "%s: couldn't open %s for writing: %s\n", me, outS[1], strerror(errno)); airMopError(mop); return 1; } airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways); fprintf(fout, "NRRD0005\n"); fprintf(fout, "type: unsigned int\n"); fprintf(fout, "dimension: %u\n", sizeNum); fprintf(fout, "sizes:"); for (axi=0; axi<sizeNum; axi++) { fprintf(fout, " %s", airSprintSize_t(stmp, size[axi])); } fprintf(fout, "\n"); fprintf(fout, "endian: %s\n", airEnumStr(airEndian, airMyEndian())); fprintf(fout, "encoding: %s\n", airEnumStr(nrrdEncodingType, nrrdEncodingTypeRaw)); if (!negskip) { if (pad[0]) { fprintf(fout, "byte skip: %s\n", airSprintSize_t(stmp, pad[0])); } } else { fprintf(fout, "byte skip: -%s\n", airSprintSize_t(stmp, pad[1]+1)); } fprintf(fout, "data file: %s\n", outS[0]); airMopSingleOkay(mop, fout); /* read it in, make sure it checks out */ fprintf(stderr, "reading data . . . \n"); nin = nrrdNew(); airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways); if (nrrdLoad(nin, outS[1], NULL)) { airMopAdd(mop, berr=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: error reading back in: %s\n", me, berr); airMopError(mop); return 1; } if (printbytes) { size_t bi, rpb, nn; char stmp[AIR_STRLEN_SMALL]; nn = nrrdElementSize(nin)*nrrdElementNumber(nin); rpb = AIR_MIN(printbytes, nn); dataUC = AIR_CAST(unsigned char *, nin->data); fprintf(stderr, "FOUND %s bytes at beginning:\n", airSprintSize_t(stmp, rpb)); for (bi=0; bi<rpb; bi++) { fprintf(stderr, "%x ", dataUC[bi]); } fprintf(stderr, "...\n"); fprintf(stderr, "FOUND %s bytes at end:\n", airSprintSize_t(stmp, rpb)); fprintf(stderr, "..."); for (bi=nn - rpb; bi<nn; bi++) { fprintf(stderr, " %x", dataUC[bi]); } fprintf(stderr, "\n"); } fprintf(stderr, "finding new CRC . . . \n"); gotCRC = nrrdCRC32(nin, airEndianBig); if (refCRC != gotCRC) { fprintf(stderr, "%s: got CRC %u but wanted %u\n", me, gotCRC, refCRC); airMopError(mop); return 1; } fprintf(stderr, "(all ok)\n"); /* HEY: to test gzip reading, we really want to do a system call to gzip compress the data, and write a new header to point to the compressed data, and make sure we can read in that just the same */ airMopOkay(mop); return 0; }