3

I am working on a project in C++ with Eclipse Helios, QT 4.6.1 integration plugin and boost 1.52 libraries. I'd like to extract some information to work with from a xml file and I'm currently doing so by calling boost function const read_xml(std::string &, Ptree &, int = 0, const std::locale & = std::locale()).

The point is that I'd like to avoid final users to access that xml resource from the release folder and I have no idea of how to do it. Is there any (easy) way I could possibly treat that xml content from inside the executable in order to load it into memory and carry on with the rest of the process as I'm already doing with the xml file being treated as a project resource? Any tips would me more than appreciated.

Thanks in advance.

grover999
  • 225
  • 1
  • 2
  • 6

3 Answers3

2

If you want to prevent the users of your program from modifying the XML file, you should use resources, to compile the file inside the executable.

If you are already using Qt, then by all means have a look at qrc in Qt 4.6. Qt provides a nice system independent way of embedding resource files into the executable. If your project is not already using Qt, then you probably don't want to add it just for that.

If you want a Windows-specific resource file, you can have a look at .rc files documentation. To check what was inside compiled resource files, I used ResEdit in the past and found it really useful. You can even create resource files with it.

If you are targeting Mac OS, you probably want to have a look at bundles, which are sort of a directory where you can put your resources. If you sign your application you can prevent the user to modify any file in the bundle (I'm not sure signing it is required though, I don't have much experience on Mac OS development).

And if you are targeting Linux or similar, you can try doing this trick which seems to work quite well.

All these methods aim to only embed your XML file into your executable, so that your users cannot easily modify it (well, in theory it is still possible but Muggles won't be able to do so). Reading the file may depend on the solution you choose. I personally dislike the Windows resource system and use it only when I really have to, avoiding the Win32 API like plague. If you choose to use Qt, it is quite easy to read the file, and you can do it with boost if you want to. Instead of reading the file at "resources/config.xml", you point to the resource file using ":/config.xml". Here would be the resource file:

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>config.xml</file>
</qresource>
</RCC>

Then when you read it, I'm not sure if you have to use a Qt class to access it or not, but even if you do, you can open the file using QFile and call readAll, then use the result with boost:

QFile myConfigFile(":/config.xml");
if (!myConfigFile.open(QIODevice::ReadOnly | QIODevice::Text))
     return;
read_xml(QString(myConfigFile.readAll()), [...]);

I haven't tested it but it should work with something like that.

Uflex
  • 1,396
  • 1
  • 13
  • 32
  • Thanks for your answer Uflex. However, after reading the documentation I'm not completely sure this alternative is meant to be used with non-QT functionality. I'll try it combining with QDir so maybe I could handle the internal path and pass it to the Boost read_xml function. What do you think? – grover999 Jun 04 '13 at 06:45
  • Oh, I thought you said you were using Qt 4.6 already. If you are, then I think qrc is the best way to do what you want. If not on the other hand, it may not be a wise choice to add it to the project "just" for that. What OS do you target? There are other solutions but they are system dependent, Qt's solution with qrc is nice because it will be working on all supported OSes. – Uflex Jun 04 '13 at 10:02
  • My final comments at the end of this page. Thanks! – grover999 Jun 06 '13 at 13:38
1

The read_xml is overloaded. You are probably refering to this function:

read_xml(filename ... )

but there is also

read_xml(stream ...)

where stream is any std::istream object produced in any way. You could even have a hard-coded string in your source converted to a stream.

CygnusX1
  • 20,968
  • 5
  • 65
  • 109
  • I also 1st thought of using an XML text as literal, but that's obviously not what the OP wants. Besides that hard coding XML as string literal is a really tedious job ... The question is IMHO, how the XML-text can be attached or bundled with the executable and be opened as a stream. – πάντα ῥεῖ Jun 03 '13 at 18:17
  • 1
    It would be nice to have some preprocessing trick where you simply could use `#include "MyXmlText.xml"` or s.th. similar, to convert the XML text to a string (const char*) literal that can be used with a `std::stringstream` instance. Need's to escape all special characters like `"`, `\\`, etc. – πάντα ῥεῖ Jun 03 '13 at 18:39
  • Thanks for your replies. Unfortunately, I'm afraid my xml file too large to be handled via string instances. I rather look for a boost-based (or similar) approach. – grover999 Jun 04 '13 at 06:21
1

Thanks again for your tip Uflex. The point with my application was using QT but only for the GUI functionality, avoiding its use in the application controller underneath...

I've just checked your approach and it is mostly what I was looking for, except for the last line, since read_xml function accepts strings with the path to the xml file or stringstreams with the content of that xml. So, after combining your explanation with these two links:

How to feed Boost.PropertyTree with a string, not a file?

http://doc.qt.digia.com/4.6/resources.html

we are ready to go...

istringstream ss;
QFile file (QString::fromStdString(pathString));
if(file.open(QIODevice::ReadOnly | QIODevice::Text)){
    ss.str(QString(file.readAll()).toStdString());
    read_xml(ss, ...)
    ...
}
Community
  • 1
  • 1
grover999
  • 225
  • 1
  • 2
  • 6