Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/libraries/core/Loader.cc @ 10549

Last change on this file since 10549 was 10508, checked in by landauf, 9 years ago

removed unused code from Loader

  • Property svn:eol-style set to native
File size: 16.2 KB
RevLine 
[1505]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "Loader.h"
[2710]30
[5695]31#include <sstream>
[2710]32#include <tinyxml/ticpp.h>
[5695]33#include <boost/scoped_ptr.hpp>
[10264]34#include <boost/filesystem.hpp>
35#include <boost/filesystem/fstream.hpp>
[2710]36
[8858]37#include "util/Output.h"
[3196]38#include "util/Exception.h"
[5695]39#include "util/StringUtils.h"
[1505]40#include "BaseObject.h"
[5695]41#include "LuaState.h"
[1505]42#include "Namespace.h"
[5695]43#include "Resource.h"
[3196]44#include "XMLFile.h"
[9667]45#include "object/Iterator.h"
46#include "object/ObjectList.h"
[1505]47
48namespace orxonox
49{
[10392]50    Loader* Loader::singletonPtr_s = 0;
[1505]51
[7648]52    /**
53    @brief
54        Loads the input file, while conforming to the restrictions given by the input ClassTreeMask.
55    @param file
56        The file to be loaded.
57    @param mask
58        A ClassTreeMask, which defines which types of classes are loaded and which aren't.
[8858]59    @param bVerbose
[7648]60        Whether the loader is verbose (prints its progress in a low output level) or not.
[8108]61    @param bRemoveLuaTags
62        If true lua tags are just ignored and removed. The default is false.
[7648]63    @return
64        Returns true if successful.
65    */
[8858]66    bool Loader::load(const XMLFile* file, const ClassTreeMask& mask, bool bVerbose, bool bRemoveLuaTags)
[1505]67    {
[2087]68        if (!file)
[1755]69            return false;
70
[10392]71        this->currentMask_ = file->getMask() * mask;
[1505]72
[5695]73        std::string xmlInput;
[10264]74
[10265]75        shared_ptr<std::vector<std::vector<std::pair<std::string, size_t> > > > lineTrace(new std::vector<std::vector<std::pair<std::string, size_t> > >());
[10264]76        lineTrace->reserve(1000); //arbitrary number
77
78
[8079]79        if (file->getLuaSupport() && !bRemoveLuaTags)
[5695]80        {
81            // Use the LuaState to replace the XML tags (calls our function)
82            scoped_ptr<LuaState> luaState(new LuaState());
[10264]83            luaState->setTraceMap(lineTrace);
[5695]84            luaState->setIncludeParser(&Loader::replaceLuaTags);
[6417]85            luaState->includeFile(file->getFilename());
[5695]86            xmlInput = luaState->getOutput().str();
87        }
88        else
89        {
[6417]90            shared_ptr<ResourceInfo> info = Resource::getInfo(file->getFilename());
[5695]91            if (info == NULL)
92            {
[8858]93                orxout(user_error, context::loader) << "Could not find XML file '" << file->getFilename() << "'." << endl;
[5695]94                return false;
95            }
[6417]96            xmlInput = Resource::open(file->getFilename())->getAsString();
[8079]97
98            if (bRemoveLuaTags)
99            {
100                // Remove all Lua code.
101                // Note: we only need this to speed up parsing of level files at the
102                // start of the program.
103                // Assumption: the LevelInfo tag does not use Lua scripting
[10392]104                xmlInput = Loader::removeLuaTags(xmlInput);
[8079]105            }
[5695]106        }
[1505]107
108        try
109        {
[8858]110            if(bVerbose)
[7648]111            {
[8858]112                orxout(user_info) << "Start loading " << file->getFilename() << "..." << endl;
[10392]113                orxout(internal_info, context::loader) << "Mask: " << this->currentMask_ << endl;
[7648]114            }
115            else
116            {
[8858]117                orxout(verbose, context::loader) << "Start loading " << file->getFilename() << "..." << endl;
[10392]118                orxout(verbose_more, context::loader) << "Mask: " << this->currentMask_ << endl;
[7648]119            }
[1505]120
[5695]121            ticpp::Document xmlfile(file->getFilename());
122            xmlfile.Parse(xmlInput, true);
[1505]123
124            ticpp::Element rootElement;
125            rootElement.SetAttribute("name", "root");
126            rootElement.SetAttribute("bAutogenerated", true);
127
128            for (ticpp::Iterator<ticpp::Element> child = xmlfile.FirstChildElement(false); child != child.end(); child++)
129                rootElement.InsertEndChild(*child);
130
[8858]131            orxout(verbose, context::loader) << "  creating root-namespace..." << endl;
[9667]132            Namespace* rootNamespace = new Namespace(Context::getRootContext());
[1505]133            rootNamespace->setLoaderIndentation("    ");
[2087]134            rootNamespace->setFile(file);
[1505]135            rootNamespace->setNamespace(rootNamespace);
136            rootNamespace->setRoot(true);
137            rootNamespace->XMLPort(rootElement, XMLPort::LoadObject);
138
[8858]139            if(bVerbose)
140                orxout(user_info) << "Finished loading " << file->getFilename() << '.' << endl;
[7648]141            else
[8858]142                orxout(verbose, context::loader) << "Finished loading " << file->getFilename() << '.' << endl;
[1505]143
[8858]144            orxout(verbose, context::loader) << "Namespace-tree:" << '\n' << rootNamespace->toString("  ") << endl;
[1505]145
146            return true;
147        }
[2171]148        catch (ticpp::Exception& ex)
[1505]149        {
[8858]150            orxout(user_error, context::loader) << endl;
151            orxout(user_error, context::loader) << "An XML-error occurred in Loader.cc while loading " << file->getFilename() << ':' << endl;
[10269]152            OutputLevel ticpplevel = user_error;
[10264]153            if (lineTrace->size() > 0)
154            {
[10269]155                ticpplevel = internal_error;
[10264]156                //Extract the line number from the exception
157                std::string tempstring(ex.what());
158                std::string::size_type pos = tempstring.find("\nLine: ");
159                if (pos != std::string::npos)
160                {
161                    std::istringstream istr(tempstring.substr(pos + 7));
162                    size_t line;
163                    istr >> line;
164                    if (line <= lineTrace->size())
165                    {
[10265]166                        std::vector<std::pair<std::string, size_t> > linesources = lineTrace->at(line - 1);
[10269]167                        std::ostringstream message;
168                        message << "Possible sources of error:" << endl;
[10265]169                        for (std::vector<std::pair<std::string, size_t> >::iterator it = linesources.begin(); it != linesources.end(); ++it)
[10264]170                        {
[10269]171                            message << it->first << ", Line " << it->second << endl;
172                        }
173                        orxout(user_error, context::loader) << message.str() << endl;
[10264]174                    }
175                }
176            }
[10269]177            orxout(ticpplevel, context::loader) << ex.what() << endl;
178            orxout(user_error, context::loader) << "Loading aborted." << endl;
[2171]179        }
180        catch (Exception& ex)
181        {
[8858]182            orxout(user_error, context::loader) << endl;
183            orxout(user_error, context::loader) << "A loading-error occurred in Loader.cc while loading " << file->getFilename() << ':' << endl;
184            orxout(user_error, context::loader) << ex.what() << endl;
185            orxout(user_error, context::loader) << "Loading aborted." << endl;
[2171]186        }
[5747]187        catch (...)
[2171]188        {
[8858]189            orxout(user_error, context::loader) << endl;
190            orxout(user_error, context::loader) << "An error occurred in Loader.cc while loading " << file->getFilename() << ':' << endl;
191            orxout(user_error, context::loader) << Exception::handleMessage() << endl;
192            orxout(user_error, context::loader) << "Loading aborted." << endl;
[1505]193        }
[10264]194        //The Tardis' version of boost is too old...
195#if BOOST_VERSION >= 104600
196        boost::filesystem::path temppath = boost::filesystem::temp_directory_path() / "orxonoxml.xml";
197        //Need binary mode, because xmlInput already has \r\n for windows
198        boost::filesystem::ofstream outfile(temppath, std::ios_base::binary | std::ios_base::out);
199        outfile << xmlInput;
200        outfile.flush();
201        outfile.close();
[10269]202        orxout(internal_error, context::loader) << "The complete xml file has been saved to " << temppath << endl;
[10264]203#endif
204        return false;
[1505]205    }
206
[2087]207    void Loader::unload(const XMLFile* file, const ClassTreeMask& mask)
[1505]208    {
[2087]209        if (!file)
[1755]210            return;
[1747]211        for (ObjectList<BaseObject>::iterator it = ObjectList<BaseObject>::begin(); it; )
[1505]212        {
[2087]213            if ((it->getFile() == file) && mask.isIncluded(it->getIdentifier()))
[5929]214                (it++)->destroy();
[1505]215            else
216                ++it;
217        }
218    }
219
[8079]220    bool Loader::getLuaTags(const std::string& text, std::map<size_t, bool>& luaTags)
[5695]221    {
[8079]222        // fill map with all Lua tags
[5695]223        {
224            size_t pos = 0;
225            while ((pos = text.find("<?lua", pos)) != std::string::npos)
226                luaTags[pos++] = true;
227        }
228        {
229            size_t pos = 0;
230            while ((pos = text.find("?>", pos)) != std::string::npos)
231                luaTags[pos++] = false;
232        }
233
234        // erase all tags from the map that are between two quotes
[10273]235        // that means occurrences like "..<?lua.." and "..?>.." would be deleted
236        // however occurrences of lua tags within quotas are retained: ".. <?lua ... ?> .. "
[5695]237        {
238            std::map<size_t, bool>::iterator it = luaTags.begin();
[10272]239            bool bBetweenQuotes = false;
240            size_t pos = 0;
241            while ((pos = getNextQuote(text, pos)) != std::string::npos)
[5695]242            {
[10272]243                while ((it != luaTags.end()) && (it->first < pos))
[5695]244                {
[10272]245                    if (bBetweenQuotes)
246                    {
[10273]247                        std::map<size_t, bool>::iterator it2 = it;
[10272]248                        it2++;
249                        if (it->second && !(it2->second) && it2->first < pos)
[10273]250                            std::advance(it, 2);
[10272]251                        else
252                            luaTags.erase(it++);
253                    }
254                    else
255                        ++it;
[5695]256                }
[10272]257                bBetweenQuotes = !bBetweenQuotes;
258                pos++;
[5695]259            }
260        }
261
262        // check whether on every opening <?lua tag a closing ?> tag follows
263        {
264            bool expectedValue = true;
265            for (std::map<size_t, bool>::iterator it = luaTags.begin(); it != luaTags.end(); ++it)
266            {
267                if (it->second == expectedValue)
268                    expectedValue = !expectedValue;
269                else
270                {
271                    expectedValue = false;
272                    break;
273                }
274            }
275            if (!expectedValue)
276            {
[10264]277                orxout(internal_error, context::loader) << "Error parsing file: lua tags not matching" << endl;
[8079]278                // TODO: error handling
[8858]279                return false;
[5695]280            }
281        }
282
[8079]283        return true;
284    }
285
286    std::string Loader::replaceLuaTags(const std::string& text)
287    {
288        // create a map with all lua tags
289        std::map<size_t, bool> luaTags;
290        if (!getLuaTags(text, luaTags))
291            return "";
292
[5695]293        // Use a stringstream object to speed up the parsing
294        std::ostringstream output;
295
296        // cut the original string into pieces and put them together with print() instead of lua tags
297        {
298            std::map<size_t, bool>::iterator it = luaTags.begin();
299            bool bInPrintFunction = true;
300            size_t start = 0;
301            size_t end = 0;
302
303            do
304            {
305                if (it != luaTags.end())
[6417]306                    end = (it++)->first;
[5695]307                else
308                    end = std::string::npos;
309
310                unsigned int equalSignCounter = 0;
311
312                if (bInPrintFunction)
313                {
314                    // count ['='[ and ]'='] and replace tags with print([[ and ]])
[6417]315                    const std::string& temp = text.substr(start, end - start);
[5695]316                    {
317                    size_t pos = 0;
318                    while ((pos = temp.find('[', pos)) != std::string::npos)
319                    {
320                        unsigned int tempCounter = 1;
321                        size_t tempPos = pos++;
[6422]322                        while (temp[++tempPos] == '=')
[5695]323                        {
324                            tempCounter++;
325                        }
[6422]326                        if (temp[tempPos] != '[')
[5695]327                        {
328                            tempCounter = 0;
329                        }
[6422]330                        else if (tempCounter == 0)
[5695]331                        {
332                            tempCounter = 1;
333                        }
334                        if (tempCounter > equalSignCounter)
335                            equalSignCounter = tempCounter;
336                        }
337                    }
338                    {
339                        size_t pos = 0;
340                        while ((pos = temp.find(']', pos)) != std::string::npos)
341                        {
342                            unsigned int tempCounter = 1;
343                            size_t tempPos = pos++;
[6422]344                            while (temp[++tempPos] == '=')
[5695]345                            {
346                                tempCounter++;
347                            }
[6422]348                            if (temp[tempPos] != ']')
[5695]349                            {
350                                tempCounter = 0;
351                            }
[6422]352                            else if (tempCounter == 0)
[5695]353                            {
354                                tempCounter = 1;
355                            }
356                            if (tempCounter > equalSignCounter)
357                                equalSignCounter = tempCounter;
358                        }
359                    }
[6417]360                    std::string equalSigns;
[6422]361                    for (unsigned int i = 0; i < equalSignCounter; i++)
[5695]362                    {
[6417]363                        equalSigns += '=';
[5695]364                    }
[10264]365                    //A newline directly after square brackets is ignored. To make sure that the string is printed
366                    //exactly as it is, including newlines at the beginning, insert a space after the brackets.
[10278]367                    bool needsExtraSpace = false;
368                    if (temp.size() > 0 && (temp[0] == '\n' || temp[0] == '\r')) // begins with \n or \r (a line break)
369                        needsExtraSpace = true;
370                    output << "print([" + equalSigns + (needsExtraSpace ? "[ " : "[") + temp + ']' + equalSigns +"])";
[5695]371                    start = end + 5;
372                }
373                else
374                {
375                    output << text.substr(start, end - start);
376                    start = end + 2;
377                }
378
379                bInPrintFunction = !bInPrintFunction;
380            }
381            while (end != std::string::npos);
382        }
383
384        return output.str();
385    }
[8079]386
387    std::string Loader::removeLuaTags(const std::string& text)
388    {
389        // create a map with all lua tags
390        std::map<size_t, bool> luaTags;
391        if (!getLuaTags(text, luaTags))
392            return "";
393
394        // Use a stringstream object to speed up the concatenation
395        std::ostringstream output;
396
397        // cut the original string into pieces and only write the non Lua parts
398        std::map<size_t, bool>::iterator it = luaTags.begin();
399        bool bLuaCode = false;
400        size_t start = 0;
401        size_t end = 0;
402
403        do
404        {
405            if (it != luaTags.end())
406                end = (it++)->first;
407            else
408                end = std::string::npos;
409
410            if (!bLuaCode)
411            {
412                output << text.substr(start, end - start);
413                start = end + 5;
414            }
415            else
[10264]416            {
417                //Preserve the amount of lines, otherwise the linenumber from the xml parse error is useless
418                std::string tempstring = text.substr(start, end - start);
419                output << std::string(std::count(tempstring.begin(), tempstring.end(), '\n'), '\n');
[8079]420                start = end + 2;
[10264]421            }
[8079]422
423            bLuaCode = !bLuaCode;
424        }
425        while (end != std::string::npos);
426
427        return output.str();
428    }
[1505]429}
Note: See TracBrowser for help on using the repository browser.