RapidXml Work when build but have problems in debugger - c++

Hi i use rapidxml to load map in my game this is how my class for loading looks like
it's normally compiling but when loading file sometimes it crashing so i wanted to debug it but debugger dont like my function which is setting pointers to data in xml file.
#0 0042D5A6 rapidxml::xml_node<char>::first_node(this=0x0, name=0x484175 <_ZSt16__convert_from_vRKPiPciPKcz+4735349> "MapInfo", name_size=7, case_sensitive=true) (C:/.../rapidxml.hpp:942)
#1 00404E31 MapLoader::SetNodes(this=0x27fc1c) (C:\...\main.cpp:651)
#2 004032F6 main() (C:\...\main.cpp:267)
class MapLoader
{
public:
xml_document<> doc;
file<>xmlFile(char);
string ca,cb,cc,cd;
xml_node<> *test;
xml_node<> *root;
xml_node<> *mapinfo;
xml_node<> *name;
xml_node<> *date;
xml_node<> *msize;
xml_attribute<> *sizex;
xml_attribute<> *sizey;
xml_node<> *mapdata;
xml_node<> *layer;
xml_attribute<> *nr;
xml_node<> *tile;
xml_attribute<> *id;
xml_attribute<> *x;
xml_attribute<> *y;
void LoadFile(const char *filename);
void SetNodes();
void FillVector();
void SaveVector();
};
void MapLoader::SetNodes()
{
root=doc.first_node("root");
mapinfo=root->first_node("MapInfo"); //////debugger is pointing on this line
name=mapinfo->first_node("Name");
date=mapinfo->first_node("Date");
msize=mapinfo->first_node("Size");
sizex=msize->first_attribute("x");
sizey=msize->first_attribute("y");
mapdata=root->first_node("MapData");
layer=mapdata->first_node("Layer");
nr=layer->first_attribute("id");
tile=layer->first_node("Tile");
id=tile->first_attribute("id");
x=tile->first_attribute("x");
y=tile->first_attribute("y");
}
what i can do to repair it or something like that?
Edit:
here is my xml file:
<?xml version="1.0" encoding="utf-8"?>
<root>
<MapInfo>
<Name>Test</Name>
<Date>17.08.2014</Date>
<Size x="64" y="64"/>
</MapInfo>
<MapData>
<Layer nr="1">
<Tile id="1" x="32" y="32"/>
<Tile id="1" x="32" y="64"/>
<Tile id="1" x="512" y="64"/>
</Layer>
<Layer nr="2"/>
<Layer nr="3"/>
</MapData>
</root>

First of all its good practice to check for NULL as returned pointer. My guess would be, that "root" is missing in the xml file.
Take a look at the Manual of rapidxml because case sensitivity can also be an issue.
Edit:
I wrote a small program and checked at least Name and Date. Works for me.
// Trying out rapid xml.
//
#include "rapidxml/rapidxml.hpp"
#include <cstdio>
#include <string>
#include <vector>
int main(int argc, char** argv) {
rapidxml::xml_document<> doc; // character type defaults to char
FILE* file = fopen("Test.xml", "r");
if (!file)
return 1;
// file exists.
// get the number of bytes.
fseek(file, 0, SEEK_END);
size_t sizeInBytes = ftell(file);
fseek(file, 0, SEEK_SET);
char* buffer = static_cast<char*>(malloc(sizeInBytes + 1)); // + 1 needed?
if (fread(buffer, 1LU, sizeInBytes, file) != sizeInBytes) {
perror("unexpected file length\n");
fclose(file);
free(buffer);
return 1;
}
buffer[sizeInBytes] = 0;
// close the file.
fclose(file);
doc.parse<0>(buffer); // 0 means default parse flags
std::vector<std::string> nodeNames;
nodeNames.push_back("Name");
nodeNames.push_back("Date");
rapidxml::xml_node<>* node = doc.first_node("root");
for (size_t i = 0; i < nodeNames.size() && node; ++i) {
if (node->first_node(nodeNames[i].c_str()))
fprintf(stderr, "CantFindNode with name %s.\n", nodeNames[i].c_str());
printf("Node %s found!\n", nodeNames[i].c_str());
}
free(buffer);
return 0;
}

Related

XML Parser not showing informations C++

