PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/applications/NXtranslate/nexus_util.cpp

https://github.com/Acidburn0zzz/code
C++ | 448 lines | 327 code | 69 blank | 52 comment | 78 complexity | e182744688435cbd71b3f08c22a5c4cc MD5 | raw file
Possible License(s): LGPL-2.1
  1. #include <iostream>
  2. #include <stdexcept>
  3. #include <string>
  4. #include <cstring>
  5. #include <cstdlib>
  6. #include <vector>
  7. #include "nexus_util.h"
  8. #include "string_util.h"
  9. #include "nxtranslate_debug.h"
  10. // ----- start of declaring debug levels
  11. #ifdef DEBUG3_NEXUS_UTIL
  12. #define DEBUG2_NEXUS_UTIL
  13. #endif
  14. #ifdef DEBUG2_NEXUS_UTIL
  15. #define DEBUG1_NEXUS_UTIL
  16. #endif
  17. // ----- end of declaring debug levels
  18. using std::invalid_argument;
  19. using std::runtime_error;
  20. using std::string;
  21. using std::vector;
  22. typedef struct{
  23. string name;
  24. string type;
  25. }SimpleNode;
  26. typedef vector<string> StringVec;
  27. typedef vector<SimpleNode> SimpleNodeVec;
  28. typedef tree<Node> TreeNode;
  29. static const int GROUP_STRING_LEN = 128;
  30. static const string NXROOT = "NXroot";
  31. static const string SDS = "SDS";
  32. static const string ATTR = "ATTR";
  33. static SimpleNodeVec get_groups(NXhandle *handle);
  34. static bool node_exists(NXhandle *handle, const Node &node){
  35. SimpleNodeVec groups=get_groups(handle);
  36. for(SimpleNodeVec::const_iterator group=groups.begin() ; group!=groups.end() ; group++ ){
  37. if(group->name==node.name()){
  38. if(group->type==node.type())
  39. return true;
  40. if(node.is_data() && group->type==SDS)
  41. return true;
  42. }
  43. }
  44. return false;
  45. }
  46. extern void nexus_util::open(NXhandle *handle, const Node &node){
  47. #ifdef DEBUG2_NEXUS_UTIL
  48. std::cout << "nexus_util::open(handle," << node.name() << ":" << node.type()
  49. << ")" << std::endl;
  50. #endif
  51. // do nothing with a root
  52. if(node.name()==NXROOT) return;
  53. // the name is needed by all "make" functions
  54. char name[GROUP_STRING_LEN];
  55. strcpy(name,node.name().c_str());
  56. bool existing_node=node_exists(handle,node);
  57. if(node.is_data()){
  58. if(!existing_node){
  59. int type=(int)node.int_type(); // get the type and cast as an int
  60. int rank=node.rank();
  61. if(rank<=0) return;
  62. int dims[NX_MAXRANK];
  63. { // copy the dimensions from the node
  64. vector<int> vec_dim=node.dims();
  65. for( int i=0 ; i<rank ; i++ )
  66. dims[i]=vec_dim[i];
  67. }
  68. // create the data
  69. int comp_type=node.compress_type();
  70. if(comp_type==Node::COMP_NONE){
  71. //std::cout << "in open: " << node.type() << " " << *(node.dims().begin()) << std::endl; // REMOVE
  72. if(NXmakedata(*handle,name,type,rank,dims)!=NX_OK){
  73. std::cout << "NXmakedata failed" << std::endl;
  74. throw runtime_error("NXmakedata failed");
  75. }
  76. }else{
  77. vector<int> buff_size_vec=node.comp_buffer_dims();
  78. int *buff_size=new int[rank];
  79. for( size_t i=0 ; i<rank ; i++ ){
  80. buff_size[i]=buff_size_vec[i];
  81. }
  82. buff_size[rank-1]=dims[rank-1];
  83. if(NXcompmakedata(*handle,name,type,rank,dims,comp_type,buff_size)!=NX_OK){
  84. std::cout << "NXcompmakedata failed" << std::endl;
  85. throw runtime_error("NXcompmakedata failed");
  86. }
  87. delete buff_size; // FIXME - is this the correct form?
  88. }
  89. }
  90. // open the data that was just created
  91. if(NXopendata(*handle,name)!=NX_OK)
  92. throw runtime_error("NXopendata failed");
  93. }else{
  94. char type[GROUP_STRING_LEN];
  95. strcpy(type,node.type().c_str());
  96. if(!existing_node)
  97. if(NXmakegroup(*handle,name,type)!=NX_OK)
  98. throw runtime_error("NXmakegroup failed");
  99. if(NXopengroup(*handle,name,type)!=NX_OK)
  100. throw runtime_error("NXopengroup failed");
  101. }
  102. }
  103. static void add_attribute(NXhandle *handle, const Node& node,
  104. const int attr_num){
  105. Attr attr=(node.get_attr(attr_num));
  106. char name[GROUP_STRING_LEN];
  107. strcpy(name,attr.name().c_str());
  108. if(NXputattr(*handle,name,attr.value(),attr.length(),attr.type())!=NX_OK)
  109. throw runtime_error("NXputattr failed");
  110. }
  111. extern void nexus_util::make_data(NXhandle *handle, const Node& node){
  112. //std::cout << "make(" << node.name() << ")" << std::endl; // REMOVE
  113. // do nothing with a root
  114. if(node.name()==NXROOT) return;
  115. // do nothing unless this is a data
  116. if(!node.is_data()) return;
  117. // put in the attributes
  118. for( int i=0 ; i<node.num_attr() ; i++ )
  119. add_attribute(handle,node,i);
  120. // put in the data
  121. void *data(NULL);
  122. node.copy_data(data);
  123. if(data==NULL)
  124. throw runtime_error("CANNOT ADD NULL DATA");// << std::endl;
  125. if(NXputdata(*handle,data)!=NX_OK)
  126. throw runtime_error("NXputdata failed");
  127. NXfree(&data);
  128. }
  129. static void recurse_make_data(NXhandle *handle, const TreeNode &tree, const TreeNode::sibling_iterator &begin, const TreeNode::sibling_iterator &end){
  130. using namespace nexus_util;
  131. for( TreeNode::sibling_iterator sib=begin ; sib!=end ; sib++ ){
  132. open(handle,*sib);
  133. if(sib->is_data())
  134. make_data(handle,*sib);
  135. else
  136. recurse_make_data(handle,tree,tree.begin(sib),tree.end(sib));
  137. close(handle,*sib);
  138. sib.skip_children();
  139. }
  140. }
  141. extern void nexus_util::make_data(NXhandle *handle, const TreeNode &tree){
  142. //std::cout << "make_data(handle,tree[" << tree.size() << "])" << std::endl; // REMOVE
  143. // check that the tree is not empty
  144. if(tree.size()<=0)
  145. throw invalid_argument("Cannot write empty tree to file");
  146. // recursively write out the tree
  147. for( TreeNode::iterator it=tree.begin() ; it!=tree.end() ; it++ ){
  148. open(handle,*it);
  149. if(it->is_data())
  150. make_data(handle,*it);
  151. else
  152. recurse_make_data(handle,tree,tree.begin(it),tree.end(it));
  153. close(handle,*it);
  154. it.skip_children();
  155. }
  156. }
  157. extern void nexus_util::close(NXhandle *handle, const Node &node){
  158. #ifdef DEBUG2_NEXUS_UTIL
  159. std::cout << "nexus_util::close(handle," << node.name() << ":"
  160. << node.type() << ")" << std::endl;
  161. #endif
  162. // do nothing with a root
  163. if(node.name()==NXROOT) return;
  164. if(node.is_data()){
  165. // check that there was something created
  166. if(node.rank()<=0) return;
  167. if(NXclosedata(*handle)!=NX_OK)
  168. throw runtime_error("NXclosedata failed");
  169. }else{
  170. if(NXclosegroup(*handle)!=NX_OK)
  171. throw runtime_error("NXclosegroup failed");
  172. }
  173. }
  174. static int num_group(NXhandle *handle){
  175. char group_name[GROUP_STRING_LEN];
  176. char group_class[GROUP_STRING_LEN];
  177. int num_groups;
  178. if(NXgetgroupinfo(*handle,&num_groups,group_name,group_class)!=NX_OK)
  179. throw runtime_error("NXgetgroupinfo failed");
  180. return num_groups;
  181. }
  182. static SimpleNode get_next_group(NXhandle *handle){
  183. //std::cout << "get_next_group(handle)" << std::endl;
  184. char name[GROUP_STRING_LEN], class_name[GROUP_STRING_LEN];
  185. int datatype;
  186. // get the information
  187. if(NXgetnextentry(*handle,name,class_name,&datatype)!=NX_OK)
  188. throw "NXgetnextentry failed";
  189. // copy it into the supplied node
  190. SimpleNode node;
  191. node.name=name;
  192. node.type=class_name;
  193. return node;
  194. }
  195. static bool node_is_okay(const SimpleNode& node){
  196. static const string UNKNOWN="UNKNOWN";
  197. if(node.name==UNKNOWN)
  198. return false;
  199. if(node.type==UNKNOWN)
  200. return false;
  201. if(node.type=="CDF0.0")
  202. return false;
  203. return true;
  204. }
  205. static SimpleNodeVec get_groups(NXhandle *handle){
  206. //std::cout << "get_groups(handle)" << std::endl; // REMOVE
  207. // reset the directory
  208. if(NXinitgroupdir(*handle)!=NX_OK)
  209. throw runtime_error("NXinitgroupdir failed");
  210. // determine the number of groups at the current location
  211. int num_groups = 0;
  212. try{
  213. num_groups=num_group(handle);
  214. }catch(runtime_error &e){
  215. // let it drop on the floor
  216. }
  217. // set up for the listing
  218. SimpleNodeVec result;
  219. if(num_groups<=0) return result;
  220. // get the listing
  221. SimpleNode node;
  222. for( int i=0 ; i<num_groups ; i++ ){
  223. node=get_next_group(handle);
  224. if(node_is_okay(node))
  225. result.push_back(node);
  226. }
  227. return result;
  228. }
  229. extern vector<string> nexus_util::get_list(NXhandle *handle){
  230. SimpleNodeVec vec=get_groups(handle);
  231. vector<string> result;
  232. for( SimpleNodeVec::const_iterator it=vec.begin() ; it!=vec.end() ; it++ ){
  233. result.push_back(it->name);
  234. result.push_back(it->type);
  235. }
  236. return result;
  237. }
  238. static string get_type(NXhandle *handle, const string &name){
  239. SimpleNodeVec groups=get_groups(handle);
  240. for(SimpleNodeVec::const_iterator group=groups.begin() ; group!=groups.end() ; group++ ){
  241. if(group->name==name)
  242. return group->type;
  243. }
  244. return "";
  245. }
  246. static void open_node(NXhandle *handle, const string &name, const string &type, int &num_group, int &num_data){
  247. // do nothing for attributes
  248. if(type==ATTR)
  249. return;
  250. // everything else needs a name
  251. char ch_name[GROUP_STRING_LEN];
  252. strcpy(ch_name,name.c_str());
  253. // open a data if appropriate
  254. if(type==SDS){
  255. if(NXopendata(*handle,ch_name)!=NX_OK)
  256. throw runtime_error("NXopendata failed");
  257. num_data++;
  258. return;
  259. }
  260. // open the group
  261. char ch_type[GROUP_STRING_LEN];
  262. strcpy(ch_type,type.c_str());
  263. if(NXopengroup(*handle,ch_name,ch_type)!=NX_OK)
  264. throw runtime_error("NXopengroup failed");
  265. num_group++;
  266. }
  267. extern string nexus_util::open(NXhandle *handle, const string &name){
  268. string type=get_type(handle,name);
  269. if(type.size()<=0)
  270. throw runtime_error(string("could not find type for node[")+name+"]");
  271. int num_group=0;
  272. int num_data=0;
  273. open_node(handle,name,type,num_group,num_data);
  274. return type;
  275. }
  276. static string path_to_str(const StringVec &path){
  277. string str="";
  278. for( StringVec::const_iterator it=path.begin() ; it!=path.end() ; it++ )
  279. str+=("/"+*it);
  280. return str;
  281. }
  282. extern void nexus_util::open_path(NXhandle *handle, const StringVec &path, int &num_group, int &num_data){
  283. #ifdef DEBUG1_NEXUS_UTIL
  284. std::cout << "open_path(" << handle << ",";
  285. for( StringVec::const_iterator it=path.begin() ; it!=path.end() ; it++ )
  286. std::cout << "/" << *it;
  287. std::cout << "," << num_group << "," << num_data << ")" << std::endl;
  288. #endif
  289. for( StringVec::const_iterator it=path.begin() ; it!=path.end() ; it++ ){
  290. string type=get_type(handle,*it);
  291. if(type.size()<=0){
  292. close_path(handle,num_group,num_data);
  293. throw runtime_error("Path ["+path_to_str(path)+"] did not exist");
  294. }
  295. try{
  296. open_node(handle,*it,type,num_group,num_data);
  297. }catch(runtime_error &e){
  298. throw runtime_error("Could not open path ["+path_to_str(path)+"]");
  299. }
  300. }
  301. }
  302. extern void nexus_util::close_path(NXhandle *handle, int &num_group, int &num_data){
  303. #ifdef DEBUG1_NEXUS_UTIL
  304. std::cout << "close_path(" << handle << "," << num_group << ","
  305. << num_data << ")" << std::endl;
  306. #endif
  307. if( (num_group<=0) && (num_data<=0) ){
  308. num_group=0;
  309. num_data=0;
  310. return;
  311. }
  312. if(num_data){
  313. if(NXclosedata(*handle)!=NX_OK)
  314. throw runtime_error("NXclosedata failed");
  315. num_data--;
  316. }
  317. for( ; num_group>0 ; num_group-- ){
  318. if(NXclosegroup(*handle)!=NX_OK)
  319. throw runtime_error("NXclosegroup failed");
  320. }
  321. }
  322. extern size_t nexus_util::calc_size(int rank, int *dims, int type){
  323. // check that the rank is reasonable
  324. if(rank<=0) throw invalid_argument("Do not understand rank<=0");
  325. // determine how much to copy
  326. size_t size=1;
  327. for( int i=0 ; i<rank ; i++ )
  328. size*=dims[i];
  329. if(type==NX_CHAR || type==NX_INT8 || type==NX_UINT8){
  330. // size is already correct
  331. }else if(type==NX_INT16 || type==NX_UINT16){
  332. size*=2;
  333. }else if(type==NX_INT32 || type==NX_UINT32 || type==NX_FLOAT32){
  334. size*=4;
  335. }else if(type==NX_FLOAT64 || type==NX_UINT64 || type==NX_INT64){
  336. size*=8;
  337. }else{
  338. throw invalid_argument("Did not understand type in nexus_util::calc_size");
  339. }
  340. return size;
  341. }
  342. extern void nexus_util::make_link(NXhandle *handle, const vector<string> &link, const vector<string> &source){
  343. /*
  344. // ********** begin debug print
  345. std::cout << "LINKING ";
  346. for( vector<string>::const_iterator it=link.begin() ; it!=link.end() ; it++ )
  347. std::cout << "/" << *it;
  348. std::cout << " -> ";
  349. for( vector<string>::const_iterator it=source.begin() ; it!=source.end() ; it++ )
  350. std::cout << "/" << *it;
  351. std::cout << std::endl;
  352. // ********** end debug print
  353. */
  354. // keep track of location in file
  355. NXlink *link_id=(NXlink *)malloc(sizeof(NXlink));
  356. int num_group=0;
  357. int num_data=0;
  358. // open the path to the source
  359. nexus_util::open_path(handle,source,num_group,num_data);
  360. // get the link_id
  361. if(num_data>0){
  362. if(NXgetdataID(*handle,link_id)!=NX_OK)
  363. throw new runtime_error("could not get data ID for linking");
  364. }else{
  365. if(NXgetgroupID(*handle,link_id)!=NX_OK)
  366. throw new runtime_error("could not get group ID for linking");
  367. }
  368. // return to the root node in the file
  369. nexus_util::close_path(handle,num_group,num_data);
  370. // open to link's parent location
  371. nexus_util::open_path(handle,link,num_group,num_data);
  372. // create the link
  373. if(NXmakelink(*handle,link_id)!=NX_OK)
  374. throw new runtime_error("could not create link");
  375. // return to the root node in the file
  376. nexus_util::close_path(handle,num_group,num_data);
  377. // free up the NXlink variable
  378. free(link_id);
  379. }