Reputation: 11
I have a problem with TinyXML that can't be able to fix. I have extended an MFC application using C++ for work. The application does automated testing. After it completes it saves all the data in an XML file. Below the beginning of my DOM tree.
<?xml version="1.0" encoding="utf-8" ?>
<TestData>
<Operator>Alex</Operator>
<ParentBarCode>12345
</ParentBarCode>
<Measurements>
The issue is the library seems to be adding a random newline after 12345. It should be:
<ParentBarCode>12345</ParentBarCode>
Could you help me please? I have tried everything... Code snippet below. Also, is there any way to remove a newline before closing the tag of a new element , i.e. before
</ParentBarCode>??
//Code starts here
TiXmlDocument doc;
TiXmlDeclaration * decl = new TiXmlDeclaration("1.0","utf-8", "");
//doc.FirstChildElement();
doc.LinkEndChild(decl);
TiXmlElement *rootelement = new TiXmlElement("TestData");
doc.LinkEndChild(rootelement);
TiXmlText *textTestData = new TiXmlText("");
rootelement->LinkEndChild(textTestData);
//Operator node
TiXmlElement *Operator = new TiXmlElement("Operator");
//Tree root
rootelement->LinkEndChild(Operator);
TiXmlText *textOperator = new TiXmlText("Alex");
Operator->LinkEndChild(textOperator);
//ParentBarcode Node
TiXmlElement *barcode = new TiXmlElement("ParentBarCode");
//Tree root
rootelement->LinkEndChild(barcode);
//saving serial to a stringstream
stringstream serial;
serial << (DlgPtr->m_lSerialNumber);
std::string myserial = serial.str();
//Removing spaces
myserial.erase(std::remove_if(myserial.begin(), myserial.end(),::isspace), myserial.end());
char buffer[sizeof(myserial) + 1];
//int ret = snprintf(buffer, sizeof(myserial), "%05ld", DlgPtr>m_lSerialNumber);
int ret = sprintf_s(buffer, sizeof(myserial), "%05ld", myserial);
const char * charSerial = buffer;
TiXmlText *textbarcode = new TiXmlText(charSerial);
barcode->LinkEndChild(textbarcode);
No error messages, just the element's tag doesn't close on the same line. I made a small sandbox project with the exact same DOM tree but it worked fine there. I was thinking maybe there is another issue I don't see with sprintf_s?? Thank you in advance.
Upvotes: 1
Views: 767
Reputation: 3973
As @AlanBirtles poked at in the comments, this part of your code is not great:
stringstream serial;
serial << (DlgPtr->m_lSerialNumber);
std::string myserial = serial.str();
//Removing spaces
myserial.erase(std::remove_if(myserial.begin(), myserial.end(),::isspace), myserial.end());
char buffer[sizeof(myserial) + 1];
int ret = sprintf_s(buffer, sizeof(myserial), "%05ld", myserial);
const char * charSerial = buffer;
TiXmlText *textbarcode = new TiXmlText(charSerial);
barcode->LinkEndChild(textbarcode);
You start out strong by converting DlgPtr->m_lSerialNumber
into a std::string
:
stringstream serial;
serial << (DlgPtr->m_lSerialNumber);
std::string myserial = serial.str();
This is fine, though from C++11 forward you could also just do:
std::string myserial = std::to_string(DlgPtr->m_lSerialNumber);
Then you remove spaces from myserial
, which doesn't hurt - but I'm pretty sure there won't be any to remove, since you have just constructed the string from a single integer.
This is then where it starts going wrong.
You make a char-array buffer to write your number in, but you size that with sizeof(myserial)
, which gives you the number of bytes that the object takes up in memory, including bookkeeping stuff, vtable pointers, etc. So you wind up allocating too much space here; myserial.size()
would give you a better fit.
Then you try to use sprintf_s
to write the number to the new buffer, but you use "%05ld"
as the format string and a std::string as the argument - that just won't work. "%05ld"
tells sprintf_s
to expect an integer as input (and pad it to 5 digits with extra zeros), so it just takes that argument, casts it to an int, and interprets the first 4 bytes as a number - which makes no sense, and probably invokes undefined behavior.
Not only does this not do what you want it to do, you already have a string with your number in it, and can just call myserial.c_str()
to get a const char*
with the contents of myserial
. This means that the entire second section could be replaced by:
TiXmlText *textbarcode = new TiXmlText(std::to_string(DlgPtr->m_lSerialNumber).c_str());
barcode->LinkEndChild(textbarcode);
Upvotes: 0