I am using TinyXML2 and I got some strange problem. So It seems it work because I dont have any crashes but when I want to output one of the value I got I have nothing , if someone know why ?
I already used tinyxml2 and it was working but here maybe the XML is strange?
#include <iostream>
#include "tinyxml2/tinyxml2.cpp"
#include "../Inc/classConfigCtx.h"
#include "../Inc/globalDefine.h"
using namespace tinyxml2;
int main() {
std::cout << "Hello World!";
XMLDocument doc;
doc.LoadFile( "NetworkConfig.xml" );
int AppliMsgPort_;
const char * portAppli;
const char * IPtemp;
XMLElement * pRootElement =doc.RootElement()->FirstChildElement();
portAppli=pRootElement->FirstChildElement()->GetText();
std::cout<<portAppli;
return 0;
}
and my XML
<configuration>
<operational_00001000><name value="100.CBD" /><radio_1><type value="Net" /><ip value="10.36.1.1" /><port_s value="50010" /><port_r value="50100" /><radioID value="10040" /></radio_1></operational_00001000>
<operational_00001005><name value="100.LOG" /><radio_1><type value="Net" /><ip value="10.26.2.1" /><port_s value="50000" /><port_r value="50000" /><radioID value="1000005" /></radio_1></operational_00001005>
</configuration>

tinyxml2 building and writing xml file on c++

I am trying to build a simple xml file using tinyxml2 in VS2019,
for some reason the code works until it hits the element named port.
this element and every element after it is ignored in the xml file.
I just noticed, it is also writing xml output in the wrong order, host should be the one right below , not port.
What am i missing here?
Truth be told, i have about 2 days experience writing c++, and very basic python knowlage.
#include <iostream>
#include <fstream>
#include <windows.h>
#include <Lmcons.h>
#include <stdlib.h>
#include <filesystem>
#include "tinyxml/tinyxml2.h"
using namespace tinyxml2;
using namespace std;
namespace fs = std::filesystem;
int main()
{
SetConsoleOutputCP(CP_UTF8);
char* appdata;
size_t len;
errno_t err = _dupenv_s(&appdata, &len, "APPDATA");
fs::path path = appdata;
path /= "FileZilla";
path /= "sitemanager.xml";
TCHAR username[UNLEN + 1];
DWORD size = UNLEN + 1;
GetUserName((TCHAR*)username, &size);
tinyxml2::XMLDocument xmlDoc;
//tinyxml2::XMLDeclaration* decl = new XMLDeclaration("1.0", "UTF-8", "");
XMLElement* pRoot = xmlDoc.NewElement("FileZilla3");
pRoot->SetAttribute("Version", "");
pRoot->SetAttribute("Platform", "");
xmlDoc.InsertFirstChild(pRoot);
XMLElement* child = xmlDoc.NewElement("Servers");
child->SetText("\n");
pRoot->InsertEndChild(child);
XMLElement* subchild = xmlDoc.NewElement("Server");
subchild->SetText("\n");
child->InsertEndChild(subchild);
XMLElement* host = xmlDoc.NewElement("host");
host->SetText("ftp.some.url");
subchild->InsertEndChild(host);
XMLElement* port = xmlDoc.NewElement("port");
port->SetText(21);
subchild->InsertEndChild(port);
XMLElement* protocol = xmlDoc.NewElement("Protocol");
protocol->SetText(0);
subchild->InsertEndChild(protocol);
XMLElement* type = xmlDoc.NewElement("type");
type->SetText(0);
subchild->InsertEndChild(type);
XMLElement* user = xmlDoc.NewElement("user");
user->SetText("test");
subchild->InsertEndChild(host);
xmlDoc.SaveFile("SavedData.xml");
cout << path << endl;
std::wcout << username << endl;
return 0;
}
The output file looks like this:
<FileZilla3 Version="" platform="">
<Servers>
<Server>
<port>21</port>
<Protocol>0</Protocol>
<type>0</type>
<host>ftp.some.url</host>
</Server>
</Servers>
</FileZilla3>
the desired uotput should be this:
<?xml version="1.0" encoding="UTF-8"?>
<FileZilla3 version="" platform="">
<Servers>
<Server>
<Host>saddf</Host>
<Port>21</Port>
<Protocol>0</Protocol>
<Type>0</Type>
<User>username</User>
<Pass encoding="base64" />
<Logontype>1</Logontype>
<PasvMode>MODE_DEFAULT</PasvMode>
<EncodingType>Auto</EncodingType>
<BypassProxy>0</BypassProxy>
<Name>Ny tjener</Name>
<SyncBrowsing>0</SyncBrowsing>
<DirectoryComparison>0</DirectoryComparison>
</Server>
</Servers>
</FileZilla3>
XMLElement* user = xmlDoc.NewElement("user");
user->SetText("test");
subchild->InsertEndChild(host);
should be
XMLElement* user = xmlDoc.NewElement("user");
user->SetText("test");
subchild->InsertEndChild(user);

