1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15 
16 #include "H5Group.hxx"
17 #include "H5File.hxx"
18 #include "H5SoftLinksList.hxx"
19 #include "H5GroupsList.hxx"
20 #include "H5DatasetsList.hxx"
21 #include "H5TypesList.hxx"
22 #include "H5Link.hxx"
23 #include "H5BasicData.hxx"
24 
25 namespace org_modules_hdf5
26 {
27 
init()28 void H5Group::init()
29 {
30     group = H5Gopen(getParent().getH5Id(), name.c_str(), H5P_DEFAULT);
31     if (group < 0)
32     {
33         throw H5Exception(__LINE__, __FILE__, _("Cannot open the group %s."), name.c_str());
34     }
35 }
36 
H5Group(H5Object & _parent,const std::string & _name)37 H5Group::H5Group(H5Object & _parent, const std::string & _name) : H5Object(_parent, _name)
38 {
39     init();
40 }
41 
H5Group(H5Object & _parent,hid_t _group,const std::string & _name)42 H5Group::H5Group(H5Object & _parent, hid_t _group, const std::string & _name) : H5Object(_parent, _name), group(_group)
43 {
44 
45 }
46 
~H5Group()47 H5Group::~H5Group()
48 {
49     if (group >= 0)
50     {
51         H5Gclose(group);
52     }
53 }
54 
getSoftLinks()55 H5NamedObjectsList<H5SoftLink> & H5Group::getSoftLinks()
56 {
57     return *new H5NamedObjectsList<H5SoftLink>(*this, -1, H5L_TYPE_SOFT, "Soft Link");
58 }
59 
getExternalLinks()60 H5NamedObjectsList<H5ExternalLink> & H5Group::getExternalLinks()
61 {
62     return *new H5NamedObjectsList<H5ExternalLink>(*this, -1, H5L_TYPE_EXTERNAL, "External Link");
63 }
64 
getGroups()65 H5GroupsList & H5Group::getGroups()
66 {
67     return *new H5GroupsList(*this);
68 }
69 
getHardGroups()70 H5NamedObjectsList<H5Group> & H5Group::getHardGroups()
71 {
72     return *new H5NamedObjectsList<H5Group>(*this, H5O_TYPE_GROUP, H5L_TYPE_HARD, "Group");
73 }
74 
getHardTypes()75 H5NamedObjectsList<H5Type> & H5Group::getHardTypes()
76 {
77     return *new H5NamedObjectsList<H5Type>(*this, H5O_TYPE_NAMED_DATATYPE, H5L_TYPE_HARD, "Type");
78 }
79 
getHardDatasets()80 H5NamedObjectsList<H5Dataset> & H5Group::getHardDatasets()
81 {
82     return *new H5NamedObjectsList<H5Dataset>(*this, H5O_TYPE_DATASET, H5L_TYPE_HARD, "Dataset");
83 }
84 
getDatasets()85 H5DatasetsList & H5Group::getDatasets()
86 {
87     return *new H5DatasetsList(*this);
88 }
89 
getTypes()90 H5TypesList & H5Group::getTypes()
91 {
92     return *new H5TypesList(*this);
93 }
94 
getLinksSize() const95 unsigned int H5Group::getLinksSize() const
96 {
97     herr_t err;
98     H5G_info_t info;
99 
100     err = H5Gget_info(group, &info);
101     if (err < 0)
102     {
103         throw H5Exception(__LINE__, __FILE__, _("Cannot get the links number"));
104     }
105 
106     return (unsigned int)info.nlinks;
107 }
108 
getCompletePath() const109 std::string H5Group::getCompletePath() const
110 {
111     std::string name = getName();
112     if (name == "/")
113     {
114         return "/";
115     }
116 
117     return H5Object::getCompletePath();
118 }
119 
getAccessibleAttribute(const std::string & _name,const int pos,void * pvApiCtx) const120 void H5Group::getAccessibleAttribute(const std::string & _name, const int pos, void * pvApiCtx) const
121 {
122     SciErr err;
123     std::string lower(_name);
124 
125     std::transform(_name.begin(), _name.end(), lower.begin(), tolower);
126 
127     if (lower == "attributes")
128     {
129         std::vector<std::string> names;
130         getNames(*this, names, ATTRIBUTE);
131         H5BasicData<char>::putStringVectorOnStack(names, (int)names.size(), 1, pos, pvApiCtx);
132 
133         return;
134     }
135     else if (lower == "groups")
136     {
137         std::vector<std::string> names;
138         getNames(*this, names, GROUP);
139         H5BasicData<char>::putStringVectorOnStack(names, (int)names.size(), 1, pos, pvApiCtx);
140 
141         return;
142     }
143     else if (lower == "datasets")
144     {
145         std::vector<std::string> names;
146         getNames(*this, names, DATASET);
147         H5BasicData<char>::putStringVectorOnStack(names, (int)names.size(), 1, pos, pvApiCtx);
148 
149         return;
150     }
151     else if (lower == "types")
152     {
153         std::vector<std::string> names;
154         getNames(*this, names, TYPE);
155         H5BasicData<char>::putStringVectorOnStack(names, (int)names.size(), 1, pos, pvApiCtx);
156 
157         return;
158     }
159     else if (lower == "externals")
160     {
161         std::vector<std::string> names;
162         getNames(*this, names, EXTERNAL);
163         H5BasicData<char>::putStringVectorOnStack(names, (int)names.size(), 1, pos, pvApiCtx);
164 
165         return;
166     }
167     else if (lower == "softs")
168     {
169         std::vector<std::string> names;
170         getNames(*this, names, SOFT);
171         H5BasicData<char>::putStringVectorOnStack(names, (int)names.size(), 1, pos, pvApiCtx);
172 
173         return;
174     }
175     else if (lower == "danglings")
176     {
177         std::vector<std::string> names;
178         getNames(*this, names, DANGLING);
179         H5BasicData<char>::putStringVectorOnStack(names, (int)names.size(), 1, pos, pvApiCtx);
180 
181         return;
182     }
183     else if (lower == "hards")
184     {
185         std::vector<std::string> names;
186         getNames(*this, names, HARD);
187         H5BasicData<char>::putStringVectorOnStack(names, (int)names.size(), 1, pos, pvApiCtx);
188 
189         return;
190     }
191     else if (lower == "links")
192     {
193         std::vector<std::string> names;
194         std::vector<std::string> types;
195         std::vector<std::string> linkstype;
196         std::vector<const char *> _str;
197         H5Object::getLinksInfo(*this, names, types, linkstype);
198         _str.reserve(names.size() * 3);
199 
200         for (unsigned int i = 0; i < names.size(); i++)
201         {
202             _str.push_back(names[i].c_str());
203         }
204         for (unsigned int i = 0; i < names.size(); i++)
205         {
206             _str.push_back(linkstype[i].c_str());
207         }
208         for (unsigned int i = 0; i < names.size(); i++)
209         {
210             _str.push_back(types[i].c_str());
211         }
212 
213         err = createMatrixOfString(pvApiCtx, pos, (int)names.size(), 3, &(_str[0]));
214         if (err.iErr)
215         {
216             throw H5Exception(__LINE__, __FILE__, _("Cannot create a column of strings on the stack."));
217         }
218 
219         return;
220     }
221     else
222     {
223         try
224         {
225             H5Object & obj = H5Object::getObject(*const_cast<H5Group *>(this), _name);
226             obj.createOnScilabStack(pos, pvApiCtx);
227             return;
228         }
229         catch (const H5Exception & /*e*/) { }
230     }
231 
232     H5Object::getAccessibleAttribute(_name, pos, pvApiCtx);
233 }
234 
ls(std::vector<std::string> & name,std::vector<std::string> & type) const235 void H5Group::ls(std::vector<std::string> & name, std::vector<std::string> & type) const
236 {
237     herr_t err;
238     OpDataGetLs opdata(const_cast<H5Group *>(this), &name, &type);
239     hsize_t idx = 0;
240 
241     err = H5Literate(group, H5_INDEX_NAME, H5_ITER_INC, &idx, getLsInfo, &opdata);
242     if (err < 0)
243     {
244         throw H5Exception(__LINE__, __FILE__, _("Cannot list group links."));
245     }
246 
247     idx = 0;
248     err = H5Aiterate(group, H5_INDEX_NAME, H5_ITER_INC, &idx, H5Object::getLsAttributes, &opdata);
249     if (err < 0)
250     {
251         throw H5Exception(__LINE__, __FILE__, _("Cannot list group attributes."));
252     }
253 }
254 
getLsInfo(hid_t g_id,const char * name,const H5L_info_t * info,void * op_data)255 herr_t H5Group::getLsInfo(hid_t g_id, const char * name, const H5L_info_t * info, void * op_data)
256 {
257     H5O_info_t oinfo;
258     herr_t err;
259     hid_t obj;
260     OpDataGetLs & opdata = *(OpDataGetLs *)op_data;
261 
262     switch (info->type)
263     {
264         case H5L_TYPE_SOFT:
265             opdata.name->push_back(name);
266             opdata.type->push_back("soft");
267             break;
268         case H5L_TYPE_EXTERNAL:
269             opdata.name->push_back(name);
270             opdata.type->push_back("external");
271             break;
272         case H5L_TYPE_HARD:
273             obj = H5Oopen_by_addr(g_id, info->u.address);
274             if (obj < 0)
275             {
276                 return (herr_t) - 1;
277             }
278 
279             err = H5Oget_info(obj, &oinfo);
280             H5Oclose(obj);
281             if (err < 0)
282             {
283                 return (herr_t) - 1;
284             }
285 
286             switch (oinfo.type)
287             {
288                 case H5O_TYPE_GROUP:
289                     opdata.name->push_back(name);
290                     opdata.type->push_back("group");
291                     break;
292                 case H5O_TYPE_DATASET:
293                     opdata.name->push_back(name);
294                     opdata.type->push_back("dataset");
295                     break;
296                 case H5O_TYPE_NAMED_DATATYPE:
297                     opdata.name->push_back(name);
298                     opdata.type->push_back("type");
299                     break;
300                 default:
301                     return (herr_t) - 1;
302             }
303             break;
304         default:
305             return (herr_t) - 1;
306     }
307 
308     return (herr_t)0;
309 }
310 
ls() const311 std::string H5Group::ls() const
312 {
313     std::ostringstream os;
314     herr_t err;
315     OpDataPrintLs opdata;
316     opdata.parent = const_cast<H5Group *>(this);
317     opdata.os = &os;
318     hsize_t idx = 0;
319 
320     err = H5Literate(group, H5_INDEX_NAME, H5_ITER_INC, &idx, printLsInfo, &opdata);
321     if (err < 0)
322     {
323         throw H5Exception(__LINE__, __FILE__, _("Cannot list group contents"));
324     }
325 
326     return os.str();
327 }
328 
printLsInfo(hid_t g_id,const char * name,const H5L_info_t * info,void * op_data)329 herr_t H5Group::printLsInfo(hid_t g_id, const char * name, const H5L_info_t * info, void * op_data)
330 {
331     H5O_info_t oinfo;
332     herr_t err;
333     H5Object * hobj = 0;
334     hid_t obj = 0;
335     OpDataPrintLs & opdata = *(OpDataPrintLs *)op_data;
336 
337     switch (info->type)
338     {
339         case H5L_TYPE_SOFT:
340             hobj = new H5SoftLink(*opdata.parent, name);
341             break;
342         case H5L_TYPE_EXTERNAL:
343             hobj = new H5ExternalLink(*opdata.parent, name);
344             break;
345         case H5L_TYPE_HARD:
346             obj = H5Oopen(g_id, name, H5P_DEFAULT);
347             err = H5Oget_info(obj, &oinfo);
348             H5Oclose(obj);
349 
350             if (err < 0)
351             {
352                 return (herr_t) - 1;
353             }
354 
355             switch (oinfo.type)
356             {
357                 case H5O_TYPE_GROUP:
358                     hobj = new H5Group(*opdata.parent, name);
359                     break;
360                 case H5O_TYPE_DATASET:
361                     hobj = new H5Dataset(*opdata.parent, name);
362                     break;
363                 case H5O_TYPE_NAMED_DATATYPE:
364                     hobj = new H5Type(*opdata.parent, name);
365                     break;
366                 default:
367                     return (herr_t) - 1;
368             }
369             break;
370         default:
371             return (herr_t) - 1;
372     }
373 
374     hobj->printLsInfo(*opdata.os);
375     delete hobj;
376 
377     return (herr_t)0;
378 }
379 
printLsInfo(std::ostringstream & os) const380 void H5Group::printLsInfo(std::ostringstream & os) const
381 {
382     std::string str(getName());
383     H5Object::getResizedString(str);
384 
385     os << str << "Group" << std::endl;
386 }
387 
dump(std::map<haddr_t,std::string> & alreadyVisited,const unsigned int indentLevel) const388 std::string H5Group::dump(std::map<haddr_t, std::string> & alreadyVisited, const unsigned int indentLevel) const
389 {
390     std::ostringstream os;
391     haddr_t addr = this->getAddr();
392     std::map<haddr_t, std::string>::iterator it = alreadyVisited.find(addr);
393     if (it != alreadyVisited.end())
394     {
395         os << H5Object::getIndentString(indentLevel) << "GROUP \"" << getName() << "\" {" << std::endl
396            << H5Object::getIndentString(indentLevel + 1) << "HARDLINK \"" << it->second << "\"" << std::endl
397            << H5Object::getIndentString(indentLevel) << "}" << std::endl;
398 
399         return os.str();
400     }
401     else
402     {
403         alreadyVisited.insert(std::pair<haddr_t, std::string>(addr, getCompletePath()));
404     }
405 
406     H5AttributesList & attrs = const_cast<H5Group *>(this)->getAttributes();
407     H5NamedObjectsList<H5SoftLink> & softlinks = const_cast<H5Group *>(this)->getSoftLinks();
408     H5NamedObjectsList<H5ExternalLink> & externallinks = const_cast<H5Group *>(this)->getExternalLinks();
409     H5NamedObjectsList<H5Group> & hardgroups = const_cast<H5Group *>(this)->getHardGroups();
410     H5NamedObjectsList<H5Type> & hardtypes = const_cast<H5Group *>(this)->getHardTypes();
411     H5NamedObjectsList<H5Dataset> & harddatasets = const_cast<H5Group *>(this)->getHardDatasets();
412 
413     os << H5Object::getIndentString(indentLevel) << "GROUP \"" << name << "\" {" << std::endl;
414     os << attrs.dump(alreadyVisited, indentLevel + 1);
415     os << hardgroups.dump(alreadyVisited, indentLevel + 1);
416     os << hardtypes.dump(alreadyVisited, indentLevel + 1);
417     os << harddatasets.dump(alreadyVisited, indentLevel + 1);
418     os << softlinks.dump(alreadyVisited, indentLevel + 1);
419     os << externallinks.dump(alreadyVisited, indentLevel + 1);
420     os << H5Object::getIndentString(indentLevel) << "}" << std::endl;
421 
422     delete &attrs;
423     delete &softlinks;
424     delete &externallinks;
425     delete &hardgroups;
426     delete &hardtypes;
427     delete &harddatasets;
428 
429     return os.str();
430 }
431 
toString(const unsigned int indentLevel) const432 std::string H5Group::toString(const unsigned int indentLevel) const
433 {
434     std::ostringstream os;
435     std::string indentString = H5Object::getIndentString(indentLevel + 1);
436     OpDataCount opdata(false);
437     H5Object::count(*this, opdata);
438 
439     os << H5Object::getIndentString(indentLevel) << "HDF5 Group" << std::endl
440        << indentString << "Filename" << ": " << getFile().getFileName() << std::endl
441        << indentString << "Name" << ": " << getBaseName() << std::endl
442        << indentString << "Path" << ": " << getCompletePath() << std::endl
443        << indentString << "Attributes" << ": [1 x " << getAttributesNumber() << "]" << std::endl
444        << indentString << "Groups" << ": [1 x " << opdata.group << "]" << std::endl
445        << indentString << "Datasets" << ": [1 x " << opdata.dataset << "]" << std::endl
446        << indentString << "Types" << ": [1 x " << opdata.type << "]" << std::endl
447        << indentString << "Externals" << ": [1 x " << opdata.external << "]" << std::endl
448        << indentString << "Softs" << ": [1 x " << opdata.soft << "]";
449 
450     return os.str();
451 }
452 
createGroup(H5Object & parent,const std::string & name)453 void H5Group::createGroup(H5Object & parent, const std::string & name)
454 {
455     const char * _name = name.c_str();
456     createGroup(parent, 1, &_name);
457 }
458 
createGroup(H5Object & parent,const int size,const char ** names)459 void H5Group::createGroup(H5Object & parent, const int size, const char ** names)
460 {
461     hid_t obj;
462     hid_t loc = parent.getH5Id();
463 
464     for (unsigned int i = 0; i < (unsigned int)size; i++)
465     {
466         if (H5Lexists(loc, names[i], H5P_DEFAULT) > 0)
467         {
468             throw H5Exception(__LINE__, __FILE__, _("The group already exists: %s."), names[i]);
469         }
470 
471         obj = H5Gcreate(loc, names[i], H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
472         if (obj < 0)
473         {
474             throw H5Exception(__LINE__, __FILE__, _("Cannot create the group: %s."), names[i]);
475         }
476         H5Gclose(obj);
477     }
478 }
479 }
480