// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef toolx_hdf5_tools #define toolx_hdf5_tools #include "hdf5_h" #include namespace toolx { namespace hdf5 { inline bool check_sizes(){ if(sizeof(bool)!=1) return false; if(sizeof(char)!=1) return false; if(sizeof(short)!=2) return false; if(sizeof(int)!=4) return false; if(sizeof(float)!=4) return false; if(sizeof(double)!=8) return false; return true; } inline int failure() {return -1;} inline hid_t string_datatype(size_t aSize){ // aSize should include the trailing null char. hid_t datatype = ::H5Tcopy(H5T_C_S1); if(datatype<0) return failure(); if(::H5Tset_size(datatype,aSize)<0) { ::H5Tclose(datatype); return failure(); } if(::H5Tset_strpad(datatype,H5T_STR_NULLTERM)<0) { ::H5Tclose(datatype); return failure(); } return datatype; } inline hid_t str_datatype() { hid_t datatype = ::H5Tcopy(H5T_C_S1); if(datatype<0) return failure(); if(::H5Tset_size(datatype,H5T_VARIABLE)<0) { ::H5Tclose(datatype); return failure(); } if(::H5Tset_strpad(datatype,H5T_STR_NULLTERM)<0) { ::H5Tclose(datatype); return failure(); } return datatype; } inline hid_t basic_mem_type(hid_t a_file_type){ H5T_class_t mclass = H5Tget_class(a_file_type); size_t msize = H5Tget_size(a_file_type); if(mclass==H5T_INTEGER) { H5T_sign_t msign = H5Tget_sign(a_file_type); if(msize==1) { if(msign==H5T_SGN_NONE) { return H5Tcopy(H5T_NATIVE_UCHAR); } else { return H5Tcopy(H5T_NATIVE_CHAR); } } else if(msize==4) { if(msign==H5T_SGN_NONE) { return H5Tcopy(H5T_NATIVE_UINT); } else { return H5Tcopy(H5T_NATIVE_INT); } } else if(msize==8) { //for osc_file::header::fDate. if(msign==H5T_SGN_NONE) { return H5Tcopy(H5T_NATIVE_UINT64); } else { return H5Tcopy(H5T_NATIVE_INT64); } } else { return failure(); } } else if(mclass==H5T_FLOAT) { if(msize==4) { return H5Tcopy(H5T_NATIVE_FLOAT); } else if(msize==8) { return H5Tcopy(H5T_NATIVE_DOUBLE); } else { return failure(); } } else if(mclass==H5T_STRING) { return H5Tcopy(a_file_type); } return failure(); } }} #include namespace toolx { namespace hdf5 { inline hid_t compound_mem_type(hid_t a_file_type){ // FIXME : In principle H5T_get_native_type should do the job but it crashes. H5T_class_t t_class = H5Tget_class(a_file_type); if(t_class!=H5T_COMPOUND) return failure(); size_t sz = H5Tget_size(a_file_type); hid_t mem_type = ::H5Tcreate(H5T_COMPOUND,sz); if(mem_type<0) return failure(); //FIXME : WARNING : is order the booked order ? int mn = H5Tget_nmembers(a_file_type); std::vector szs(mn); for(int index=0;index namespace toolx { namespace hdf5 { inline bool read_atb(hid_t a_id,const std::string& a_name,std::string& a_data,unsigned int aSize = 100){ // From H5LT.c/H5LTget_attribute_string. if(!H5LT_find_attribute(a_id,a_name.c_str())) {a_data.clear();return false;} char* b = new char[aSize]; if(H5LT_get_attribute_disk(a_id,a_name.c_str(),b)<0) { delete [] b; a_data.clear(); return false; } a_data = std::string(b); delete [] b; return true; } inline bool read_atb(hid_t a_id,const std::string& a_name,unsigned int& a_data){ if(!H5LT_find_attribute(a_id,a_name.c_str())) {a_data=0;return false;} if(H5LT_get_attribute_mem(a_id,a_name.c_str(),H5T_NATIVE_UINT,&a_data)<0) {a_data=0;return false;} return true; } inline bool read_atb(hid_t a_id,const std::string& a_name,int& a_data){ if(!H5LT_find_attribute(a_id,a_name.c_str())) {a_data=0;return false;} if(H5LT_get_attribute_mem(a_id,a_name.c_str(),H5T_NATIVE_INT,&a_data)<0) {a_data=0;return false;} return true; } inline hid_t H5T_STD_U8XX() {return H5T_STD_U8LE;} inline hid_t H5T_STD_U32XX() {return H5T_STD_U32LE;} inline hid_t H5T_STD_U64XX() {return H5T_STD_U64LE;} inline hid_t H5T_STD_I8XX() {return H5T_STD_I8LE;} inline hid_t H5T_STD_I16XX() {return H5T_STD_I16LE;} inline hid_t H5T_STD_I32XX() {return H5T_STD_I32LE;} inline hid_t H5T_STD_I64XX() {return H5T_STD_I64LE;} inline hid_t H5T_IEEE_F32XX() {return H5T_IEEE_F32LE;} inline hid_t H5T_IEEE_F64XX() {return H5T_IEEE_F64LE;} inline bool dataset_vec_size(hid_t a_loc,const std::string& a_name,hsize_t& a_size) { hid_t dataset = toolx_H5Dopen(a_loc,a_name.c_str()); if(dataset<0) { a_size = 0; return false; // data set not found. } hid_t file_space = H5Dget_space(dataset); if(file_space<0) { ::H5Dclose(dataset); a_size = 0; return false; } int dimn = H5Sget_simple_extent_ndims(file_space); if(dimn<0) { ::H5Sclose(file_space); ::H5Dclose(dataset); a_size = 0; return false; } if(dimn!=1) { ::H5Sclose(file_space); ::H5Dclose(dataset); a_size = 0; return false; } hsize_t dims[1]; {if(H5Sget_simple_extent_dims(file_space,dims,NULL)<0) { ::H5Sclose(file_space); ::H5Dclose(dataset); a_size = 0; return false; }} ::H5Sclose(file_space); ::H5Dclose(dataset); a_size = dims[0]; return true; } inline bool write_atb(hid_t a_id,const std::string& a_name,const std::string& a_data){ // From H5LT.c/H5LTset_attribute_string. int has_attr = H5LT_find_attribute(a_id,a_name.c_str()); if(has_attr==1) { if(H5Adelete(a_id,a_name.c_str())<0) return false; } hid_t datatype = string_datatype(a_data.size()+1); if(datatype<0) return false; hid_t scalar = ::H5Screate(H5S_SCALAR); if(scalar<0) { ::H5Tclose(datatype); return false; } hid_t aid = toolx_H5Acreate(a_id,a_name.c_str(),datatype,scalar,H5P_DEFAULT); if(aid<0) { ::H5Sclose(scalar); ::H5Tclose(datatype); return false; } if(H5Awrite(aid,datatype,a_data.c_str())<0) { ::H5Aclose(aid); ::H5Sclose(scalar); ::H5Tclose(datatype); return false; } ::H5Aclose(aid); ::H5Sclose(scalar); ::H5Tclose(datatype); return true; } inline bool write_bool(hid_t a_loc,const std::string& a_name,bool a_data) { hid_t scalar = ::H5Screate(H5S_SCALAR); if(scalar<0) return false; hid_t compact = ::H5Pcreate(H5P_DATASET_CREATE); if(compact<0) { ::H5Sclose(scalar); return false; } if(H5Pset_layout(compact,H5D_COMPACT)<0) { ::H5Pclose(compact); ::H5Sclose(scalar); return false; } hid_t dataset = toolx_H5Dcreate(a_loc,a_name.c_str(),H5T_STD_U8XX(),scalar,compact); if(dataset<0) { ::H5Pclose(compact); ::H5Sclose(scalar); return false; } unsigned char data = a_data?1:0; if(::H5Dwrite(dataset,H5T_NATIVE_UCHAR,H5S_ALL,H5S_ALL,H5P_DEFAULT,&data)<0) { ::H5Pclose(compact); ::H5Sclose(scalar); ::H5Dclose(dataset); return false; } ::H5Pclose(compact); ::H5Sclose(scalar); ::H5Dclose(dataset); return true; } inline bool write_string(hid_t a_loc,const std::string& a_name,const std::string& a_string) { hid_t scalar = ::H5Screate(H5S_SCALAR); if(scalar<0) return false; hid_t compact = ::H5Pcreate(H5P_DATASET_CREATE); if(compact<0) { ::H5Sclose(scalar); return false; } if(H5Pset_layout(compact,H5D_COMPACT)<0) { ::H5Pclose(compact); ::H5Sclose(scalar); return false; } // From H5LTmakge_dataset_string. hid_t file_type = string_datatype(a_string.size()+1); if(file_type<0) { ::H5Pclose(compact); ::H5Sclose(scalar); return false; } hid_t dataset = toolx_H5Dcreate(a_loc,a_name.c_str(),file_type,scalar,compact); if(dataset<0) { ::H5Pclose(compact); ::H5Sclose(scalar); ::H5Tclose(file_type); return false; } hid_t mem_type = file_type; if(H5Dwrite(dataset,mem_type,H5S_ALL,H5S_ALL,H5P_DEFAULT,a_string.c_str())<0) { ::H5Pclose(compact); ::H5Sclose(scalar); ::H5Dclose(dataset); ::H5Tclose(file_type); return false; } ::H5Pclose(compact); ::H5Sclose(scalar); ::H5Dclose(dataset); ::H5Tclose(file_type); return true; } inline bool write_string_dataset(hid_t a_loc,const std::string& a_name, unsigned int a_chunked,unsigned int a_compress, const std::string& a_string) { hid_t cpt = -1; if(a_compress || a_chunked) { cpt = ::H5Pcreate(H5P_DATASET_CREATE); if(cpt<0) return false; if(a_chunked) { if(H5Pset_layout(cpt,H5D_CHUNKED)<0) { ::H5Pclose(cpt); return false; } hsize_t cdims[1]; cdims[0] = a_chunked; if(H5Pset_chunk(cpt,1,cdims)<0) { ::H5Pclose(cpt); return false; } } else { if(H5Pset_layout(cpt,H5D_COMPACT)<0) { ::H5Pclose(cpt); return false; } } if(a_compress) { if(H5Pset_deflate(cpt,a_compress>9?9:a_compress)<0) { ::H5Pclose(cpt); return false; } } } else { cpt = H5P_DEFAULT; } hid_t file_type = str_datatype(); //first input => H5T_VARIABLE. if(file_type<0) { if(cpt>=0) ::H5Pclose(cpt); return false; } hid_t file_space = -1; {hsize_t dims[1]; dims[0] = 1; if(a_chunked) { hsize_t mx_dims[1]; mx_dims[0] = H5S_UNLIMITED; //extendable. file_space = ::H5Screate_simple(1,dims,mx_dims); } else { file_space = ::H5Screate_simple(1,dims,NULL); } if(file_space<0) {if(cpt>=0) ::H5Pclose(cpt);::H5Tclose(file_type);return false;}} hid_t dataset = toolx_H5Dcreate(a_loc,a_name.c_str(),file_type,file_space,cpt); if(cpt>=0) ::H5Pclose(cpt); ::H5Sclose(file_space); if(dataset<0) { ::H5Tclose(file_type); return false; } hid_t mem_type = file_type; const char* wdata[1]; wdata[0] = a_string.c_str(); if(H5Dwrite(dataset,mem_type,H5S_ALL,H5S_ALL,H5P_DEFAULT,wdata)<0) { ::H5Dclose(dataset); ::H5Tclose(file_type); return false; } ::H5Tclose(file_type); ::H5Dclose(dataset); return true; } inline bool write_string_dataset(hid_t a_loc,const std::string& a_name, const std::string& a_string, unsigned int a_chunked = 0,unsigned int a_compress = 0) { return hdf5::write_string_dataset(a_loc,a_name,a_chunked,a_compress,a_string); } inline bool write_append_string_dataset(hid_t a_dataset,const std::string& a_string) { hsize_t old_size = 0; {hid_t dataspace = H5Dget_space(a_dataset); if(dataspace<0) return false; hsize_t dims[1]; if(H5Sget_simple_extent_dims(dataspace,dims,NULL)<0) { ::H5Sclose(dataspace); return false; } old_size = dims[0]; ::H5Sclose(dataspace);} {hsize_t exts[1]; exts[0] = old_size+1; if(H5Dset_extent(a_dataset,exts)<0) return false;} hid_t file_space = H5Dget_space(a_dataset); if(file_space<0) return false; {hsize_t offset[1]; offset[0] = old_size; hsize_t count[1]; count[0] = 1; if(H5Sselect_hyperslab(file_space,H5S_SELECT_SET,offset,NULL,count,NULL)<0) { ::H5Sclose(file_space); return false; }} hsize_t dims[1]; dims[0] = 1; hid_t mem_space = ::H5Screate_simple(1,dims,NULL); if(mem_space<0) { ::H5Sclose(file_space); return false; } hid_t mem_type = str_datatype(); if(mem_type<0) { ::H5Sclose(mem_space); ::H5Sclose(file_space); return false; } const char* wdata[1]; wdata[0] = a_string.c_str(); if(H5Dwrite(a_dataset,mem_type,mem_space,file_space,H5P_DEFAULT,wdata)<0) { ::H5Tclose(mem_type); ::H5Sclose(mem_space); ::H5Sclose(file_space); return false; } ::H5Tclose(mem_type); ::H5Sclose(mem_space); ::H5Sclose(file_space); return true; } }} #include namespace toolx { namespace hdf5 { inline bool write_array_string(hid_t a_loc,const std::string& a_name,const std::vector& a_array) { hid_t scalar = ::H5Screate(H5S_SCALAR); if(scalar<0) return false; // From H5LTmake_dataset_string. size_t sz; char* buffer; if(!tools::strings2buf(a_array,sz,buffer)) { ::H5Sclose(scalar); return false; } hid_t file_type = string_datatype(sz); if(file_type<0) { delete [] buffer; ::H5Sclose(scalar); return false; } hid_t dataset = toolx_H5Dcreate(a_loc,a_name.c_str(),file_type,scalar,H5P_DEFAULT); if(dataset<0) { delete [] buffer; ::H5Tclose(file_type); ::H5Sclose(scalar); return false; } hid_t mem_type = file_type; if(H5Dwrite(dataset,mem_type,H5S_ALL,H5S_ALL,H5P_DEFAULT,buffer)<0) { delete [] buffer; ::H5Dclose(dataset); ::H5Tclose(file_type); ::H5Sclose(scalar); return false; } delete [] buffer; ::H5Dclose(dataset); ::H5Tclose(file_type); ::H5Sclose(scalar); return true; } inline bool write_object(hid_t a_loc,const std::string& a_name,hid_t a_file_type,char* a_data) { unsigned int chunked = 0; unsigned int compress = 0; hid_t cpt = -1; if(compress || chunked) { cpt = ::H5Pcreate(H5P_DATASET_CREATE); if(cpt<0) return false; if(chunked) { if(H5Pset_layout(cpt,H5D_CHUNKED)<0) { ::H5Pclose(cpt); return false; } hsize_t cdims[1]; cdims[0] = chunked; if(H5Pset_chunk(cpt,1,cdims)<0) { ::H5Pclose(cpt); return false; } } else { if(H5Pset_layout(cpt,H5D_COMPACT)<0) { ::H5Pclose(cpt); return false; } } if(compress) { if(H5Pset_deflate(cpt,compress>9?9:compress)<0) { ::H5Pclose(cpt); return false; } } } else { cpt = H5P_DEFAULT; } hsize_t dims[1]; dims[0] = 1; hid_t simple = ::H5Screate_simple(1,dims,NULL); if(simple<0) { if(cpt>=0) ::H5Pclose(cpt); return false; } hid_t mem_type = compound_mem_type(a_file_type); if(mem_type<0) { ::H5Sclose(simple); if(cpt>=0) ::H5Pclose(cpt); return false; } hid_t dataset = toolx_H5Dcreate(a_loc,a_name.c_str(),a_file_type,simple,cpt); if(dataset<0) { ::H5Tclose(mem_type); ::H5Sclose(simple); if(cpt>=0) ::H5Pclose(cpt); return false; } if(H5Dwrite(dataset,mem_type,H5S_ALL,H5S_ALL,H5P_DEFAULT,a_data)<0) { ::H5Dclose(dataset); ::H5Tclose(mem_type); ::H5Sclose(simple); if(cpt>=0) ::H5Pclose(cpt); return false; } ::H5Dclose(dataset); ::H5Tclose(mem_type); ::H5Sclose(simple); if(cpt>=0) ::H5Pclose(cpt); return true; } inline bool read_string(hid_t a_loc,const std::string& a_name,std::string& a_string) { // From H5LTread_dataset_string. hid_t dataset = toolx_H5Dopen(a_loc,a_name.c_str()); if(dataset<0) { a_string.clear(); return false; // data set not found. } hid_t file_type = H5Dget_type(dataset); if(file_type<0) { ::H5Dclose(dataset); a_string.clear(); return false; } H5T_class_t t_class = H5Tget_class(file_type); if(t_class!=H5T_STRING) { ::H5Tclose(file_type); ::H5Dclose(dataset); a_string.clear(); return false; } size_t sz = H5Tget_size(file_type); ::H5Tclose(file_type); if(!sz) { ::H5Dclose(dataset); a_string.clear(); return false; } // We could have use file_type since, for string, // file type is the same than memory type. hid_t mem_type = string_datatype(sz); if(mem_type<0) { ::H5Dclose(dataset); a_string.clear(); return false; } char* buff = new char[sz]; herr_t stat = H5Dread(dataset,mem_type,H5S_ALL,H5S_ALL,H5P_DEFAULT,buff); ::H5Tclose(mem_type); ::H5Dclose(dataset); if(stat<0) { delete [] buff; a_string.clear(); return false; } size_t len = sz-1; a_string.resize(len,0); for(size_t index=0;index& a_array) { a_array.clear(); hid_t dataset = toolx_H5Dopen(a_loc,a_name.c_str()); if(dataset<0) return false; hid_t file_type = H5Dget_type(dataset); if(file_type<0) { ::H5Dclose(dataset); return false; } H5T_class_t t_class = H5Tget_class(file_type); if(t_class!=H5T_STRING) { ::H5Tclose(file_type); ::H5Dclose(dataset); return false; } size_t sz = H5Tget_size(file_type); ::H5Tclose(file_type); if(!sz) { ::H5Dclose(dataset); return false; } // We could have use file_type since, for string, // file type is the same than memory type. hid_t mem_type = string_datatype(sz); if(mem_type<0) { ::H5Dclose(dataset); return false; } char* buffer = new char[sz]; herr_t stat = H5Dread(dataset,mem_type,H5S_ALL,H5S_ALL,H5P_DEFAULT,buffer); ::H5Tclose(mem_type); ::H5Dclose(dataset); if(stat<0) { delete [] buffer; return false; } if(!tools::buf2strings(sz,buffer,a_array)) { delete [] buffer; return false; } delete [] buffer; return true; } }} #endif