How to create dataset from geotiff located in RAM by GDAL

Gdal function for open files use filename to read data like so:
GDALOpen (const char *pszFilename, GDALAccess eAccess)
but my file located in memory. I use next code to create pointer to file:
FILE *stream;
stream = fmemopen(buf, lengthOfArray, "r");
Is it possible to create GDALDataset by pointer to file somehow?
Any tricks and tips?
GDAL has the option to create an in-memory file from a buffer. See:
http://gdal.org/cpl__vsi_8h.html#a86b6b1c37bb19d954ee3c4a7e910120c
I dont have experience with C++, but in Python it looks like:
with open('myfile.tif', mode='rb') as f:
gdal.FileFromMemBuffer('/vsimem/some_memfile', f.read())
You can then open that virtual location as if its a normal file:
ds = gdal.Open('/vsimem/some_memfile')
And when you're done with the file, make sure you unlink it, or it will stick around.
ds = None
gdal.Unlink('/vsimem/some_memfile')
Here is the full example of C++ for processing geotiff file from java bytearray using jni on linux:
#include <jni.h>
#include "gdal_priv.h"
#include "cpl_string.h"
#include "cpl_conv.h"
#include "gdalwarper.h"
#include "cpl_vsi.h"
JNIEXPORT void JNICALL Java_com_box_processing_GEOTransform_run(JNIEnv *env, jobject obj, jbyteArray array) {
GDALAllRegister();
jboolean isCopy;
jbyte* buf = env->GetByteArrayElements(array, &isCopy);
jsize lengthOfArray = env->GetArrayLength(array);
const char *pszFormat = "GTiff";
GDALDriver *poDriver;
poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
VSILFILE* fpMem = VSIFileFromMemBuffer ("/vsimem/temp.tif", (GByte*) buf, (vsi_l_offset) lengthOfArray, FALSE );
VSIFCloseL(fpMem);
GDALDataset *poSrcDS = (GDALDataset *) GDALOpen( "/vsimem/temp.tif", GA_ReadOnly );
GDALDataset *poDstDS;
const char *pszSrcWKT = NULL;
pszSrcWKT=GDALGetProjectionRef(poSrcDS);
double error_threshold = 0.125;
GDALResampleAlg resampling = GRA_Cubic;
char* pszDstWKT = NULL;
GDALDataset * tmpDS = (GDALDataset*)(GDALDataset*)GDALAutoCreateWarpedVRT(poSrcDS, pszSrcWKT, pszDstWKT, resampling, error_threshold, NULL);
poDstDS = poDriver->CreateCopy( "/some/folder/example1.tif", (GDALDataset*)tmpDS, FALSE, NULL, NULL, NULL );
GDALClose( (GDALDatasetH) poDstDS );
GDALClose( (GDALDatasetH) poSrcDS );
VSIUnlink( "/vsimem/temp.tif" );
}

UTF-8 and TinyXML

