HDF5 Simple Read of Dataset Fails - c++

I am looking to do a simple read from an hdf5 file using C++. I will split this up into 4 parts. 1st what the file looks like. 2nd my code which attempts to read the file. 3rd the error message. 4th my conclusions.
1.The File - The dataset can be found in the file as shown:
$ h5ls -r myfile.h5
/ Group
/mydata Dataset {1200}
Note - The dataset is an array of 1200 strings. Note the CTYPE is H5T_C_S1 which is what I will use to read it in.
HDF5 "myfile.h5" {
GROUP "/" {
DATASET "mydata" {
DATATYPE H5T_STRING {
STRSIZE H5T_VARIABLE;
STRPAD H5T_STR_NULLTERM;
CSET H5T_CSET_UTF8;
CTYPE H5T_C_S1;
}
DATASPACE SIMPLE { ( 1200 ) / ( 1200 ) }
DATA {
(0): "pxsntpfcnkeesswwpwopksu", "exsytafcbkecsswwpwopnng",
(2): "ebswtlfcbnecsswwpwopnnm", "pxywtpfcnneesswwpwopksu",
(4): "exsgfnfwbktesswwpwoenag", "exyytafcbnecsswwpwopkng",
2.The Code - My code attempts to read the dataset like so:
#include "H5Cpp.h"
#ifndef H5_NO_NAMESPACE
using namespace H5;
#endif
const H5std_string FILE_NAME("myfile.h5");
const H5std_string DATASET_NAME("mydata");
// open file
H5File file(FILE_NAME, H5F_ACC_RDONLY);
// get dataset
DataSet dataset = file.openDataSet(DATASET_NAME);
// get src dataspace
DataSpace src = dataset.getSpace();
// get dimensions
int NUM_DIMS = src.getSimpleExtentNdims();
std::vector<hsize_t> dims(NUM_DIMS);
src.getSimpleExtentDims(&dims[0]);
hsize_t height = dims[0];
hsize_t width = 23;
// define src hyperslab
std::vector<hsize_t> count(NUM_DIMS, 1);
std::vector<hsize_t> offset(NUM_DIMS, 0);
src.selectHyperslab(H5S_SELECT_SET, &count[0], &offset[0]);
// define dst hyperslab
DataSpace dst(NUM_DIMS, dims);
dst.selectHyperslab(H5S_SELECT_SET, &count[0], &offset[0]);
// read data into memory, array of cstrings
std::vector<char*> data_out(height);
dataset.read(&data_out[0], H5T_C_S1, dst, src);
// print first line
std::cout << data_out[0] << std::endl;
3.The Error - However, it fails from what appears to be a type mismatch between the src and dst hyperslabs, even though I designed the src and dst to have the same dimensions. The error message is as follows:
HDF5-DIAG: Error detected in HDF5 (1.10.3) thread 0:
#000: H5Dio.c line 199 in H5Dread(): can't read data
major: Dataset
minor: Read failed
#001: H5Dio.c line 467 in H5D__read(): unable to set up type info
major: Dataset
minor: Unable to initialize object
#002: H5Dio.c line 993 in H5D__typeinfo_init(): unable to convert between src and dest datatype
major: Dataset
minor: Feature is unsupported
#003: H5T.c line 4546 in H5T_path_find(): can't find datatype conversion path
major: Datatype
minor: Can't get value
#004: H5T.c line 4762 in H5T__path_find_real(): no appropriate function for conversion path
major: Datatype
minor: Unable to initialize object
HDF5-DIAG: Error detected in HDF5 (1.10.3) thread 0:
#000: H5T.c line 1756 in H5Tclose(): immutable datatype
major: Invalid arguments to routine
minor: Bad value
DataType::~DataType - H5Tclose failed
4.My Conclusions - I have attempted many variations, including removing dst and src as parameters for dataset.read(), changing H5T_C_S1 to PredType::C_S1 and PredType::NATIVE_CHAR, however the same error persists.
How do I simply read the dataset into memory? Is the datatype truly mismatched or is there something else I am not defining? Am I still using the wrong datatype in the read function? Am I defining my hyperslabs improperly such that there actually is a type mismatch?

Maybe you want to try out HDFql and abstract yourself from HDF5 low-level details. In C++ using HDFql, you could read your variable-length char dataset mydata (contained in file myfile.h5) like this:
HDFql::execute("SELECT FROM myfile.h5 mydata"); // select (i.e. read) dataset "mydata" from file "myfile.h5" and populate default cursor with it
while(HDFql::cursorNext() == HDFql::Success) // display content of default cursor
{
std::cout << HDFql::cursorGetChar() << std::endl;
}

Related

Saving Armadillo matrix/cube into HDF5 file

I'm trying to save a struct with multiple arma::vec, arma:mat and arma::cube.
struct rdb_struct{
string info;
vec rng_vec;
vec azvec;
cube TSAP;
cube CONV;
cube TVSAP;
mat rd_maxbeam;
mat rd_maxbeam2;
mat rd_maxbeam3;
umat rd_maxbeam_index;
umat rd_maxbeam2_index;
umat rd_maxbeam3_index;
mat rd_maxbeam_azdeg;
mat rd_maxbeam2_azdeg;
mat rd_maxbeam3_azdeg;
};
For the string and vectors, it was somewhat simple to save:
#define ARMA_DONT_USE_WRAPPER
#include <armadillo>
#include <string>
#include <iostream>
#include "H5Cpp.h"
#define ARMA_ALLOW_FAKE_GCC //allows the use of GCC compiled armadillo with ICC compiler
using namespace std;
using namespace arma;
struct rdb_struct{
string info;
//params_struct params;
vec rng_vec;
vec azvec;
cube TSAP;
cube CONV;
cube TVSAP;
mat rd_maxbeam;
mat rd_maxbeam2;
mat rd_maxbeam3;
umat rd_maxbeam_index;
umat rd_maxbeam2_index;
umat rd_maxbeam3_index;
mat rd_maxbeam_azdeg;
mat rd_maxbeam2_azdeg;
mat rd_maxbeam3_azdeg;
};
struct rdb_struct_hdf5{
string info;
// params_struct params;
hvl_t rng_vec;
hvl_t azvec;
hid_t mem_TSAP;
};
int main(void)
{
rdb_struct rdb_data;
rdb_struct_hdf5 rdb_hdf5;
long long unsigned int NR=256;
long long unsigned int ND=450;
long long unsigned int NE=64;
hid_t vlen_double = H5Tvlen_create(H5T_NATIVE_DOUBLE);
rdb_data.info="testing woohoo";
rdb_data.rng_vec=2*ones<vec>(32);
rdb_data.azvec=3*ones<vec>(32);
rdb_data.TSAP=4*ones<cube>(NR,ND,NE);
rdb_data.CONV=5*ones<cube>(NR,ND,NE);
rdb_data.TVSAP=6*ones<cube>(NR,ND,NE);
rdb_data.rd_maxbeam=7*ones<mat>(NR,ND);
rdb_data.rd_maxbeam2=8*ones<mat>(NR,ND);
rdb_data.rd_maxbeam3=9*ones<mat>(NR,ND);
rdb_data.rd_maxbeam_index=10*ones<umat>(NR,ND);
rdb_data.rd_maxbeam2_index=11*ones<umat>(NR,ND);
rdb_data.rd_maxbeam3_index=12*ones<umat>(NR,ND);
rdb_data.rd_maxbeam_azdeg=13*ones<mat>(NR,ND);
rdb_data.rd_maxbeam2_azdeg=14*ones<mat>(NR,ND);
rdb_data.rd_maxbeam3_azdeg=15*ones<mat>(NR,ND);
rdb_hdf5.info=rdb_data.info;
rdb_hdf5.rng_vec.p=rdb_data.rng_vec.memptr();
rdb_hdf5.rng_vec.len=rdb_data.rng_vec.size();
rdb_hdf5.azvec.p=rdb_data.azvec.memptr();
rdb_hdf5.azvec.len=rdb_data.azvec.size();
// the array of each length of multidimentional data.
hsize_t dim_rdb[1];
dim_rdb[0] = sizeof(rdb_hdf5) / sizeof(rdb_struct_hdf5);
// the length of dim
int rank_rdb = sizeof(dim_rdb) / sizeof(hsize_t);
// defining the datatype to pass HDF55
H5::CompType h5_rdb(sizeof(rdb_struct_hdf5));
h5_rdb.insertMember("info", HOFFSET(rdb_struct_hdf5, info), H5::StrType(H5::PredType::C_S1, H5T_VARIABLE));
h5_rdb.insertMember("rng_vec", HOFFSET(rdb_struct_hdf5, rng_vec), vlen_double);
h5_rdb.insertMember("azvec", HOFFSET(rdb_struct_hdf5, azvec), vlen_double);
h5_rdb.insertMember("TSAP", HOFFSET(rdb_struct_hdf5, mem_TSAP), cube_double);
// preparation of a dataset and a file.
H5::DataSpace space_rdb(rank_rdb, dim_rdb);
H5::H5File *file = new H5::H5File("data_test.h5", H5F_ACC_TRUNC);
H5::DataSet *dataset_rdb = new H5::DataSet(file->createDataSet("rdb_data", h5_rdb, space_rdb));
// Write
dataset_rdb->write(&rdb_hdf5, h5_rdb);
delete dataset_rdb;
delete file;
return 0;
}
But the mat and cubes have been giving me trouble, mainly because I have no idea what I'm doing with HDF5. It looks like to do what I want, I need to create a H5Tarray_create and insert it into the 'cpmp_type h5_rdb' but everything I have tried has failed to run (it does compile) with the following message:
HDF5-DIAG: Error detected in HDF5 (1.10.4) thread 139735682275136:
#000: ../../../src/H5Tcompound.c line 354 in H5Tinsert(): unable to insert member
major: Datatype
minor: Unable to insert object
#001: ../../../src/H5Tcompound.c line 446 in H5T__insert(): member extends past end of compound type
major: Datatype
minor: Unable to insert object
terminate called after throwing an instance of 'H5::DataTypeIException'
Aborted (core dumped)
This code seems to work but when I try to merge it with my original code it doesn't work, mainly from me not understanding how/why hid_t is used for everything...
#include <armadillo>
#include <string>
#include <iostream>
#include "H5Cpp.h"
#define ARMA_ALLOW_FAKE_GCC //allows the use of GCC compiled armadillo with ICC compiler
using namespace std;
using namespace arma;
int
main (void)
{
long long unsigned int NR=64;
long long unsigned int ND=64;
long long unsigned int NE=64;
hsize_t dims_of_int_array[] = {NR,ND,NE};
hsize_t dims_of_int_dataspace[] = {1};
// int *data = (int *)malloc(4*4*4*sizeof(int));
// int i;
// for (i=0; i<(4*4*4); i++) data[i] = i;
cube data = 4*ones<cube>(NR,ND,NE);
hid_t file = H5Fcreate("multset.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
hid_t mem_h5t = H5Tarray_create(H5T_NATIVE_DOUBLE, 2, dims_of_int_array);
hid_t dataspace = H5Screate_simple(2, dims_of_int_dataspace, NULL);
hid_t dataset = H5Dcreate(file, "data_data", mem_h5t, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Dwrite(dataset, mem_h5t, H5S_ALL, H5S_ALL, H5P_DEFAULT, data.memptr());
H5Dclose(dataset);
H5Sclose(dataspace);
H5Tclose(mem_h5t);
// free(data);
return 0;
}
I did notice the code that is work only works until the cube size becomes too large and starts spitting out errors about contiguous write failed but I think that's a problem for another day. I'm mainly looking for help on how to insert a array datatype into a composite datatype. Any help would be greatly appreciated.

Access violation at 0x00000000 Loading PNG File With SDL_image Library

I am using the SDL2 2.0.3 library with the SDL_image library 2.0.0 in Visual C++ 2010 Express. I am utilizing the SDL_image library to load a variety of PNG and JPEG files from a resources folder. While the library initializes without any errors and loads BMP and JPEG files, it breaks when given a PNG file.
"Unhandled exception at 0x00000000 in appname.exe: 0xC0000005: Access violation."
Inside of my texture manager, (an object that stores and manages textures for the program), is a function to load a texture from a given file name string. Here is the code, including the commented line I used before implementing SDL_image to do the loading. It is within the line bitmapSurface = IMG_Load(... that the exception above is thrown.
/**
* Attempts to load a given image file and reports to the console any failures
*
* #param fileName The exact file name of the resource to be loaded
* #return The SDL_Texture loaded from the given fileName
*/
SDL_Texture* TextureManager::loadTexture(string fileName)
{
//Create our surface in RAM
SDL_Surface *bitmapSurface = NULL;
//bitmapSurface = SDL_LoadBMP(fileName.c_str()); //OLD METHOD; standard SDL, BMP only
bitmapSurface = IMG_Load(fileName.c_str()); //NEW METHOD; SDL_image lib, many formats
//Verify it exists
if (bitmapSurface == NULL)
cout << "Image resource not loaded: " << fileName << " Message: " << IMG_GetError() << endl;
//Create a texture in VRAM from the surface
SDL_Texture *bitmapTexture = NULL;
bitmapTexture = SDL_CreateTextureFromSurface(this->renderer, bitmapSurface);
//Verify it exists
if (bitmapTexture == NULL)
cout << "Failed to create texture: " << fileName << endl;
return bitmapTexture;
}
Call Stack:
00000000()
SDL2_image.dll!6a887a01()
[Frames below may be incorrect and/or missing, no symbols loaded for SDL2_image.dll]
SDL2.dll!6c77da4b()
SDL2_image.dll!6a88792e()
SDL2_image.dll!6a881693()
SDL2_image.dll!6a8817e9()
> appname.exe!TextureManager::loadTexture(std::basic_string<char,std::char_traits<char>,std::allocator<char> > fileName) Line 143 + 0xe bytes C++
00daf5e0()
Here is the constructor for my TextureManager:
/**
* Creates a new TextureManager with the current SDL_Renderer
*
* #param renderer The current renderer instance of the current graphic window
*/
TextureManager::TextureManager(SDL_Renderer* renderer)
{
//Assign our renderer link
this->renderer = renderer;
//Create the vector to hold textures
this->textures = new vector<Texture*>();
//SDL_image initialization
int flags = IMG_INIT_JPG|IMG_INIT_PNG;
int initted = IMG_Init(flags); //Use IMG_Quit(); at closing
if(initted&flags != flags)
{
//Handle error
printf("IMG_Init: Failed to init required jpg and png support!\n");
printf("IMG_Init: %s\n", IMG_GetError());
}
else
{
cout << "SDL_Image initialized for JPEG and PNG support" << endl;
}
}
For your information, I am using Windows 10 x64, which is up to date. Graphics drivers for dual NVidia GTX 550ti are up to date as well.
All DLL files (including the pnglib dll) are in the debug folder and do load. If I remove the DLL file from the program, the image fails to load and provides the message as coded above for NULL surfaces. No exceptions occur.
Question summary:
Why is this exception thrown, why is it only thrown for PNG files, and how can I trace it when the call stack's details end at my call that appears to work properly? Am I doing something wrong, or is there a configuration step I may have missed?
EDIT: Thanks to #Nandu I have recompiled the DLL SDL_image, and got a better call stack output here:
00000000()
> SDL2_image.dll!IMG_LoadPNG_RW(SDL_RWops * src) Line 375 + 0x11 bytes C
SDL2_image.dll!IMG_LoadTyped_RW(SDL_RWops * src, int freesrc, const char * type) Line 193 + 0x12 bytes C
SDL2_image.dll!IMG_Load(const char * file) Line 134 + 0xf bytes C
appname.exe!TextureManager::loadTexture(std::basic_string<char,std::char_traits<char>,std::allocator<char> > fileName) Line 143 + 0xe bytes C++
appname.exe!TextureManager::loadFromDirectory(std::basic_string<char,std::char_traits<char>,std::allocator<char> > relPath) Line 117 + 0x73 bytes C++
appname.exe!SDL_main(int argc, char * * argv) Line 31 C++
appname.exe!main(int argc, char * * argv) Line 140 + 0xd bytes C
appname.exe!__tmainCRTStartup() Line 555 + 0x19 bytes C
appname.exe!mainCRTStartup() Line 371 C
kernel32.dll!77963744()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
ntdll.dll!77c3a064()
ntdll.dll!77c3a02f()
This suggests the problem is occurring on line 374 of IMG_png.c:
/* Create the PNG loading context structure */
png_ptr = lib.png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL,NULL,NULL);
VS reports that lib is NULL at this time, which would explain the error! The question becomes, why is it NULL? It seems this code should be doing a check for that, but nonetheless, nobody else seems to having this problem on the almighty internet.
Thank you all very much for you help, but the problem, as usual, was rather obvious!
As noted here by #Gigi: SDL_Image IMG_Load fails on png with: "Failed loading libpng16-16.dll:"
I suggest you try including all the rest - there may be a dependency that you and I are not aware of. In fact I just checked, and libpng requires zlib: libpng.org/pub/png/libpng.html
I'm not sure why my original search or suggestions didn't bring that post up.
I originally excluded the DLLs for other file formats I wasn't using (or initializing in my code), but once I included the zlib DLL, bingo. PNGs load exactly as expected.

cvLogPolar results in opencv error "Bad flag (parameter or structure field)"

I'm trying to use the cvLogPolar method, but I always get the following error:
OpenCV Error: Bad flag (parameter or structure field) (Unrecognized or unsupported array type) in cvGetMat, file /tmp/opencv-pcqRHK/opencv-2.4.10.1/modules/core/src/array.cpp, line 2482
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /tmp/opencv-pcqRHK/opencv-2.4.10.1/modules/core/src/array.cpp:2482: error: (-206) Unrecognized or unsupported array type in function cvGetMat
My code:
cv::Mat logpolar_frame(size, CV_8UC3), bgr_frame;
for(;;) {
capture >> bgr_frame;
if( bgr_frame.empty() ) {
break;
}
cv::imshow( "Example2_10", bgr_frame );
cvLogPolar(&bgr_frame, &logpolar_frame, cv::Point2f(bgr_frame.cols / 2, bgr_frame.rows / 2), 40);
}
I already tried to copy the bgr_frame inside the loop, but this results in the same error.
you need a bloody IplImage* for the arcane c-api legacy functions.
IplImage ipl_in = bgr_frame;
IplImage ipl_out = logpolar_frame;
cvLogPolar(&ipl_in, &ipl_out, ...)
(for 3.0, avoid all of it, and use cv::logPolar(), unfortunately not available in opencv2.4)

Weird Exception in HDF5

I was trying a basic hdf5 dataset read/write operations in C++.
#include "stdafx.h"
#include "h5cpp.h"
#include <iostream>
#include <conio.h>
#include <vector>
#include <string>
#ifndef H5_NO_NAMESPACE
using namespace H5;
#endif
const H5std_string fName("dset.h5");
const H5std_string dsName("dset");
int main()
{
try
{
int data[10];
int dataOut[10];
//Exception::dontPrint();
std::cout<<"Enter The Data : ";
for(int i = 0 ; i < 10 ; i++)
std::cin>>data[i];
H5File file(fName, H5F_ACC_TRUNC);
IntType type(H5T_NATIVE_INT);
Group *myGroup = new Group(file.createGroup("\\myGroup"));
hsize_t dim[] = {10};
DataSpace dSpace(1,dim);
DataSet dSet = myGroup->createDataSet(dsName, type, dSpace);
dSet.write(data, type);
std::cout << "Data Written\n";
dSet.read(dataOut, type);
std::cout<<"Data Read\n";
for(int i = 0 ; i < 10 ; i ++)
std::cout<<dataOut[i]<<"\n";
delete myGroup;
}
catch(Exception e)
{
e.printError();
}
_getch();
return 0;
}
After all the data is entered, I get exceptions:
HDF5-DIAG: Error detected in HDF5 (1.8.12) thread 0:
#000: ..\..\src\H5F.c line 1503 in H5Fcreate(): unable to create file
major: File accessibilty
minor: Unable to open file
#001: ..\..\src\H5F.c line 1285 in H5F_open(): unable to open file: time = Wed
Feb 12 00:02:29 2014
, name = '#╦>ÿK', tent_flags = 13
major: File accessibilty
minor: Unable to open file
#002: ..\..\src\H5FD.c line 987 in H5FD_open(): open failed
major: Virtual File Layer
minor: Unable to initialize object
#003: ..\..\src\H5FDsec2.c line 343 in H5FD_sec2_open(): unable to open file:
name = '#╦>ÿK', errno = 22, error message = 'Invalid argument', flags = 13, o_fl
ags = 302
major: File accessibilty
minor: Unable to open file
HDF5-DIAG: Error detected in HDF5 (1.8.12) thread 0:
#000: ..\..\src\H5F.c line 1503 in H5Fcreate(): unable to create file
major: File accessibilty
minor: Unable to open file
#001: ..\..\src\H5F.c line 1285 in H5F_open(): unable to open file: time = Wed
Feb 12 00:02:29 2014
, name = '#╦>ÿK', tent_flags = 13
major: File accessibilty
minor: Unable to open file
#002: ..\..\src\H5FD.c line 987 in H5FD_open(): open failed
major: Virtual File Layer
minor: Unable to initialize object
#003: ..\..\src\H5FDsec2.c line 343 in H5FD_sec2_open(): unable to open file:
name = '#╦>ÿK', errno = 22, error message = 'Invalid argument', flags = 13, o_fl
ags = 302
major: File accessibilty
minor: Unable to open file
But if I hardcode the filename and dataset names like "abcd.h5" and "dSet", then, I am able to get to get the required output but after the output, I am getting exceptions:
HDF5-DIAG: Error detected in HDF5 (1.8.12) thread 0:
#000: ..\..\src\H5T.c line 1765 in H5Tclose(): immutable datatype
major: Invalid arguments to routine
minor: Bad value
DataType::~DataType - H5Tclose failed
Please, help me in figuring out this problem.
There are two distinct problems. The first one is that somehow, H5std_string which is in fact just a std::string gets mangled on your system. It seems that dset.h5 is transformed into #╦>ÿK. I might be wrong but that's how it looks. For this I have no clue, it's a Windows issue and to be honest, it's a bit scary.
The second problem problem comes from type: the destructor complains that it cannot destroy this object since it is immutable. So why is it immutable? Because you are using this constructor:
H5::IntType::IntType(const hid_t existing_id)
which just wraps the immutable H5T_NATIVE_INT type, instead of this one:
H5::IntType::IntType(const PredType& pred_type)
which clones H5T_NATIVE_INT, and the clone is mutable and more importantly, can be destroyed. So you need to replace:
IntType type(H5T_NATIVE_INT);
by
IntType type(PredType::NATIVE_INT);
and you will be good.

OpenCV FileStorage Reading Error

I'm trying to solve a problem related with the OpenCV FileStorage.
I can successfully write and read to/from yml/xml files.
This only works when writing and reading functions are in the same program though.
When I create and write a yml file successfully in one program and tried to access that file from another program, I'm having the following problem.
Writing part:
d_img = imread(filename, 1);
FileStorage fs_source("tmp.yaml", FileStorage::WRITE);
if (fs_source.isOpened()){
fs_source << "source" << d_img;
fs_source.releaseAndGetString();
cout<<"Source : image written to temporary file"<<endl;
}
else
{
fs_source.open("tmp.yaml", FileStorage::WRITE);
fs_source << "source" << d_img;
fs_source.releaseAndGetString();
cout<<"Source : image written to temporary file 2"<<endl;
}
Reading part:
FileStorage fs_sink("tmp.yaml", FileStorage::READ);
if (fs_sink.isOpened()){
fs_sink["source"] >> d_img;
fs_sink.releaseAndGetString();
cout<<"Sink : image read from file 1"<<endl;
}
else
{
fs_sink.open("tmp.yaml", FileStorage::READ);
fs_sink["source"] >> d_img;
fs_sink.releaseAndGetString();
cout<<"Sink : image read from file 2"<<endl;
}
imwrite( "output.jpg", d_img );
First code creates the yml file without any problem.
But the second code throws the following error when it comes to the first line here which is FileStorage fs_sink("tmp.yaml", FileStorage::READ);
OpenCV Error: Parsing error (tmp.yaml(0): Valid XML should start with '<?xml ...?>') in icvXMLParse, file /var/tmp/portage/media-libs/opencv-2.4.7/work/opencv-2.4.7/modules/core/src/persistence.cpp, line 2257
thread[thread-per-block[1]: <block image_sink (2)>]: /var/tmp/portage/media-libs/opencv-2.4.7/work/opencv-2.4.7/modules/core/src/persistence.cpp:2257: error: (-212) tmp.yaml(0): Valid XML should start with '<?xml ...?>' in function icvXMLParse
This is odd because the file is yml, not an xml. It still gives the same error when I change the file type to xml.
What could cause this error?
PS: Both releaseAndGetString(); and release(); methods are tried to close the file. Same results.
xml, yml, and yaml extensions are all tried too.
Edit: Can be replicated if file is empty.