I want to read an INI file entirely, I am using wxFileConfig class to do that but the most examples of the internet just to reading & writing only an item, not an entire INI file.
The data in the INI file similar to the following:
[sdl]
fullresolution=0x0
fullscreen=true
output=opengl
autolock=false
[dosbox]
machine=svga_s3
memsize=16
[render]
frameskip=0
aspect=false
scaler=normal2x
[cpu]
core=normal
cputype=auto
cycles=10000
cycleup=1000
cycledown=1000
.....
I tried to do something, but it just reads the headers ([sdl], [dosbox], [render], ...).
wxFileConfig config(wxEmptyString, wxEmptyString, wxEmptyString, wxGetCwd() + "\\dosbox.conf");
wxString str;
long idx;
bool bCont = config.GetFirstGroup(str, idx);
while (bCont) {
bCont = config.GetNextGroup(str, idx);
debugMsg("%s", str);
}
How to read each header with its items?
Taken from the documentation you can read all the entries like so:
// enumeration variables
wxString str;
long dummy;
// first enum all entries
bool bCont = config->GetFirstEntry(str, dummy);
while ( bCont ) {
aNames.Add(str);
bCont = config->GetNextEntry(str, dummy);
}
It's very similar to the code you have to read the all the groups.
I found a complete code that brings all data from an .ini file:
wxFileConfig config(wxEmptyString, wxEmptyString, wxEmptyString, wxGetCwd() + "\\dosbox.conf");
wxString group;
long group_index;
config.SetPath("/");
bool has_group = config.GetFirstGroup(group, group_index);
while (has_group) {
config.SetPath(group);
wxString entry;
long entry_index;
bool has_entry = config.GetFirstEntry(entry, entry_index);
while (has_entry) {
wxString value = config.Read(entry, "");
wxMessageOutputDebug d;
d.Printf("[%s] %s = %s", group, entry, value);
has_entry = config.GetNextEntry(entry, entry_index);
}
config.SetPath("/");
has_group = config.GetNextGroup(group, group_index);
}
The source.
Related
I am starter and right now I am trying to extract the key information from a .xml file then load them to an object of my class, for example:
Here are some information in .xml file:
<row Id="17" Phone="12468" Address="Bos" />
<row Id="242" Phone="98324" Address="Chi" Age="30"/>
<row Id="157" Phone="23268" Age="25" />
<row Id="925" Phone="54325" Address="LA" />
And my class would be:
class worker{
string ID;
string Phone;
string Address;
string Age;
}
I know the infomation would be various and if there is not that infomation of that line, we put ""(empty string) in it as return. And I know the infomation are given in the same order of the fields in class. I try to implement a function, let says extractInfo(const string& line, const string &key)
//#line: the whole line read from .xml
//#key: it would be "Id:"", "Phone:"", "Address:"" or "Age:"", so that I could reach the
// previous index of the infomation that I could extract.
extractInfo(const string& line, const string &key){
int index = line.find(key);
if(index == -1) return "";
int start = index + key.length(); //to reach the start quote
int end = start;
while(line[end] != '"'){ //to reach the end quote
end++;
}
return line.substr(start, end - start);
}
int main(){
...// for each line read from .xml, I build a new object of class worker and filling the field
worker.Id = extraInfo(line, "Id:\"");
worker.Phone = extraInfo(line, "Phone:\"");
...//etc.
...//then work on other manipulation
return 0;
}
My question are, is there any way that I could read and load the infomation from xml much more quickly through other APL or functions? That is, is there any way for me to improve this function when the .xml is a huge file with TBytes? And, is there any way that I can use less memory to, for example, find the oldest worker then print out? I know it's tough for me and I still try hard on it!
Thank all the ideas and advice in advance!
You can parse XML with existing XML parsing libraries, such as rapidxml, libxml2, etc.
Please note that for huge XML, since it need read all XML content to create the DOM tree, so the DOM method is not really suitable. you can use libxml2's xmlreader to parse each node one by one.
libxml2 xml reader
static void
streamFile(const char *filename) {
xmlTextReaderPtr reader;
int ret;
reader = xmlReaderForFile(filename, NULL, 0);
if (reader != NULL) {
ret = xmlTextReaderRead(reader);
while (ret == 1) {
const xmlChar *name = xmlTextReaderConstName(reader);
if(xmlStrEqual(BAD_CAST "row", name)) {
const xmlChar *id = xmlTextReaderGetAttribute(reader, "Id");
const xmlChar *phone = xmlTextReaderGetAttribute(reader, "Phone");
// you code here...
xmlFree(id);
xmlFree(phone);
}
ret = xmlTextReaderRead(reader);
}
xmlFreeTextReader(reader);
if (ret != 0) {
fprintf(stderr, "%s : failed to parse\n", filename);
}
} else {
fprintf(stderr, "Unable to open %s\n", filename);
}
}
And, If your XML format is always like above, you can also use std::regex_search to handle it
https://en.cppreference.com/w/cpp/regex/regex_search
#include <iostream>
#include <string>
#include <regex>
int main()
{
std::string str = R"(<row Id="17" Phone="12468" Address="Bos" />)";
std::regex regex("(\\w+)=\"(\\w+)\"");
// get all tokens
std::smatch result;
while (std::regex_search(str, result, regex))
{
std::cout << result[1] << ": " << result[2] << std::endl;
str = result.suffix().str();
}
}
I'm having an issue with libexif saving tags string data. I'm allocating memory for string value, using strcpy and then just assiggn pointer to specific tags entry->data. Problem is - saving with exif_data_save_data and fwrite, i get my string value cutted to 7 chars. If I load all this data at first from file with longer string value for this specific exif tag (EXIF_TAG_NAME in particular), max string len coud be different.
static char* get_c_str(QString qs)
{
QByteArray *qba = new QByteArray(qs.toLatin1());
char* str = (char *)malloc(qba->count());
strcpy(str,qba->data());
return str;
}
static ExifEntry *init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag)
{
ExifEntry *entry;
if (!((entry = exif_content_get_entry (exif->ifd[ifd], tag)))) {
entry = exif_entry_new ();
assert(entry != NULL);
entry->tag = tag;
exif_content_add_entry (exif->ifd[ifd], entry);
exif_entry_initialize (entry, tag);
exif_entry_unref(entry);
}
return entry;
}
void MainWindow::on_writeButton_clicked()
{
if(!buf)
return;
ent = init_tag(ed,ExifIfd::EXIF_IFD_0,ExifTag::EXIF_TAG_MODEL);
ent->data = (unsigned char*)get_c_str(ui->modelL->text());
................................................
exif_data_save_data(ed, &exifData, &exifDatLen);
f = fopen(path, "wb");
fwrite(exif_header,exif_header_len,1,f);
fputc((exifDatLen+2)>>8,f);
fputc((exifDatLen+2) & 0xff, f);
fwrite(exifData,exifDatLen,1,f);
fwrite(buf+image_data_offset,flen,1,f);
fclose(f);
}
Expected Camera Model to be "Canon EOS 5D Mark II" but was "Canon E"
My requirement is to store string data in to .dat or .bin file which human cannot understand it.
I am able to store integers in to file in binary mode but not able to store string in binary mode.
I tried using CFile and CArchive in MFC
Tried using fstream
Tried using File*
But could not succeeded.
Can Anyone help me in doing this?
void CAuthenticationFileDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
static int count =0;
DisplayKeys(count);
CString strTotalKeys = m_keys->GetKey1() + m_keys->GetKey2() + m_keys-getkey3() + m_keys->GetKey4();
m_vectKeys.push_back(strTotalKeys);
m_EditKey1.SetFocus();
CFile pFile;
ASSERT (pFile != NULL);
if (!pFile.Open (_T("foo.dat"), CFile::modeReadWrite | CFile::modeCreate|CFile::typeBinary))
{ // Handle error
return;
}
CArchive arStore(&pFile, CArchive::store);
Serialize(arStore);
delete m_keys;
count++;
if(count>0)
{
m_keys = new CKeys;
}
UpdateData(FALSE);
}
I have a class called Ckeys which has 4 Cstring variables.
I am trying to store it's object.
Anyways i s OK. I want to store data into binary format.
Above I mentioned OnintDialog() which is MFC CDialog Virtual function which is invoed before dialog is shown. In which I am trying to read file and displaying it in list control. (I could not achive this)
in Button event I am trying to write the objects data which is given by user.
Use any method to convert/encode the string to unreadable format.
The following methods can save/restore a CString value to/from file:
void WriteString(CString file, CString s)
{
CFile myFile(file, CFile::modeCreate | CFile::modeWrite);
CArchive ar(&myFile, CArchive::store);
int sz = s.GetLength();
ar << sz; // ar.Write(&sz, sizeof(int));
ar.Write(s.GetBuffer(), sz);
ar.Close();
}
CString ReadString(CString file)
{
CString s;
CFile myFile(file, CFile::modeRead);
CArchive ar(&myFile, CArchive::load);
int sz = 0;
ar >> sz; // ar.Read(&sz, sizeof(int));
char* p = s.GetBuffer(sz);
ar.Read(p, sz);
s.ReleaseBuffer(sz);
p = nullptr; // avoid using released buffer
ar.Close();
return s;
}
I have a .json file, containing an array of dictionaries. Can you show me a good way of parsing it? I'm using the cocos2d-x 3.0-alpha version and the json classes, placed in the external/json directory.
I tried:
Array* items = Array::createWithContentsOfFile("test.json");
and
string fullPath = CCFileUtils::getInstance()->fullPathForFilename("test.json");
long bufferSize = 0;
const char* mFileData = (const char*)FileUtils::getInstance()->getFileData(fullPath.c_str(), "r", &bufferSize);
string clearData(mFileData);
size_t pos = clearData.rfind("}");
clearData = clearData.substr(0, pos+1);
string data = clearData.c_str();
log("%s", clearData.c_str());
Json::Value _root;
Json::Reader reader;
reader.parse(data, _root);
but none of them work - the first method returns an empty array, the second one results a _root variable, containing the whole json, but I can't make it into an array and create a separate dictionary object for each of the array's elements ( which is what I'm trying to do ).
Use JsonCPP you mentioned above but with CCFileUtils class
unsigned long filesize = 0;
std::string content;
std::string fullPath = "path relative to your androidmanifest.xml/index.json"
unsigned char* fileData = CCFileUtils::sharedFileUtils()->getFileData(fullPath.c_str(), "r", &filesize);
content.append((char*)fileData);
delete[] fileData;
Json::Value jsonresult;
Json::Reader reader;
bool parsingSuccessful = reader.parse( content, jsonresult );
if ( !parsingSuccessful )
{
// report to the user the failure
return false;
}
The following code works in a the Marmalade simulator (I'm on OSX using x-code)
bool PictureDictionary::OnTableSelect(CTable* table, int tab){
//if something is selected, look up the item, and display it
//also change the search to the selected item
if(-1 < tab){
// if a term is selected, set the search text field to the term
CString term = m_SearchResults.GetString(tab);
if(m_currentWord != (char*)term.Get()){
m_currentWord = (char *)term.Get();
m_searchTextField->SetAttribute("text", term);
char* normalizedTerm = (char *)term.Get();
char* imagePath;
sprintf(imagePath,"images/%s.jpg", normalizedTerm);
if(m_ImageAttached){
m_Image->SetAttribute("image", (const char*)imagePath);
} else {
m_Image = CreateImage(CAttributes()
.Set("name", "picture")
.Set("x1", "0")
.Set("x2", "0")
.Set("y1", "50%")
.Set("image", (const char*)imagePath)
);
m_SearchView->AddChild(m_Image);
m_ImageAttached = true;
}
}
}
return true;
}
When I run the simulator, and select an item from the table, the image appears, and changes when I select a different item. When I go to refactor, I get a EXC_BAD_ACCESS (code=1…..) Error
bool PictureDictionary::OnTableSelect(CTable* table, int tab){
//if something is selected, look up the item, and display it
//also change the search to the selected item
if(-1 < tab){
// if a term is selected, set the search text field to the term
CString term = m_SearchResults.GetString(tab);
if(m_currentWord != (char*)term.Get()){
m_currentWord = (char *)term.Get();
m_searchTextField->SetAttribute("text", term);
char* normalizedTerm = (char *)term.Get();
char* imagePath;
sprintf(imagePath,"images/%s.jpg", normalizedTerm);
UpdatePictureView(imagePath);
}
}
return true;
}
void PictureDictionary::UpdatePictureView(char* imagePath){
if(m_ImageAttached){
m_Image->SetAttribute("image", (const char*)imagePath);
} else {
m_Image = CreateImage(CAttributes()
.Set("name", "picture")
.Set("x1", "0")
.Set("x2", "0")
.Set("y1", "50%")
.Set("image", (const char*)imagePath)
);
m_SearchView->AddChild(m_Image);
m_ImageAttached = true;
}
}
Any suggestions on how to clean up the code without getting these issues?
Edit RE Comments about uninitialized variables:
m_ImageAttached was initialized to false in the constructor, unless I'm doing something wrong. Also, changing the condition to check if m_Image!=NULL also throws the same error.
main.cpp:
PictureDictionary pictDict(myApp, &dictionary);
Constructor for PictureDictionary:
PictureDictionary::PictureDictionary(CAppPtr app,Dictionary::Dictionary* dictionary){
m_App = app;
m_Dictionary = dictionary;
m_currentWord = "";
m_ImageAttached = false;
}
imagePath is an unitialized pointer, in both snippets. Any attempt to dereference is undefined behaviour. It just appeared to work in the first snippet. Use an array or populate a std::string instead:
std::string imagePath(std::string("images/") + normalizedTerm + ".jpg");
And use std::string::c_str() if access to the underlying const char* is required.