For some reason I can not read data from a xml file properly.
For example instead of "Schrüder" I get something like "Schrüder".
My code:
tinyxml2::XMLDocument doc;
bool open(string path) {
if(doc.LoadFile(path.c_str()) == XML_SUCCESS)
return true;
return false;
}
int main() {
if(open("C:\\Users\\Admin\\Desktop\\Test.xml"))
cout << "Success" << endl;
XMLNode * node = doc.RootElement();
string test = node->FirstChild()->GetText();
cout << test << endl;
return 0;
}
Part of XML:
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>Schrüder</my:TXT_UTF8Test>
</myXML>
Notice that if I convert it to ANSI and change the encoding type to "ISO-8859-15" it works fine.
I read that something like "LoadFile( filename, TIXML_ENCODING_UTF8 )" should help. However that's not the case (error: Invalid arguments, it just expects a const char). I have the latest version of TinyXML2 (I guess?). I downloaded it just a couple minutes ago from https://github.com/leethomason/tinyxml2.
Any ideas?
Edit: When I write the string to a .xml or .txt file it works fine. There might be some problem with the eclipse ide console. Anyway, when I try to send the string via E-Mail, I also get the same problems. Here's the MailSend script:
bool sendMail(std::string params) {
if( (int) ShellExecute(NULL, "open", "H:\\MailSend\\MailSend_anhang.exe", params.c_str(), NULL, SW_HIDE) <= 32 )
return false;
return true;
}
I call it in the main method like this:
sendMail("-f:d.nitschmann#example.com -t:person2#example.com -s:Subject -b:Body " + test);
I think the problem is with your terminal; can you try run your test code in a different terminal ? one with known good UTF-8 support ?
Output with terminal in UTF-8 mode:
$ ./a.out
Success
Schrüder
Output with terminal in ISO-8859-15 mode:
$ ./a.out
Success
SchrÃŒder
Also - please try and follow http://sscce.org/ - for posterity sake here is your code with everything needed to compile (17676169.cpp):
#include <tinyxml2.h>
#include <string>
#include <iostream>
using namespace std;
using namespace tinyxml2;
tinyxml2::XMLDocument doc;
bool open(string path) {
if(doc.LoadFile(path.c_str()) == XML_SUCCESS)
return true;
return false;
}
int main() {
if(open("Test.xml"))
cout << "Success" << endl;
XMLNode * node = doc.RootElement();
string test = node->FirstChildElement()->GetText();
cout << test << endl;
return 0;
}
compiled with:
g++ -o 17676169 17676169.cpp -ltinyxml2
and uuencoded Test.xml - to ensure exact same data is used
begin 660 Test.xml
M/#]X;6P#=F5R<VEO;CTB,2XP(B!E;F-O9&EN9STB551&+3#B/SX*/&UY6$U,
M/#H#("`#/&UY.E185%]55$8X5&5S=#Y38VARP[QD97(\+VUY.E185%]55$8X
/5&5S=#X*/"]M>5A-3#X*
`
end
Edit 1:
If you want to confirm this theory - run this in eclipse:
#include <iostream>
#include <string>
#include <fstream>
int main()
{
std::ifstream ifs("Test.xml");
std::string xml_data((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
std::cout << xml_data;
}
Output with terminal in UTF-8 mode:
$ ./17676169.cat
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>Schrüder</my:TXT_UTF8Test>
</myXML>
Output with terminal in ISO-8859-15 mode:
$ ./17676169.cat
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>SchrÃŒder</my:TXT_UTF8Test>
</myXML>

TinyXml to parse conf file

I`m try to realize how to use TinyXML library.
I have to parse this conf file:
<?xml version="1.0" encoding="UTF-8"?>
<Client>
<port num = "20035">
<server_addr ip="127.0.0.1">
<AV_list>
<AV>
<AVNAME>BitDefender</AVNAME>>
<AVPATH> C:\Program Files\Common Files\BitDefender\BitDefender Threat Scanner\av64bit_26308\bdc.exe </AVPATH>
<AVMASK>0x80000000</AVMASK>
<AVCOMMANDLINE> %avpath% \log=%avlog% %scanpath% </AVCOMMANDLINE>
<AVREGEX>(%scanpath%.*?)+(([a-zA-Z0-9]+\\.)+[a-zA-Z]{2,4})+(.+[a-zA-Z_])</AVREGEX>
<AVLOG>C:\log\bd_log.txt</AVLOG>
</AV>
</AV_list>
</Client>
And c++ code
#include "stdafx.h"
#include "iostream"
#include "tinyxml.h"
int main(int argc, char* argv[])
{
TiXmlDocument doc( "D:\\client_conf.xml" );
bool loadOkay = doc.LoadFile();
if ( loadOkay )
printf("Yes \n");
else
printf("No \n");
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlText* pText;
TiXmlHandle hRoot(0);
pElem = hDoc.FirstChildElement().Element();
if (!pElem)
printf("error element");
hRoot = TiXmlHandle(pElem);
pElem = hRoot.FirstChild("server_addr").Element();
const char* info = pElem->Attribute("ip");
printf( "%s \n", info);
pElem = hRoot.FirstChild("port").Element();
info = pElem->Attribute("num");
printf( "%s \n", info);
system("pause");
return 0;
}
Now I can get first two param, but dont figure out how to reach "AV_list" block. Any help will be appreciated. (:
Have a look at the TinyXml Documentation. Your friend is the TiXmlNode Class Reference. You may use most of the Node functions also on TiXmlElements.
You already use the FirstChild() function to get the first child of an element; use the NextSibling() function to iterate over all elements. You can also use the NextSiblingElement() function to get the element directly.
Antother more sophisticated solution would be to use XPath to retrieve elements from the xml file. There is TinyXPath that builds on top of TinyXML. It needs some knowledge of XPath but it might be worth it. (XPath standard)