/* * LaRC_visst_unpacker.c * * Written by Greg Nowicki, AS&M under contract to * Langley Research Center, 2003-2004 * * unpackCP - unpack bit format data to float */ #include #include #include #include #include "vintrt.h" static int check_sizes(const int *, int, int, int, const char *); void change_endian(unsigned int *, int); char VERSION[] = "LaRC_visst_unpacker: V1.0 Langley Research Center"; #ifndef DEBUG #define DEBUG 0 #endif #define ERROR_RETURN -1 /* * this code is designed to unpack the data that is packed using the LaRC Minnis cloud * group's VISST data packer. the reason the data is packed because of the huge data sets * created by the processing of cloud data. reductions of over 60% are being achieved, * justifing the overhead of supporting this code. * * Danger, Will Robinson!!! * _YOU_ are required to make sure that the bounds of the array are not exceeded. * * parameters: * char *fn - pointer to NULL (0) terminated string containing the filename of the packed * data to be unpacked * int *array_size - pointer to a 4 byte integer array with 3 (or more) elements which * contain the actual physical size of the data array so array indexing * can be done correctly. this should be XxYxZ where in a Fortran array * (column-major) the X indicates the number of pixels, Y states the * number of lines, and Z denotes the number of parameters. for a C * array (row-major) the definitions of X and Z are reversed. this is * done for the efficency reasons when cycling through the array, one * always wants to access the elements with the least amount of "stride" * between them. so you want to access Fortran arrays (1,1,1), (2,1,1), * etc. and C arrays as [0][0][0], [0][0][1], etc. this routine doesn't * care WHY it's packed that way, but it needs to know HOW it is aligned. * int *selection - an array of integers, number of parameters in size. allows the caller to * selectively unpack and return only the data they require. if the array * contains [ 0, 0, 1, 0, 1, 0, ..., 0 ], the caller would be returned only * the data values from the third and fifth line by pixel parameter. * int *mcidas_navarr - pointer to int array large enough to hold the mcidas navigation * array (usually 640 4 byte integers) * int *mcidas_head - pointer to int array large enough to hold the mcidas header array * (usually 64 4 byte integers) * int *valid_size - pointer to a 4 byte integer array with 3 (or more) elements which will * have the actual nparams x nlines x npixels numbers put into the first * three elements. this is the actual number of data points which have * been read from the data file and modified by this routine. * float *data - pointer to float array where data is to be unpacked into. this must be * large enough to hold all of the data which is unpacked! see array_size. * * this routine will _NOT_ touch the data in the first three parameters, but it will overwrite * data contained in the last four * * returns ERROR_RETURN upon routine failure, 0 for success. * * written by GDN starting 24-Oct-2002 * */ /* * wrapper for IDL calls */ int unpackcp_idl(int argc, void *argv[]) { const char *fn; const int *array_size; const int *selection; int *mcidas_navarr; int *mcidas_head; int *valid_size; float *data; float *lat_lon; char *comment; if (argc != 9) { fprintf(stderr, "Bad number of parameters to unpackcp_idl: %d\n", argc); return(-1); } fn = (char *) argv[0]; array_size = (int *) argv[1]; selection = (int *) argv[2]; mcidas_navarr = (int *) argv[3]; mcidas_head = (int *) argv[4]; valid_size = (int *) argv[5]; data = (float *) argv[6]; lat_lon = (float *) argv[7]; comment = (char *) argv[8]; return (unpackCP(fn, array_size, selection, mcidas_navarr, mcidas_head, valid_size, data, lat_lon, comment)); } /* * wrappers for Fortran calls */ int unpackcp_(const char *fn, const int *array_size, const int *selection, int *mcidas_navarr, int *mcidas_head, int *valid_size, float *data, float *lat_lon, char *comment) { return (unpackCP(fn, array_size, selection, mcidas_navarr, mcidas_head, valid_size, data, lat_lon, comment)); } int unpackCP_(const char *fn, const int *array_size, const int *selection, int *mcidas_navarr, int *mcidas_head, int *valid_size, float *data, float *lat_lon, char *comment) { return (unpackCP(fn, array_size, selection, mcidas_navarr, mcidas_head, valid_size, data, lat_lon, comment)); } int unpackCP(const char *fn, const int *array_size, const int *selection, int *mcidas_navarr, int *mcidas_head, int *valid_size, float *data, float *lat_lon, char *comment) { int i, j, k, pos, index, offset, extra, status, curr_pos, curr_arr_pos; unsigned int uvalue, nbits, scale, ints2read, *values; unsigned int start_pos[MAX_PARAMETERS], num2read[MAX_PARAMETERS]; int nparams, nlines, npixels, mcidas_head_size, mcidas_navigation_size; float *p, neg; FILE *f; int data_format_version, ascii_header_size, adj_nparams; char data_format[DATA_FORMAT_SIZE + 1], *str1, *str2, *tt; unsigned char elems[MAX_PARAMETERS]; static char ename[] = "visst_unpacker error:"; static char dname[] = "visst_unpacker debug:"; if ((f = fopen(fn, "rb")) == NULL) { fprintf(stderr, "%s Opening data file: %s\n", ename, fn); return ERROR_RETURN; } /* * to make this routine as generic as possible, we'll read juat enough data to determine * the format of the data contained within this data file, then read the data. */ if ((status = fread(data_format, sizeof(char), DATA_FORMAT_SIZE, f)) != DATA_FORMAT_SIZE) { fprintf(stderr, "%s Reading data_format from file: %s number: %d\n", ename, fn, status); return ERROR_RETURN; } data_format_version = atoi(data_format); switch (data_format_version) { case 0: case 1: ascii_header_size = MAX_ASCII_SIZE - DATA_FORMAT_SIZE; break; default: fprintf(stderr, "%s Unknown data format version: %d\n", ename, data_format_version); return ERROR_RETURN; } if ((str1 = calloc(ascii_header_size + DATA_FORMAT_SIZE, sizeof(char))) == NULL) { fprintf(stderr, "%s callocing str1, size: %d\n", ename, ascii_header_size + DATA_FORMAT_SIZE); return ERROR_RETURN; } if ((status = fread(str1 + DATA_FORMAT_SIZE, sizeof(char), ascii_header_size, f)) != ascii_header_size) { fprintf(stderr, "%s Reading char_info from file: %s number: %d\n", ename, fn, status); return ERROR_RETURN; } memcpy(str1, data_format, DATA_FORMAT_SIZE); /* * we don't _need_ a second copy, but since strtok hoses the string as it parses it, * let's keep a 'virgin' copy around. */ if ((str2 = calloc(ascii_header_size + DATA_FORMAT_SIZE, sizeof(char))) == NULL) { fprintf(stderr, "%s callocing str2, size: %d\n", ename, ascii_header_size + DATA_FORMAT_SIZE); return ERROR_RETURN; } memcpy(str2, str1, ascii_header_size + DATA_FORMAT_SIZE); /* * pick off the data format string. */ tt = strtok(str1, " \t\0"); /* * pick off the date string. */ tt = strtok(NULL, " \t\0"); /* * pick off the time string. */ tt = strtok(NULL, " \t\0"); /* * pick off the number of parameters and convert it to an int. */ tt = strtok(NULL, " \t\0"); nparams = atoi(tt); /* * pick off the number of lines and convert it to an int. */ tt = strtok(NULL, " \t\0"); nlines = atoi(tt); /* * pick off the number of pixels and convert it to an int. */ tt = strtok(NULL, " \t\0"); npixels = atoi(tt); /* * pick off the number of mcidas navigation block integers. */ tt = strtok(NULL, " \t\0"); mcidas_navigation_size = atoi(tt); /* * pick off the number of mcidas head block integers. */ tt = strtok(NULL, " \t\0"); mcidas_head_size = atoi(tt); /* * pick off the date and time of file creation, discard ;-( */ tt = strtok(NULL, " \t\0"); tt = strtok(NULL, " \t\0"); /* * pick off the latitude and longitude values */ for (i = 0; i < 6; i++) { tt = strtok(NULL, " \t\0"); lat_lon[i] = atof(tt); } strncpy(comment, &str2[DEDICATED_ASCII_SIZE], COMMENT_SIZE); /* * let's do a little error checking here. never assume that the user gives good input. * * check to make sure the user has provided enough space in which to place the data. * use adj_nparams to compare because the whole idea is to allow the caller to * request a subset of the data and only provide enough space for that subset. */ for (i = 0, adj_nparams = 0; i < array_size[0]; i++) { if (selection[i] == 1) { adj_nparams++; } } j = i; if (check_sizes(array_size, adj_nparams, nlines, npixels, "array_size") == ERROR_RETURN) { fprintf(stderr, "%s Unrecoverable error.\n", ename); return ERROR_RETURN; } /* * now we know how much data to read. tell the caller how much of his/her data array is filled. */ valid_size[0] = nparams; valid_size[1] = nlines; valid_size[2] = npixels; if (nparams > MAX_PARAMETERS) { fprintf(stderr, "%s MAX_PARAMETERS not set big enough: %d\n", ename, nparams); return ERROR_RETURN; } if ((values = calloc(nlines * npixels, sizeof(int))) == NULL) { fprintf(stderr, "%s callocing values, size: %d\n", ename, nlines * npixels); return ERROR_RETURN; } /* * read in the char array which contains parameter index. */ if ((status = fread(elems, sizeof(elems), 1, f)) != 1) { fprintf(stderr, "%s Reading char array from file: %s number: %d\n", ename, fn, status); return ERROR_RETURN; } /* * read in the mcidas navigation array. */ if ((status = fread(mcidas_navarr, sizeof(int), mcidas_navigation_size, f)) != mcidas_navigation_size) { fprintf(stderr, "%s Reading mcidas navarr from file: %s number: %d\n", ename, fn, status); return ERROR_RETURN; } /* * read in the mcidas header array. */ if ((status = fread(mcidas_head, sizeof(int), mcidas_head_size, f)) != mcidas_head_size) { fprintf(stderr, "%s Reading mcidas head from file: %s number: %d\n", ename, fn, status); return ERROR_RETURN; } change_endian((unsigned int *) mcidas_navarr, mcidas_navigation_size); change_endian((unsigned int *) mcidas_head, mcidas_head_size); #if DEBUG printf("%s mcidas_navigation_size: %d mcidas_head_size: %d\n", dname, mcidas_navigation_size, mcidas_head_size); printf("%s nparams: %d nlines: %d npixels: %d\n", dname, nparams, nlines, npixels); #endif /* * now, we unpack the data, nbits at a time and put it into the correct float array location. */ curr_pos = ftell(f); for (i = 0; i < nparams; i++) { nbits = full_list[elems[i]].bits; ints2read = (nbits * nlines * npixels) / BITS_PER_INT; if ((nbits * nlines * npixels) % BITS_PER_INT != 0) { ints2read++; } start_pos[i] = curr_pos; num2read[i] = ints2read; curr_pos += (ints2read * sizeof(int)); } j = i; #if DEBUG printf("%s Max array size in integers: %d\n", dname, array_size[0] * array_size[1] * array_size[2]); #endif curr_arr_pos = 0; for (i = 0; i < nparams; i++) { /* * if we're selecting parameters and the current parameter is not set to 1, * then we skip this parameter. */ if (selection[i] != 1) { continue; } /* * given the number of bits per data value and number of data values, how many * 4 byte integers should I read for each parameter? */ nbits = full_list[elems[i]].bits; scale = full_list[elems[i]].scale; ints2read = num2read[i]; #if DEBUG printf("%s %d: nbits: %d scale: %d ints2read: %d\n", dname, i, nbits, scale, ints2read); #endif /* * read 'em in. */ if (fseek(f, start_pos[i], SEEK_SET) != 0) { fprintf(stderr, "%s positioning to byte pos: %d from file: %s\n", ename, start_pos[i], fn); return ERROR_RETURN; } if ((status = fread(values, sizeof(int), ints2read, f)) != ints2read) { fprintf(stderr, "%s Reading packed: %d from file: %s number: %d\n", ename, i, fn, status); return ERROR_RETURN; } change_endian(values, ints2read); /* * process the data value one line and one pixel at a time. */ #if DEBUG printf("%s About to fill array elements: %d-%d\n", dname, i * array_size[1] * array_size[2], (i + 1) * array_size[1] * array_size[2] - 1); #endif for (j = 0, pos = 0; j < nlines; j++) { /* * reset array positioning because the storage array may be larger than the data * being unpacked (or it may be the same size) */ p = data + j * array_size[2] + curr_arr_pos * array_size[1] * array_size[2]; for (k = 0; k < npixels; k++, p++, pos += nbits) { index = pos / BITS_PER_INT; offset = pos % BITS_PER_INT; /* * how many extra bits (outside of this BITS_PER_INT bit int) are there? */ extra = offset + nbits - BITS_PER_INT; /* * shift and mask the current int array value. * right shift on a signed int brings the sign bit along for the ride, so do the * shift on the unsiged value. */ uvalue = values[index]; uvalue = (uvalue >> offset) & MASK[nbits]; /* * OK, do we need to go into the next array element to get the rest of the number? */ if (extra > 0) { uvalue += ((values[index + 1] & MASK[extra]) << (BITS_PER_INT - offset)); } /* * see if the negative flag is set, if so, remove it and negate the value. */ if ((uvalue >> (nbits - 1)) == 1) { uvalue &= MASK[nbits - 1]; neg = -1.; } else { neg = 1.; } *p = neg * (float) uvalue / scale; } /* end of k loop */ } /* end of j loop */ curr_arr_pos++; #if DEBUG printf("%s unpack: i: %d index: %u\n", dname, i, index); #endif } /* end of i loop */ #if DEBUG printf("%s Time to free strings\n", dname); #endif free(str1); free(str2); #if DEBUG printf("%s Time to free values\n", dname); #endif free(values); #if DEBUG printf("%s Time to return\n", dname); #endif fclose(f); return 0; } void change_endian(unsigned int *data, int num) { unsigned char *p = (unsigned char *) data; int i; for (i = 0; i < num; i++, p += 4) { data[i] = (*p << 24) + (*(p+1) << 16) + (*(p+2) << 8) + (*(p+3)); } } int check_sizes(const int *valid, int x, int y, int z, const char *var_name) { static char ename[] = "check_sizes error:"; static char dname[] = "check_sizes debug:"; int i; for (i = 0; i < 3; i++) { if (valid[i] < 1) { fprintf(stderr, "%s Invalid value for %s: %d\n", ename, var_name, valid[i]); return ERROR_RETURN; } } if ((x > valid[0]) || (y > valid[1]) || (z > valid[2])) { fprintf(stderr, "%s Array sizes incorrect, data is : %dx%dx%d\n", ename, x, y, z); fprintf(stderr, "Provided array size is: "); for (i = 0; i < 3; i++) { fprintf(stderr, "%d", valid[i]); if (i < 2) { fprintf(stderr, "x"); } else { fprintf(stderr, "\n"); } } return ERROR_RETURN; } return 0; } /* * utilities */ /* Global data structures that get set each time a file is opened */ static int fd = -1, data_format = -1; static int ascii_header_size; static unsigned char elems[MAX_PARAMETERS]; static struct visst_header vhead; /* defined in vintrt.h */ static int *mcidas_navarr; static int *mcidas_head; static off_t fpos = -1; /* currently not consistantly used nor fulled implemnted */ static int bytes2skip[MAX_PARAMETERS]; static int ints2read[MAX_PARAMETERS]; /* Internal prototypes */ static int get_data_format(); static struct visst_header *parse_vintrt_head(); static char *num2var_name(int); static int var_name2num(const char *); static int mystrncasecmp(const char *, const char *); /************************************************************************/ /* * open the file whose name is pointed to by fn and return the file descriptor. * fill out the global data structures. return nparams, nlines, and npixels to caller. * calls parse_vintrt_head() (an internal routine). * * return -1 on failure, 0 on success. */ int vintrt_open_(char *fn, int *nparams, int *nlines, int *npixels) { return (vintrt_open(fn, nparams, nlines, npixels)); } int vintrt_open(char *fn, int *nparams, int *nlines, int *npixels) { const char ename[] = "vintrt_open error:"; const char dname[] = "vintrt_open debug:"; int b2s, i; #if DEBUG printf("%s file name: %s\n", dname, fn); #endif if (fd != -1) { fprintf(stderr, "%s Opening file: %s, file descriptor already in use.\n", ename, fn); return -1; } if ((fd = open(fn, O_RDONLY, 0)) == -1) { fprintf(stderr, "%s Opening file: %s\n", ename, fn); return -1; } /* * set variable fpos */ if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { fprintf(stderr, "%s lseek position current.\n", ename); return -1; } if (parse_vintrt_head() == NULL) { fprintf(stderr, "%s Reading/parsing ascii header.\n", ename); return -1; } *nparams = vhead.nparams; *nlines = vhead.nlines; *npixels = vhead.npixels; if ((fpos = lseek(fd, ascii_header_size, SEEK_SET)) == -1) { fprintf(stderr, "%s lseek position %d.\n", ename, ascii_header_size); return -1; } if (read(fd, elems, MAX_PARAMETERS) != MAX_PARAMETERS) { fprintf(stderr, "%s Reading parameter (elems) info.\n", ename); return -1; } free(mcidas_navarr); if ((mcidas_navarr = malloc(vhead.mcidas_nsize * sizeof(int))) == NULL) { fprintf(stderr, "%s Mallocing mcidas navarr data.\n", ename); return -1; } if (read(fd, mcidas_navarr, vhead.mcidas_nsize * sizeof(int)) != vhead.mcidas_nsize * sizeof(int)) { fprintf(stderr, "%s Reading mcidas navarr data.\n", ename); return -1; } free(mcidas_head); if ((mcidas_head = malloc(vhead.mcidas_hsize * sizeof(int))) == NULL) { fprintf(stderr, "%s Mallocing mcidas head data.\n", ename); return -1; } if (read(fd, mcidas_head, vhead.mcidas_hsize * sizeof(int)) != vhead.mcidas_hsize * sizeof(int)) { fprintf(stderr, "%s Reading mcidas head data.\n", ename); return -1; } change_endian((unsigned int *) mcidas_navarr, vhead.mcidas_nsize); change_endian((unsigned int *) mcidas_head, vhead.mcidas_hsize); #if DEBUG printf("%s file descriptor: %d\n", dname, fd); #endif /* * figure out how many bytes reside in each parameter of the data. and how many * bytes to skip for each one. store it in global arrays. */ bytes2skip[0] = ascii_header_size + MAX_PARAMETERS + (vhead.mcidas_nsize + vhead.mcidas_hsize) * sizeof(int); for (i = 0; i < vhead.nparams; i++) { ints2read[i] = (full_list[elems[i]].bits * vhead.nlines * vhead.npixels) / BITS_PER_INT; if ((full_list[elems[i]].bits * vhead.nlines * vhead.npixels) % BITS_PER_INT != 0) { ints2read[i]++; } if (i > 0) { bytes2skip[i] = bytes2skip[i - 1] + (ints2read[i - 1] * sizeof(int)); } } return 0; } /************************************************************************/ /* * read the vintrt header from open file pointed to by file descriptor fd. * copy it into the area pointed to by header (provided by the caller). * * return -1 on failure, 0 on success. */ int vintrt_get_header_(char *header) { return (vintrt_get_header(header)); } int vintrt_get_header(char *header) { const char ename[] = "vintrt_print_head error:"; char str[MAX_ASCII_SIZE]; int status; if (lseek(fd, 0, SEEK_SET) == -1) { fprintf(stderr, "%s lseek position BOF.\n", ename); return -1; } if ((status = read(fd, str, ascii_header_size)) != ascii_header_size) { fprintf(stderr, "%s Reading ascii header from file. number: %d\n", ename, status); return -1; } if (lseek(fd, fpos, SEEK_SET) == -1) { fprintf(stderr, "%s lseek position fpos.\n", ename); return -1; } strncpy(header, str, MAX_ASCII_SIZE); return 0; } /************************************************************************/ /* * find and return to the caller the parameters for var_name. * space for those parameters must be provided by the caller. * * return -1 upon failure, 0 for success. */ int vintrt_var_attributes_(const char *var_name, char *units, float range[], float fill[], int *valid) { return (vintrt_var_attributes(var_name, units, range, fill, valid)); } int vintrt_var_attributes(const char *var_name, char *units, float range[], float fill[], int *valid) { int vnum; char ename[] = "vintrt_var_attributes error:"; char dname[] = "vintrt_var_attributes debug:"; if (fd == -1) { fprintf(stderr, "%s No file open\n", ename); return -1; } if ((vnum = var_name2num(var_name)) == -1) { fprintf(stderr, "%s Unknown variable name: %s\n", ename, var_name); return -1; } strncpy(units, full_list[elems[vnum]].unit_name, MAX_UNIT_NAME_SIZE); range[0] = full_list[elems[vnum]].min; range[1] = full_list[elems[vnum]].max; fill[0] = -7.; fill[1] = -8.; fill[2] = -9.; *valid = 3; return 0; } /************************************************************************/ /* * return to the caller the data for variable name var_name. the caller is * responsible for telling this routine the size of the array (in variable * asize) provided in [nlines, npixels] format and making that array * available to the routine. * * return -1 upon failure, 0 for success. */ int vintrt_read_var_(const char *var_name, const int asize[], float data[]) { return (vintrt_read_var(var_name, asize, data)); } int vintrt_read_var(const char *var_name, const int asize[], float data[]) { char ename[] = "vintrt_read_var error:"; char dname[] = "vintrt_read_var debug:"; int vnum, i, j; int *values; int pos, index, offset, extra, neg, bits, bytes2read; unsigned uvalue; float *p, scale; if (fd == -1) { fprintf(stderr, "%s No file open.\n", ename); return -1; } if ((vnum = var_name2num(var_name)) == -1) { fprintf(stderr, "%s Unknown variable name: %s\n", ename, var_name); return -1; } if ((vhead.npixels > asize[1]) || (vhead.nlines > asize[0])) { fprintf(stderr, "%s Array sizes incorrect, data is : %dx%d\n", ename, vhead.nlines, vhead.npixels); fprintf(stderr, "Provided array size is: %dx%d\n", asize[0], asize[1]); return -1; } /* * now we know how much data to read. */ if ((values = calloc(vhead.nlines * vhead.npixels, sizeof(int))) == NULL) { fprintf(stderr, "%s callocing values, size: %d\n", ename, vhead.nlines * vhead.npixels); return -1; } #if DEBUG printf("%s vnum: %d bytes2skip: %d ints2read: %d nbits: %d\n", dname, vnum, bytes2skip[vnum], ints2read[vnum], full_list[elems[vnum]].bits); #endif if (lseek(fd, bytes2skip[vnum], SEEK_SET) == -1) { free(values); fprintf(stderr, "%s lseek position bytes2skip: %d\n", ename, bytes2skip[vnum]); return -1; } bytes2read = ints2read[vnum] * sizeof(int); if (read(fd, values, bytes2read) != bytes2read) { free(values); fprintf(stderr, "%s parameter: %d read values: %d\n", ename, vnum, bytes2read); return -1; } change_endian((unsigned int *) values, ints2read[vnum]); bits = full_list[elems[vnum]].bits; scale = full_list[elems[vnum]].scale; /* * insert the data in the array pixel by pixel, leading to a layout as follows: * memory location * 1 2 3 . . . . n * nline=1,npixel=1 nline=1,npixel=2 nline=1,npixel=3 .. nline=nline,npixel=npixel */ for (i = 0, pos = 0; i < vhead.nlines; i++) { p = data + i * asize[1]; for (j = 0; j < vhead.npixels; j++, p++, pos += bits) { index = pos / BITS_PER_INT; offset = pos % BITS_PER_INT; /* * how many extra bits (outside of this BITS_PER_INT bit int) are there? */ extra = offset + bits - BITS_PER_INT; /* * shift and mask the current int array value. * right shift on a signed int brings the sign bit along for the ride, so do the * shift on the unsiged value. */ uvalue = values[index]; uvalue = (uvalue >> offset) & MASK[bits]; /* * OK, do we need to go into the next array element to get the rest of the number? */ if (extra > 0) { uvalue += ((values[index + 1] & MASK[extra]) << (BITS_PER_INT - offset)); } /* * see if the negative flag is set, if so, remove it and negate the value. */ if ((uvalue >> (bits - 1)) == 1) { uvalue &= MASK[bits - 1]; neg = -1.; } else { neg = 1.; } *p = neg * (float) uvalue / scale; } /* end of j loop */ #if DEBUG printf("%s unpack: i: %d index: %u\n", dname, i, index); #endif } /* end of i loop */ free(values); if (lseek(fd, fpos, SEEK_SET) == -1) { return -1; } return 0; } /************************************************************************/ /* * front-end for num2var_name which will take the integer provided by the caller * and copy that variable name into space provided by the caller. * * return -1 upon failure, 0 for success. */ int vintrt_get_vname_(int *num, char *var_name) { return (vintrt_get_vname(num, var_name)); } int vintrt_get_vname(int *num, char *var_name) { char ename[] = "vintrt_get_vnames error:"; char *c; if (fd == -1) { fprintf(stderr, "%s No file open.\n", ename); return -1; } if ((c = num2var_name(*num)) == NULL) { fprintf(stderr, "%s Variable number %d not found.\n", ename, *num); return -1; } strncpy(var_name, c, MAX_VAR_NAME_SIZE); return 0; } /************************************************************************/ /* * return to the caller the date and time contained in the header. * copy into space provided by the caller. * assumes that the header has been read into the data structure. * date contains: dd/mm/yyyy * time contains: hh:mm:ss * * return -1 upon failure, 0 for success. */ int vintrt_get_datetime_(int *date, int *time) { return (vintrt_get_datetime(date, time)); } int vintrt_get_datetime(int *date, int *time) { char ename[] = "vintrt_get_datetime error:"; if (fd == -1) { fprintf(stderr, "%s No file open.\n", ename); return -1; } date[0] = vhead.day; date[1] = vhead.month; date[2] = vhead.year; time[0] = vhead.hour; time[1] = vhead.minute; time[2] = vhead.second; return 0; } /************************************************************************/ /* * return to the caller the sizes of the mcidas nav and header block. * copy into space provided by the caller. * assumes that the header has been read into the data structure. * * return -1 upon failure, 0 for success. */ int vintrt_get_mcidas_size_(int *nav_size, int *head_size) { return (vintrt_get_mcidas_size(nav_size, head_size)); } int vintrt_get_mcidas_size(int *nav_size, int *head_size) { char ename[] = "vintrt_get_mcidas_size error:"; if (fd == -1) { fprintf(stderr, "%s No file open.\n", ename); return -1; } *nav_size = vhead.mcidas_nsize; *head_size = vhead.mcidas_hsize; return 0; } /************************************************************************/ /* * close the file pointed to by the file descriptor. reset global fd to -1. * * return -1 upon failure, 0 for success. */ int vintrt_close_() { return (vintrt_close()); } int vintrt_close() { if (close(fd) == 0) { fd = -1; return 0; } else { return -1; } } /************************************************************************/ /* * just printout the VERSION and return. * * void return. */ void vintrt_utils_version_() { vintrt_utils_version(); return; } void vintrt_utils_version() { printf("%s\n", VERSION); return; } /* * do not call any of the following code from outside of this module. any of * these structures can change at any time! */ /************************************************************************/ /* * given a file descriptor, return the information from the packed pixel files * header, such as number of parameters, lines, and pixels, comment, etc. * * Only for use within the utils code since it can only be easily integrated * into C calling routines. * the structure it returns is flexible and could be changed at any time. * * return NULL upon failure, pointer to global vhead structure for success. * * Internal use only! */ static struct visst_header *parse_vintrt_head() { const char ename[] = "parse_vintrt_head error:"; const char dname[] = "parse_vintrt_head debug:"; int status; char str[MAX_ASCII_SIZE + 1], form[DATA_FORMAT_SIZE + 1]; if (fd == -1) { fprintf(stderr, "%s No file open.\n", ename); return NULL; } form[DATA_FORMAT_SIZE] = '\0'; if (lseek(fd, 0, SEEK_SET) == -1) { fprintf(stderr, "%s lseek.\n", ename); return NULL; } if ((status = read(fd, form, DATA_FORMAT_SIZE)) != DATA_FORMAT_SIZE) { fprintf(stderr, "%s Reading data format from file. number: %d\n", ename, status); return NULL; } switch (atoi(form)) { case 0: case 1: ascii_header_size = MAX_ASCII_SIZE; break; default: fprintf(stderr, "%s Unknown data format: %d\n", ename, form); return NULL; break; } if (lseek(fd, 0, SEEK_SET) == -1) { fprintf(stderr, "%s lseek.\n", ename); return NULL; } str[ascii_header_size] = '\0'; if ((status = read(fd, str, ascii_header_size)) != ascii_header_size) { fprintf(stderr, "%s Reading char_info from file. number: %d\n", ename, status); return NULL; } #if DEBUG printf("%s header string: %s\n", dname, str); #endif /* * pick off the format number */ vhead.data_format = atoi(strtok(str, ":/ \t\0")); /* * pick off the date string elements, month, day, year. */ vhead.month = atoi(strtok(NULL, ":/ \t\0")); vhead.day = atoi(strtok(NULL, ":/ \t\0")); vhead.year = atoi(strtok(NULL, ":/ \t\0")); #if DEBUG printf("%s month-day-year: %d-%d-%d\n", dname, vhead.month, vhead.day, vhead.year); #endif /* * pick off the time string elements, hour, minute, second. */ vhead.hour = atoi(strtok(NULL, ":/ \t\0")); vhead.minute = atoi(strtok(NULL, ":/ \t\0")); vhead.second = atoi(strtok(NULL, ":/ \t\0")); #if DEBUG printf("%s hour:minute:second: %d:%d:%d\n", dname, vhead.hour, vhead.minute, vhead.second); #endif /* * pick off the number of parameters, lines, and pixels. */ vhead.nparams = atoi(strtok(NULL, ":/ \t\0")); vhead.nlines = atoi(strtok(NULL, ":/ \t\0")); vhead.npixels = atoi(strtok(NULL, ":/ \t\0")); #if DEBUG printf("%s nparams nlines npixels: %d %d %d\n", dname, vhead.nparams, vhead.nlines, vhead.npixels); #endif /* * pick off the number of mcidas navigation and header block integers. */ vhead.mcidas_nsize = atoi(strtok(NULL, ":/ \t\0")); vhead.mcidas_hsize = atoi(strtok(NULL, ":/ \t\0")); #if DEBUG printf("%s mcidas head size, nav size: %d %d\n", dname, vhead.mcidas_hsize, vhead.mcidas_nsize); #endif /* * pick off the pixel level file creation date string elements, month, day, year. */ vhead.cmonth = atoi(strtok(NULL, ":/ \t\0")); vhead.cday = atoi(strtok(NULL, ":/ \t\0")); vhead.cyear = atoi(strtok(NULL, ":/ \t\0")); #if DEBUG printf("%s data collection month-day-year: %d-%d-%d\n", dname, vhead.cmonth, vhead.cday, vhead.cyear); #endif /* * pick off the pixel level file creation time string elements, hour, minute, second. */ vhead.chour = atoi(strtok(NULL, ":/ \t\0")); vhead.cminute = atoi(strtok(NULL, ":/ \t\0")); vhead.csecond = atoi(strtok(NULL, ":/ \t\0")); #if DEBUG printf("%s data collection hour:minute:second: %d:%d:%d\n", dname, vhead.chour, vhead.cminute, vhead.csecond); #endif vhead.ul_lat = atof(strtok(NULL, ":/ \t\0")); vhead.ul_lon = atof(strtok(NULL, ":/ \t\0")); vhead.lr_lat = atof(strtok(NULL, ":/ \t\0")); vhead.lr_lon = atof(strtok(NULL, ":/ \t\0")); vhead.x_res = atof(strtok(NULL, ":/ \t\0")); vhead.y_res = atof(strtok(NULL, ":/ \t\0")); strncpy(vhead.comment, &str[DEDICATED_ASCII_SIZE], COMMENT_SIZE); #if DEBUG printf("%s comment: %s\n", dname, vhead.comment); printf("%s file descriptor: %d\n", dname, fd); printf("%s &vhead: %p\n", dname, &vhead); #endif if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) { fprintf(stderr, "%s lseek\n", ename); return NULL; } return &vhead; } /************************************************************************/ /* * just return the data format version as an integer * no side effects as the file stream pointer is reset to initial location. * * return -1 upon failure, 0 for success. * * Internal use only! */ static int get_data_format() { const char ename[] = "get_data_format error:"; const char dname[] = "get_data_format debug:"; char data_format_str[DATA_FORMAT_SIZE + 1]; /* * to make this routine as generic as possible, we'll read just enough data to determine * the format of the data contained within this data file. * we may come into this routine at any time, so now make sure that the characters read * are the first 4 and reset the file pointer to the previous position. */ if (lseek(fd, 0, SEEK_SET) == -1) { return -1; } if (read(fd, data_format_str, DATA_FORMAT_SIZE) != DATA_FORMAT_SIZE) { return -1; } if (lseek(fd, fpos, SEEK_SET) == -1) { return -1; } #if DEBUG printf("%s data_format_string: %s\n", dname, data_format_str); #endif return atoi(data_format_str); } /************************************************************************/ /* * given a file descriptor and parameter number, locate the variable name and use * the provided cahracter pointer to return the variable name. * return pointer to var_name if successful. overwritten after each call. * return NULL if the parameter number is not in range or file cannot be read from. * * Internal use only! */ static char *num2var_name(int num) { static char var_name[MAX_VAR_NAME_SIZE + 1]; if (fd == -1) { return NULL; } if ((num < 0) || (num >= vhead.nparams)) { return NULL; } strncpy(var_name, full_list[elems[num]].var_name, MAX_VAR_NAME_SIZE + 1); return var_name; } /************************************************************************/ /* * given a file descriptor and variable name, return the parameter number * of this variable name. -1 if file problem or not a valid variable name. * * Internal use only! */ static int var_name2num(const char *var_name) { int i; if (fd == -1) { return -1; } for (i = 0; i < vhead.nparams; i++) { if (mystrncasecmp(var_name, full_list[elems[i]].var_name) == 0) { return i; } } return -1; } /************************************************************************/ /* * given a file descriptor and variable name, return the attributes of this * variable such as range, dimensions, and fill value(s). * return NULL if variable not found. * * return -1 upon failure, 0 for success. * * Internal use only! */ struct var_attributes *vintrt_var_attributes_internal(const char *var_name) { static struct var_attributes attrib; int i, max_vals; if ((attrib.data_format = get_data_format()) == -1) { return NULL; } attrib.fill[0] = -7; attrib.fill[1] = -8; attrib.fill[2] = -9; attrib.num_fill = 3; for (i = 0; i < vhead.nparams; i++) { if (mystrncasecmp(var_name, full_list[elems[i]].var_name) == 0) { strncpy(attrib.var_name, full_list[elems[i]].var_name, MAX_VAR_NAME_SIZE); strncpy(attrib.unit_name, full_list[elems[i]].unit_name, MAX_UNIT_NAME_SIZE); attrib.min = full_list[elems[i]].min; attrib.max = full_list[elems[i]].max; attrib.var_num = i; return &attrib; } } return NULL; } /************************************************************************/ /* * compare two string, case insensitive * * return 0 if the same, else -1. * * Internal use only! */ static int mystrncasecmp(const char *a, const char *b) { while (*a && *b) { if (tolower(*a) != tolower(*b)) { return -1; } a++; b++; } if ((*a == '\0') && (*b == '\0')) { return 0; } return -1; }