/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF. The full HDF copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at * * http://hdfgroup.org/products/hdf4/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* $Id: sdmodcompslab.c 5760 2012-01-20 12:53:37Z bmribler $ */ /****************************************************************************** file - sdmodcompslab.c This file contains the function sdmodcompslab added to support the HDFView in writing a compressed SDS partially. HDFView will link with this file prior to using sdmodcompslab. --- write compressed SDS partially --- status = sdmodcompslab(sdsid, start, stride, int32 end, VOIDP data); ******************************************************************************/ #ifndef HDF #define HDF 1 #endif #include "local_nc.h" #include "h4support.h" /****************************************************************************** NAME read_entire_orig -- read the entire data of a compressed SDS DESCRIPTION This function is a helper to sdmodcompslab. It seems that there is a bug in the library that did not allow SDwritedata write to a compressed SDS if an SDreaddata is called before the SDwritedata, during the course of the SDS being opened. This function opens the file behind the scene so that SDreaddata will not affect the file being opened by user's application. This needs to be investigated to find the cause and maybe the fix. RETURNS SUCCEED / FAIL -BMR, 2012-12-28 ******************************************************************************/ intn read_entire_orig(int32 sdsid, /* IN: dataset ID */ int32 *start, /* IN: coords of starting point */ int32 *stride, /* IN: stride along each dimension */ int32 *edge, /* IN: number of values to write per dimension */ void * data /* IN: data buffer */) { CONSTR(FUNC, "read_entire_orig"); /* for HGOTO_ERROR */ NC *handle = NULL; NC_var *var, **dp; int32 tmpsd_id, tmpsds_id; int32 ref = 0, sds_index = 0; intn ii, found = FALSE; intn status; intn ret_value = SUCCEED; /* Clear error stack */ HEclear(); /* Get the NC_var */ handle = (NC *)SDIhandle_from_id(sdsid, SDSTYPE); if(handle == NULL) HGOTO_ERROR(DFE_ARGS, FAIL); if(handle->vars == NULL) HGOTO_ERROR(DFE_ARGS, FAIL); var = (NC_var *)SDIget_var(handle, sdsid); if(var == NULL) HGOTO_ERROR(DFE_ARGS, FAIL); /* Reference number of the SDS */ ref = (int32) var->ndg_ref; /* Searching for the ref in the NC_var list from the file, to determine the SDS' index */ dp = (NC_var**) handle->vars->values; for(ii = 0; ii < handle->vars->count && !found; ii++, dp++) { if((*dp)->ndg_ref == ref) { sds_index = ii; found = TRUE; } } /* If the SDS is not found, fail; it's not likely and if happens, it'll mean the application had passed in an invalid SDS id */ if (!found) HGOTO_ERROR(DFE_ARGS, FAIL); /* Open user's file again as a work-around the SDreaddata/SDwritedata problem mentioned above */ tmpsd_id = SDstart(handle->path, DFACC_RDWR); if (tmpsd_id == FAIL) HGOTO_ERROR(DFE_INTERNAL, FAIL); /* Open, read, and close user's SDS. This access doesn't affect user's access of the SDS. */ tmpsds_id = SDselect(tmpsd_id, sds_index); if (tmpsds_id == FAIL) HGOTO_ERROR(DFE_INTERNAL, FAIL); status = SDreaddata(tmpsds_id, start, stride, edge, data); if (status == FAIL) HGOTO_ERROR(DFE_INTERNAL, FAIL); status = SDendaccess(tmpsds_id); if (status == FAIL) HGOTO_ERROR(DFE_INTERNAL, FAIL); /* Close this access of the user's file */ status = SDend(tmpsd_id); if (status == FAIL) HGOTO_ERROR(DFE_INTERNAL, FAIL); done: if (ret_value == FAIL) { /* Failure cleanup */ } /* Normal cleanup */ return ret_value; } /****************************************************************************** NAME sdmodcompslab -- write a hyperslab data to a compressed data set DESCRIPTION Write out a chunk or chunks of data. This is a wrapper of several SD API functions to allow writing compressed data set partially. This function is planned to be revised to use internal existing code to improve efficiency significantly and then will be updated to be an SD API function. RETURNS SUCCEED / FAIL ******************************************************************************/ intn sdmodcompslab(int32 sdsid, /* IN: dataset ID */ int32 *start, /* IN: coords of starting point */ int32 *stride, /* IN: stride along each dimension */ int32 *end, /* IN: number of values to write per dimension */ void * data /* IN: data buffer */) { CONSTR(FUNC, "sdmodcompslab"); /* for HGOTO_ERROR */ intn varid, ii; int32 entire_size=0; int32 rank=0, nt=0; int32 status; int32 *dimsizes=NULL, *orig_start=NULL; int32 *orig_edges=NULL; void *orig_data=NULL; uint8 *read_datap=NULL; int32 tmpsd_id, tmpsds_id; char TEMPFILE_NAME[20] = "tempfile.hdf"; intn ret_value = SUCCEED; /* Get information of the sds to be modified */ /* Get rank */ status = SDgetinfo(sdsid, NULL, &rank, NULL, NULL, NULL); if (status == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); /* Use rank to allocate these arrays */ dimsizes = (int32 *) HDmalloc(rank); if (dimsizes == NULL) HGOTO_ERROR(DFE_NOSPACE, FAIL); orig_start = (int32 *) HDmalloc(rank); if (orig_start == NULL) HGOTO_ERROR(DFE_NOSPACE, FAIL); orig_edges = (int32 *) HDmalloc(rank); if (orig_edges == NULL) HGOTO_ERROR(DFE_NOSPACE, FAIL); /* Get the data set's dimension */ status = SDgetinfo(sdsid, NULL, NULL, dimsizes, &nt, NULL); if (status == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); /* Prepare to read the entire sds */ /* Initialize origin and sizes, and compute the total size */ entire_size = 1; for (ii = 0; ii < rank; ii++) { orig_start[ii] = 0; orig_edges[ii] = dimsizes[ii]; entire_size = entire_size * dimsizes[ii]; } /* Allocate buffer to read the entire sds if it is smaller than 1G. Disallow partially modifying a compressed sds with larger than 1Gb. */ entire_size = entire_size * DFKNTsize(nt); if (entire_size > H4_MAX_MOD_ALLOWED) HGOTO_ERROR(DFE_ARGS, FAIL); orig_data = (uint8 *) HDmalloc(entire_size); if (orig_data == NULL) HGOTO_ERROR(DFE_NOSPACE, FAIL); /* Read data from user's SDS */ status = read_entire_orig(sdsid, orig_start, NULL, orig_edges, orig_data); if (status == FAIL) { fprintf(stderr, "sdmodcompslab: unable to read original data\n"); goto done; } /* Create a temporary file, then create a replica of user's SDS, and write to it. */ tmpsd_id = SDstart(TEMPFILE_NAME, DFACC_CREATE); if (tmpsd_id == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); tmpsds_id = SDcreate(tmpsd_id, NULL, nt, rank, dimsizes); if (tmpsds_id == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); status = SDwritedata (tmpsds_id, orig_start, NULL, orig_edges, (VOIDP)orig_data); if (status == FAIL) HGOTO_ERROR(DFE_WRITEERROR, FAIL); /* Free the buffer of the original SDS data. */ HDfree(orig_data); orig_data = NULL; /* Write user's updated values to the temporary SDS. */ status = SDwritedata (tmpsds_id, start, stride, end, (VOIDP)data); if (status == FAIL) HGOTO_ERROR(DFE_WRITEERROR, FAIL); /* Close temporary data set to flush the data and re-open it */ status = SDendaccess(tmpsds_id); if (status == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); tmpsds_id = SDselect(tmpsd_id, 0); if (tmpsds_id == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); /* Read the temporary SDS data, which is now updated with user's data */ read_datap = (uint8 *) HDmalloc(entire_size); if (read_datap == NULL) HGOTO_ERROR(DFE_NOSPACE, FAIL); status = SDreaddata (tmpsds_id, orig_start, NULL, orig_edges, (VOIDP)read_datap); if (status == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); /* Done with this temporary SDS, close it and delete the temporary file */ status = SDendaccess(tmpsds_id); if (status == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); status = SDend(tmpsd_id); if (status == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); remove(TEMPFILE_NAME); /* Write updated uncompressed data to the compressed SDS */ status = SDwritedata (sdsid, orig_start, NULL, orig_edges, (VOIDP)read_datap); if (status == FAIL) HGOTO_ERROR(DFE_ARGS, FAIL); done: if (ret_value == FAIL) { /* Failure cleanup */ } /* Normal cleanup */ if (orig_data != NULL) HDfree(orig_data); if (read_datap != NULL) HDfree(read_datap); if (dimsizes != NULL) HDfree(dimsizes); if (orig_start != NULL) HDfree(orig_start); if (orig_edges != NULL) HDfree(orig_edges); return ret_value; } /* sdmodcompslab */