1 // -*- coding: utf-8 -*- 2 // 3 // fgrcc.hxx --- Simple resource compiler for FlightGear 4 // Copyright (C) 2017 Florent Rougon 5 // 6 // This program is free software; you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation; either version 2 of the License, or 9 // (at your option) any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License along 17 // with this program; if not, write to the Free Software Foundation, Inc., 18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 20 #ifndef _FGRCC_HXX_ 21 #define _FGRCC_HXX_ 22 23 #include <ios> 24 #include <iosfwd> 25 #include <vector> 26 #include <array> 27 #include <cstddef> // std::size_t 28 29 #include <simgear/misc/sg_path.hxx> 30 #include <simgear/xml/easyxml.hxx> 31 #include <simgear/embedded_resources/EmbeddedResource.hxx> 32 33 // Simple class to hold data gathered by the parser. Each instance corresponds 34 // to a resource declaration (i.e., to a 'file' element in the XML resource 35 // declaration file). 36 struct ResourceDeclaration 37 { 38 ResourceDeclaration( 39 const SGPath& virtualPath, const SGPath& realPath, 40 const std::string& language, 41 simgear::AbstractEmbeddedResource::CompressionType compressionType); 42 43 bool isCompressed() const; 44 45 SGPath virtualPath; 46 SGPath realPath; 47 std::string language; 48 simgear::AbstractEmbeddedResource::CompressionType compressionType; 49 }; 50 51 // Class for turning a byte stream into a stream of escape sequences suitable 52 // for use inside a C++ string literal. This class could be changed so as to 53 // be *derived* from std::istream, however this is not needed here. 54 class CPPEncoder 55 { 56 public: 57 explicit CPPEncoder(std::istream& inputStream); 58 59 // Used to implement operator<< 60 virtual std::size_t write(std::ostream& oStream); 61 62 private: 63 // errorNumber: should be the 'errno' value set by the failing call. 64 [[ noreturn ]] static void handleWriteError(int errorNumber); 65 66 std::istream& _inputStream; 67 }; 68 69 std::ostream& operator<<(std::ostream&, CPPEncoder&); 70 71 // Generate all the C++ code needed to initialize a set of resources with the 72 // EmbeddedResourceManager. 73 class ResourceCodeGenerator 74 { 75 public: 76 explicit ResourceCodeGenerator( 77 const std::vector<ResourceDeclaration>& resourceDeclarations, 78 std::ostream& outputStream, 79 const SGPath& outputCppFile, 80 const std::string& initFuncName, 81 const SGPath& outputHeaderFile, 82 const std::string& headerIdentifier, 83 std::size_t inBufSize = 262144, 84 std::size_t outBufSize = 242144); 85 86 void writeCode() const; // write the main C++ file 87 void writeHeaderFile() const; // write the associated header file 88 89 private: 90 // Return a string representing the compression type of a resource 91 static std::string resourceClass( 92 simgear::AbstractEmbeddedResource::CompressionType compressionType); 93 // Encode an integral index in a way that can be safely used as part of a 94 // C++ variable name. This is needed because, for instance, 'resource10' is 95 // not a valid C++ variable name. 96 static std::string encodeResourceIndex(std::size_t index); 97 std::size_t writeEncodedResourceContents(const ResourceDeclaration& resDecl) 98 const; 99 100 const std::vector<ResourceDeclaration>& _resDecl; 101 std::ostream& _outputStream; 102 const SGPath _outputCppFile; // SGPath() if stdout, otherwise the path 103 const std::string _initFuncName; // in UTF-8 encoding 104 const SGPath _outputHeaderFile; // SGPath() if header not requested 105 const std::string _headerIdentifier; // in UTF-8 encoding 106 107 const std::size_t _compInBufSize; 108 const std::size_t _compOutBufSize; 109 std::unique_ptr<char[]> _compressionInBuf; 110 std::unique_ptr<char[]> _compressionOutBuf; 111 }; 112 113 // Parser class for XML resource declaration files 114 class ResourceBuilderXMLVisitor: public XMLVisitor 115 { 116 public: 117 explicit ResourceBuilderXMLVisitor(const SGPath& rootDir); 118 119 // Give access to the structured data obtained once parsing is finished 120 const std::vector<ResourceDeclaration>& getResourceDeclarations() const; 121 122 protected: 123 void startElement(const char *name, const XMLAttributes &atts) override; 124 void endElement(const char *name) override; 125 void data(const char *s, int len) override; 126 void warning(const char *message, int line, int column) override; 127 128 private: 129 void startQResourceElement(const XMLAttributes &atts); 130 void startFileElement(const XMLAttributes &atts); 131 void error(const char *message, int line, int column); 132 133 enum class XMLTagType { 134 START = 0, 135 END 136 }; 137 138 static const std::array<std::string, 2> _tagTypeStr; 139 140 enum class ParserState { 141 START = 0, 142 INSIDE_FGRCC_ELT, 143 INSIDE_QRESOURCE_ELT, 144 INSIDE_FILE_ELT, 145 END 146 }; 147 148 static const std::array<std::string, 5> _parserStateStr; 149 150 static bool readBoolean(const std::string& s); 151 152 static simgear::AbstractEmbeddedResource::CompressionType 153 determineCompressionType(const SGPath& resourceFilePath, 154 const std::string& compression); 155 156 [[ noreturn ]] void unexpectedTagError( 157 XMLTagType tagType, const std::string& found, 158 const std::string& expected = std::string()); 159 160 ParserState _parserState = ParserState::START; 161 // Value obtained from the --root command line option 162 const SGPath _rootDir; 163 164 // 'prefix' attribute of the current 'qresource' element 165 std::string _currentPrefix; 166 // 'lang' attribute of the current 'qresource' element 167 std::string _currentLanguage; 168 // 'alias' attribute of the current 'file' element 169 std::string _currentAlias; 170 // This attribute is not part of the v1.0 QRC format, it's a FlightGear 171 // extension. It tells whether, and if so, how the current <file> should be 172 // compressed in the generated code. 173 std::string _currentCompressionTypeStr; 174 // String used to assemble resource file paths declared in 'file' elements 175 // (the contents of an element can be provided in several chunks by 176 // XMLVisitor::data()) 177 std::string _resourceFile; 178 179 // Holds the resulting structured data once the parsing is finished 180 std::vector<ResourceDeclaration> _resourceDeclarations; 181 }; 182 183 #endif // _FGRCC_HXX_ 184