| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: wxrc.cpp |
| 3 | // Purpose: XML resource compiler |
| 4 | // Author: Vaclav Slavik, Eduardo Marques <edrdo@netcabo.pt> |
| 5 | // Created: 2000/03/05 |
| 6 | // RCS-ID: $Id$ |
| 7 | // Copyright: (c) 2000 Vaclav Slavik |
| 8 | // Licence: wxWindows licence |
| 9 | ///////////////////////////////////////////////////////////////////////////// |
| 10 | |
| 11 | // For compilers that support precompilation, includes "wx/wx.h". |
| 12 | #include "wx/wxprec.h" |
| 13 | |
| 14 | #ifdef __BORLANDC__ |
| 15 | #pragma hdrstop |
| 16 | #endif |
| 17 | |
| 18 | // for all others, include the necessary headers |
| 19 | #ifndef WX_PRECOMP |
| 20 | #include "wx/app.h" |
| 21 | #include "wx/log.h" |
| 22 | #endif |
| 23 | |
| 24 | #include "wx/cmdline.h" |
| 25 | #include "wx/xml/xml.h" |
| 26 | #include "wx/ffile.h" |
| 27 | #include "wx/filename.h" |
| 28 | #include "wx/wfstream.h" |
| 29 | #include "wx/utils.h" |
| 30 | |
| 31 | |
| 32 | class XRCWidgetData |
| 33 | { |
| 34 | public: |
| 35 | XRCWidgetData(const wxString& vname,const wxString& vclass) |
| 36 | : m_class(vclass), m_name(vname) {} |
| 37 | const wxString& GetName() const { return m_name; } |
| 38 | const wxString& GetClass() const { return m_class; } |
| 39 | private: |
| 40 | wxString m_class; |
| 41 | wxString m_name; |
| 42 | }; |
| 43 | |
| 44 | #include "wx/arrimpl.cpp" |
| 45 | WX_DECLARE_OBJARRAY(XRCWidgetData,ArrayOfXRCWidgetData); |
| 46 | WX_DEFINE_OBJARRAY(ArrayOfXRCWidgetData) |
| 47 | |
| 48 | class XRCWndClassData |
| 49 | { |
| 50 | private: |
| 51 | wxString m_className; |
| 52 | wxString m_parentClassName; |
| 53 | ArrayOfXRCWidgetData m_wdata; |
| 54 | |
| 55 | void BrowseXmlNode(wxXmlNode* node) |
| 56 | { |
| 57 | wxString classValue; |
| 58 | wxString nameValue; |
| 59 | wxXmlNode* children; |
| 60 | while (node) |
| 61 | { |
| 62 | if (node->GetName() == _T("object") |
| 63 | && node->GetPropVal(_T("class"),&classValue) |
| 64 | && node->GetPropVal(_T("name"),&nameValue)) |
| 65 | { |
| 66 | m_wdata.Add(XRCWidgetData(nameValue,classValue)); |
| 67 | } |
| 68 | children = node->GetChildren(); |
| 69 | if (children) |
| 70 | BrowseXmlNode(children); |
| 71 | node = node->GetNext(); |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | public: |
| 76 | XRCWndClassData(const wxString& className,const wxString& parentClassName, const wxXmlNode* node) : |
| 77 | m_className(className) , m_parentClassName(parentClassName) |
| 78 | { |
| 79 | BrowseXmlNode(node->GetChildren()); |
| 80 | } |
| 81 | |
| 82 | const ArrayOfXRCWidgetData& GetWidgetData() |
| 83 | { |
| 84 | return m_wdata; |
| 85 | } |
| 86 | |
| 87 | bool IsRealClass(const wxString& name) |
| 88 | { |
| 89 | if (name == _T("tool") || |
| 90 | name == _T("unknown") || |
| 91 | name == _T("notebookpage") || |
| 92 | name == _T("separator") || |
| 93 | name == _T("sizeritem") || |
| 94 | name == _T("wxMenuItem")) |
| 95 | { |
| 96 | return false; |
| 97 | } |
| 98 | return true; |
| 99 | } |
| 100 | |
| 101 | void GenerateHeaderCode(wxFFile& file) |
| 102 | { |
| 103 | |
| 104 | file.Write(_T("class ") + m_className + _T(" : public ") + m_parentClassName |
| 105 | + _T(" {\nprotected:\n")); |
| 106 | size_t i; |
| 107 | for(i=0;i<m_wdata.Count();++i) |
| 108 | { |
| 109 | const XRCWidgetData& w = m_wdata.Item(i); |
| 110 | if( !IsRealClass(w.GetClass()) ) continue; |
| 111 | if( w.GetName().Length() == 0 ) continue; |
| 112 | file.Write( |
| 113 | _T(" ") + w.GetClass() + _T("* ") + w.GetName() |
| 114 | + _T(";\n")); |
| 115 | } |
| 116 | file.Write(_T("\nprivate:\n void InitWidgetsFromXRC(){\n") |
| 117 | _T(" wxXmlResource::Get()->LoadObject(this,NULL,_T(\"") |
| 118 | + m_className |
| 119 | + _T("\"), _T(\"") |
| 120 | + m_parentClassName |
| 121 | + _T("\"));\n")); |
| 122 | for(i=0;i<m_wdata.Count();++i) |
| 123 | { |
| 124 | const XRCWidgetData& w = m_wdata.Item(i); |
| 125 | if( !IsRealClass(w.GetClass()) ) continue; |
| 126 | if( w.GetName().Length() == 0 ) continue; |
| 127 | file.Write( _T(" ") |
| 128 | + w.GetName() |
| 129 | + _T(" = XRCCTRL(*this,\"") |
| 130 | + w.GetName() |
| 131 | + _T("\",") |
| 132 | + w.GetClass() |
| 133 | + _T(");\n") |
| 134 | ); |
| 135 | } |
| 136 | file.Write(_T(" }\n")); |
| 137 | |
| 138 | file.Write( |
| 139 | _T("public:\n") |
| 140 | + m_className |
| 141 | + _T("::") |
| 142 | + m_className |
| 143 | + _T("(){\n") |
| 144 | + _T(" InitWidgetsFromXRC();\n") |
| 145 | _T(" }\n") |
| 146 | _T("};\n") |
| 147 | ); |
| 148 | }; |
| 149 | }; |
| 150 | WX_DECLARE_OBJARRAY(XRCWndClassData,ArrayOfXRCWndClassData); |
| 151 | WX_DEFINE_OBJARRAY(ArrayOfXRCWndClassData) |
| 152 | |
| 153 | |
| 154 | class XmlResApp : public wxAppConsole |
| 155 | { |
| 156 | public: |
| 157 | // don't use builtin cmd line parsing: |
| 158 | virtual bool OnInit() { return true; } |
| 159 | virtual int OnRun(); |
| 160 | |
| 161 | private: |
| 162 | void ParseParams(const wxCmdLineParser& cmdline); |
| 163 | void CompileRes(); |
| 164 | wxArrayString PrepareTempFiles(); |
| 165 | void FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath); |
| 166 | |
| 167 | wxString GetInternalFileName(const wxString& name, const wxArrayString& flist); |
| 168 | void DeleteTempFiles(const wxArrayString& flist); |
| 169 | void MakePackageZIP(const wxArrayString& flist); |
| 170 | void MakePackageCPP(const wxArrayString& flist); |
| 171 | void MakePackagePython(const wxArrayString& flist); |
| 172 | |
| 173 | void OutputGettext(); |
| 174 | wxArrayString FindStrings(); |
| 175 | wxArrayString FindStrings(wxXmlNode *node); |
| 176 | |
| 177 | bool flagVerbose, flagCPP, flagPython, flagGettext; |
| 178 | wxString parOutput, parFuncname, parOutputPath; |
| 179 | wxArrayString parFiles; |
| 180 | int retCode; |
| 181 | |
| 182 | ArrayOfXRCWndClassData aXRCWndClassData; |
| 183 | bool flagH; |
| 184 | void GenCPPHeader(); |
| 185 | }; |
| 186 | |
| 187 | IMPLEMENT_APP_CONSOLE(XmlResApp) |
| 188 | |
| 189 | int XmlResApp::OnRun() |
| 190 | { |
| 191 | static const wxCmdLineEntryDesc cmdLineDesc[] = |
| 192 | { |
| 193 | { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show help message"), |
| 194 | wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, |
| 195 | { wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose"), (wxCmdLineParamType)0, 0 }, |
| 196 | { wxCMD_LINE_SWITCH, _T("e"), _T("extra-cpp-code"), _T("output C++ header file with XRC derived classes"), (wxCmdLineParamType)0, 0 }, |
| 197 | { wxCMD_LINE_SWITCH, _T("c"), _T("cpp-code"), _T("output C++ source rather than .rsc file"), (wxCmdLineParamType)0, 0 }, |
| 198 | { wxCMD_LINE_SWITCH, _T("p"), _T("python-code"), _T("output wxPython source rather than .rsc file"), (wxCmdLineParamType)0, 0 }, |
| 199 | { wxCMD_LINE_SWITCH, _T("g"), _T("gettext"), _T("output list of translatable strings (to stdout or file if -o used)"), (wxCmdLineParamType)0, 0 }, |
| 200 | { wxCMD_LINE_OPTION, _T("n"), _T("function"), _T("C++/Python function name (with -c or -p) [InitXmlResource]"), (wxCmdLineParamType)0, 0 }, |
| 201 | { wxCMD_LINE_OPTION, _T("o"), _T("output"), _T("output file [resource.xrs/cpp]"), (wxCmdLineParamType)0, 0 }, |
| 202 | #if 0 // not yet implemented |
| 203 | { wxCMD_LINE_OPTION, _T("l"), _T("list-of-handlers"), _T("output list of necessary handlers to this file"), (wxCmdLineParamType)0, 0 }, |
| 204 | #endif |
| 205 | { wxCMD_LINE_PARAM, NULL, NULL, _T("input file(s)"), |
| 206 | wxCMD_LINE_VAL_STRING, |
| 207 | wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_OPTION_MANDATORY }, |
| 208 | |
| 209 | { wxCMD_LINE_NONE, NULL, NULL, NULL, (wxCmdLineParamType)0, 0 } |
| 210 | }; |
| 211 | |
| 212 | wxCmdLineParser parser(cmdLineDesc, argc, argv); |
| 213 | |
| 214 | switch (parser.Parse()) |
| 215 | { |
| 216 | case -1: |
| 217 | return 0; |
| 218 | |
| 219 | case 0: |
| 220 | retCode = 0; |
| 221 | ParseParams(parser); |
| 222 | if (flagGettext) |
| 223 | OutputGettext(); |
| 224 | else |
| 225 | CompileRes(); |
| 226 | return retCode; |
| 227 | } |
| 228 | return 1; |
| 229 | } |
| 230 | |
| 231 | |
| 232 | |
| 233 | |
| 234 | void XmlResApp::ParseParams(const wxCmdLineParser& cmdline) |
| 235 | { |
| 236 | flagGettext = cmdline.Found(_T("g")); |
| 237 | flagVerbose = cmdline.Found(_T("v")); |
| 238 | flagCPP = cmdline.Found(_T("c")); |
| 239 | flagPython = cmdline.Found(_T("p")); |
| 240 | flagH = flagCPP && cmdline.Found(_T("e")); |
| 241 | |
| 242 | |
| 243 | if (!cmdline.Found(_T("o"), &parOutput)) |
| 244 | { |
| 245 | if (flagGettext) |
| 246 | parOutput = wxEmptyString; |
| 247 | else |
| 248 | { |
| 249 | if (flagCPP) |
| 250 | parOutput = _T("resource.cpp"); |
| 251 | else if (flagPython) |
| 252 | parOutput = _T("resource.py"); |
| 253 | else |
| 254 | parOutput = _T("resource.xrs"); |
| 255 | } |
| 256 | } |
| 257 | if (!parOutput.empty()) |
| 258 | { |
| 259 | wxFileName fn(parOutput); |
| 260 | fn.Normalize(); |
| 261 | parOutput = fn.GetFullPath(); |
| 262 | parOutputPath = wxPathOnly(parOutput); |
| 263 | } |
| 264 | if (!parOutputPath) parOutputPath = _T("."); |
| 265 | |
| 266 | if (!cmdline.Found(_T("n"), &parFuncname)) |
| 267 | parFuncname = _T("InitXmlResource"); |
| 268 | |
| 269 | for (size_t i = 0; i < cmdline.GetParamCount(); i++) |
| 270 | { |
| 271 | #ifdef __WINDOWS__ |
| 272 | wxString fn=wxFindFirstFile(cmdline.GetParam(i), wxFILE); |
| 273 | while (!fn.empty()) |
| 274 | { |
| 275 | parFiles.Add(fn); |
| 276 | fn=wxFindNextFile(); |
| 277 | } |
| 278 | #else |
| 279 | parFiles.Add(cmdline.GetParam(i)); |
| 280 | #endif |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | |
| 285 | |
| 286 | |
| 287 | void XmlResApp::CompileRes() |
| 288 | { |
| 289 | wxArrayString files = PrepareTempFiles(); |
| 290 | |
| 291 | wxRemoveFile(parOutput); |
| 292 | |
| 293 | if (!retCode) |
| 294 | { |
| 295 | if (flagCPP){ |
| 296 | MakePackageCPP(files); |
| 297 | if (flagH) |
| 298 | GenCPPHeader(); |
| 299 | } |
| 300 | else if (flagPython) |
| 301 | MakePackagePython(files); |
| 302 | else |
| 303 | MakePackageZIP(files); |
| 304 | } |
| 305 | |
| 306 | DeleteTempFiles(files); |
| 307 | } |
| 308 | |
| 309 | |
| 310 | wxString XmlResApp::GetInternalFileName(const wxString& name, const wxArrayString& flist) |
| 311 | { |
| 312 | wxString name2 = name; |
| 313 | name2.Replace(_T(":"), _T("_")); |
| 314 | name2.Replace(_T("/"), _T("_")); |
| 315 | name2.Replace(_T("\\"), _T("_")); |
| 316 | name2.Replace(_T("*"), _T("_")); |
| 317 | name2.Replace(_T("?"), _T("_")); |
| 318 | |
| 319 | wxString s = wxFileNameFromPath(parOutput) + _T("$") + name2; |
| 320 | |
| 321 | if (wxFileExists(s) && flist.Index(s) == wxNOT_FOUND) |
| 322 | { |
| 323 | for (int i = 0;; i++) |
| 324 | { |
| 325 | s.Printf(wxFileNameFromPath(parOutput) + _T("$%03i-") + name2, i); |
| 326 | if (!wxFileExists(s) || flist.Index(s) != wxNOT_FOUND) |
| 327 | break; |
| 328 | } |
| 329 | } |
| 330 | return s; |
| 331 | } |
| 332 | |
| 333 | wxArrayString XmlResApp::PrepareTempFiles() |
| 334 | { |
| 335 | wxArrayString flist; |
| 336 | |
| 337 | for (size_t i = 0; i < parFiles.Count(); i++) |
| 338 | { |
| 339 | if (flagVerbose) |
| 340 | wxPrintf(_T("processing ") + parFiles[i] + _T("...\n")); |
| 341 | |
| 342 | wxXmlDocument doc; |
| 343 | |
| 344 | if (!doc.Load(parFiles[i])) |
| 345 | { |
| 346 | wxLogError(_T("Error parsing file ") + parFiles[i]); |
| 347 | retCode = 1; |
| 348 | continue; |
| 349 | } |
| 350 | |
| 351 | wxString name, ext, path; |
| 352 | wxSplitPath(parFiles[i], &path, &name, &ext); |
| 353 | |
| 354 | FindFilesInXML(doc.GetRoot(), flist, path); |
| 355 | if (flagH) |
| 356 | { |
| 357 | wxXmlNode* node = (doc.GetRoot())->GetChildren(); |
| 358 | wxString classValue,nameValue; |
| 359 | while(node){ |
| 360 | if(node->GetName() == _T("object") |
| 361 | && node->GetPropVal(_T("class"),&classValue) |
| 362 | && node->GetPropVal(_T("name"),&nameValue)){ |
| 363 | |
| 364 | aXRCWndClassData.Add( |
| 365 | XRCWndClassData(nameValue,classValue,node) |
| 366 | ); |
| 367 | } |
| 368 | node = node -> GetNext(); |
| 369 | } |
| 370 | } |
| 371 | wxString internalName = GetInternalFileName(parFiles[i], flist); |
| 372 | |
| 373 | doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName); |
| 374 | flist.Add(internalName); |
| 375 | } |
| 376 | |
| 377 | return flist; |
| 378 | } |
| 379 | |
| 380 | |
| 381 | // Does 'node' contain filename information at all? |
| 382 | static bool NodeContainsFilename(wxXmlNode *node) |
| 383 | { |
| 384 | // Any bitmaps: |
| 385 | if (node->GetName() == _T("bitmap")) |
| 386 | return true; |
| 387 | |
| 388 | if (node->GetName() == _T("icon")) |
| 389 | return true; |
| 390 | |
| 391 | // URLs in wxHtmlWindow: |
| 392 | if (node->GetName() == _T("url")) |
| 393 | return true; |
| 394 | |
| 395 | // wxBitmapButton: |
| 396 | wxXmlNode *parent = node->GetParent(); |
| 397 | if (parent != NULL && |
| 398 | parent->GetPropVal(_T("class"), _T("")) == _T("wxBitmapButton") && |
| 399 | (node->GetName() == _T("focus") || |
| 400 | node->GetName() == _T("disabled") || |
| 401 | node->GetName() == _T("selected"))) |
| 402 | return true; |
| 403 | |
| 404 | // wxBitmap or wxIcon toplevel resources: |
| 405 | if (node->GetName() == _T("object")) |
| 406 | { |
| 407 | wxString klass = node->GetPropVal(_T("class"), wxEmptyString); |
| 408 | if (klass == _T("wxBitmap") || klass == _T("wxIcon")) |
| 409 | return true; |
| 410 | } |
| 411 | |
| 412 | return false; |
| 413 | } |
| 414 | |
| 415 | // find all files mentioned in structure, e.g. <bitmap>filename</bitmap> |
| 416 | void XmlResApp::FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath) |
| 417 | { |
| 418 | // Is 'node' XML node element? |
| 419 | if (node == NULL) return; |
| 420 | if (node->GetType() != wxXML_ELEMENT_NODE) return; |
| 421 | |
| 422 | bool containsFilename = NodeContainsFilename(node); |
| 423 | |
| 424 | wxXmlNode *n = node->GetChildren(); |
| 425 | while (n) |
| 426 | { |
| 427 | if (containsFilename && |
| 428 | (n->GetType() == wxXML_TEXT_NODE || |
| 429 | n->GetType() == wxXML_CDATA_SECTION_NODE)) |
| 430 | { |
| 431 | wxString fullname; |
| 432 | if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty()) |
| 433 | fullname = n->GetContent(); |
| 434 | else |
| 435 | fullname = inputPath + wxFILE_SEP_PATH + n->GetContent(); |
| 436 | |
| 437 | if (flagVerbose) |
| 438 | wxPrintf(_T("adding ") + fullname + _T("...\n")); |
| 439 | |
| 440 | wxString filename = GetInternalFileName(n->GetContent(), flist); |
| 441 | n->SetContent(filename); |
| 442 | |
| 443 | if (flist.Index(filename) == wxNOT_FOUND) |
| 444 | flist.Add(filename); |
| 445 | |
| 446 | wxFileInputStream sin(fullname); |
| 447 | wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename); |
| 448 | sin.Read(sout); // copy the stream |
| 449 | } |
| 450 | |
| 451 | // subnodes: |
| 452 | if (n->GetType() == wxXML_ELEMENT_NODE) |
| 453 | FindFilesInXML(n, flist, inputPath); |
| 454 | |
| 455 | n = n->GetNext(); |
| 456 | } |
| 457 | } |
| 458 | |
| 459 | |
| 460 | |
| 461 | void XmlResApp::DeleteTempFiles(const wxArrayString& flist) |
| 462 | { |
| 463 | for (size_t i = 0; i < flist.Count(); i++) |
| 464 | wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]); |
| 465 | } |
| 466 | |
| 467 | |
| 468 | |
| 469 | void XmlResApp::MakePackageZIP(const wxArrayString& flist) |
| 470 | { |
| 471 | wxString files; |
| 472 | |
| 473 | for (size_t i = 0; i < flist.Count(); i++) |
| 474 | files += flist[i] + _T(" "); |
| 475 | files.RemoveLast(); |
| 476 | |
| 477 | if (flagVerbose) |
| 478 | wxPrintf(_T("compressing ") + parOutput + _T("...\n")); |
| 479 | |
| 480 | wxString cwd = wxGetCwd(); |
| 481 | wxSetWorkingDirectory(parOutputPath); |
| 482 | int execres = wxExecute(_T("zip -9 -j ") + |
| 483 | wxString(flagVerbose ? _T("\"") : _T("-q \"")) + |
| 484 | parOutput + _T("\" ") + files, true); |
| 485 | wxSetWorkingDirectory(cwd); |
| 486 | if (execres == -1) |
| 487 | { |
| 488 | wxLogError(_T("Unable to execute zip program. Make sure it is in the path.")); |
| 489 | wxLogError(_T("You can download it at http://www.cdrom.com/pub/infozip/")); |
| 490 | retCode = 1; |
| 491 | return; |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | |
| 496 | |
| 497 | static wxString FileToCppArray(wxString filename, int num) |
| 498 | { |
| 499 | wxString output; |
| 500 | wxString tmp; |
| 501 | wxString snum; |
| 502 | wxFFile file(filename, wxT("rb")); |
| 503 | wxFileOffset offset = file.Length(); |
| 504 | wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") ); |
| 505 | |
| 506 | const size_t lng = wx_truncate_cast(size_t, offset); |
| 507 | wxASSERT_MSG( lng == offset, wxT("Huge file not supported") ); |
| 508 | |
| 509 | snum.Printf(_T("%i"), num); |
| 510 | output.Printf(_T("static size_t xml_res_size_") + snum + _T(" = %i;\n"), lng); |
| 511 | output += _T("static unsigned char xml_res_file_") + snum + _T("[] = {\n"); |
| 512 | // we cannot use string literals because MSVC is dumb wannabe compiler |
| 513 | // with arbitrary limitation to 2048 strings :( |
| 514 | |
| 515 | unsigned char *buffer = new unsigned char[lng]; |
| 516 | file.Read(buffer, lng); |
| 517 | |
| 518 | for (size_t i = 0, linelng = 0; i < lng; i++) |
| 519 | { |
| 520 | tmp.Printf(_T("%i"), buffer[i]); |
| 521 | if (i != 0) output << _T(','); |
| 522 | if (linelng > 70) |
| 523 | { |
| 524 | linelng = 0; |
| 525 | output << _T("\n"); |
| 526 | } |
| 527 | output << tmp; |
| 528 | linelng += tmp.Length()+1; |
| 529 | } |
| 530 | |
| 531 | delete[] buffer; |
| 532 | |
| 533 | output += _T("};\n\n"); |
| 534 | |
| 535 | return output; |
| 536 | } |
| 537 | |
| 538 | |
| 539 | void XmlResApp::MakePackageCPP(const wxArrayString& flist) |
| 540 | { |
| 541 | wxFFile file(parOutput, wxT("wt")); |
| 542 | size_t i; |
| 543 | |
| 544 | if (flagVerbose) |
| 545 | wxPrintf(_T("creating C++ source file ") + parOutput + _T("...\n")); |
| 546 | |
| 547 | file.Write(_T("") |
| 548 | _T("//\n") |
| 549 | _T("// This file was automatically generated by wxrc, do not edit by hand.\n") |
| 550 | _T("//\n\n") |
| 551 | _T("#include <wx/wxprec.h>\n") |
| 552 | _T("\n") |
| 553 | _T("#ifdef __BORLANDC__\n") |
| 554 | _T(" #pragma hdrstop\n") |
| 555 | _T("#endif\n") |
| 556 | _T("\n") |
| 557 | _T("") |
| 558 | _T("#include <wx/filesys.h>\n") |
| 559 | _T("#include <wx/fs_mem.h>\n") |
| 560 | _T("#include <wx/xrc/xmlres.h>\n") |
| 561 | _T("#include <wx/xrc/xh_all.h>\n") |
| 562 | _T("\n")); |
| 563 | |
| 564 | for (i = 0; i < flist.Count(); i++) |
| 565 | file.Write( |
| 566 | FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i)); |
| 567 | |
| 568 | file.Write(_T("") |
| 569 | _T("void ") + parFuncname + wxT("()\n") |
| 570 | _T("{\n") |
| 571 | _T("\n") |
| 572 | _T(" // Check for memory FS. If not present, load the handler:\n") |
| 573 | _T(" {\n") |
| 574 | _T(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));\n") |
| 575 | _T(" wxFileSystem fsys;\n") |
| 576 | _T(" wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));\n") |
| 577 | _T(" wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));\n") |
| 578 | _T(" if (f) delete f;\n") |
| 579 | _T(" else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n") |
| 580 | _T(" }\n") |
| 581 | _T("\n")); |
| 582 | |
| 583 | for (i = 0; i < flist.Count(); i++) |
| 584 | { |
| 585 | wxString s; |
| 586 | s.Printf(_T(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/") + flist[i] + |
| 587 | _T("\"), xml_res_file_%i, xml_res_size_%i);\n"), i, i); |
| 588 | file.Write(s); |
| 589 | } |
| 590 | |
| 591 | for (i = 0; i < parFiles.Count(); i++) |
| 592 | { |
| 593 | file.Write(_T(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/") + |
| 594 | GetInternalFileName(parFiles[i], flist) + _T("\"));\n")); |
| 595 | } |
| 596 | |
| 597 | file.Write(_T("}\n")); |
| 598 | |
| 599 | |
| 600 | } |
| 601 | |
| 602 | void XmlResApp::GenCPPHeader() |
| 603 | { |
| 604 | wxString fileSpec = ((parOutput.BeforeLast('.')).AfterLast('/')).AfterLast('\\'); |
| 605 | wxString heaFileName = fileSpec + _T(".h"); |
| 606 | |
| 607 | wxFFile file(heaFileName, wxT("wt")); |
| 608 | file.Write( |
| 609 | _T("//\n") |
| 610 | _T("// This file was automatically generated by wxrc, do not edit by hand.\n") |
| 611 | _T("//\n\n") |
| 612 | _T("#ifndef __") + fileSpec + _T("_h__\n") |
| 613 | _T("#define __") + fileSpec + _T("_h__\n") |
| 614 | ); |
| 615 | for(size_t i=0;i<aXRCWndClassData.Count();++i){ |
| 616 | aXRCWndClassData.Item(i).GenerateHeaderCode(file); |
| 617 | } |
| 618 | file.Write( |
| 619 | _T("\nvoid \n") |
| 620 | + parFuncname |
| 621 | + _T("();\n#endif\n")); |
| 622 | } |
| 623 | |
| 624 | static wxString FileToPythonArray(wxString filename, int num) |
| 625 | { |
| 626 | wxString output; |
| 627 | wxString tmp; |
| 628 | wxString snum; |
| 629 | wxFFile file(filename, wxT("rb")); |
| 630 | wxFileOffset offset = file.Length(); |
| 631 | wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") ); |
| 632 | |
| 633 | const size_t lng = wx_truncate_cast(size_t, offset); |
| 634 | wxASSERT_MSG( offset == lng, wxT("Huge file not supported") ); |
| 635 | |
| 636 | snum.Printf(_T("%i"), num); |
| 637 | output = _T(" xml_res_file_") + snum + _T(" = '''\\\n"); |
| 638 | |
| 639 | unsigned char *buffer = new unsigned char[lng]; |
| 640 | file.Read(buffer, lng); |
| 641 | |
| 642 | for (size_t i = 0, linelng = 0; i < lng; i++) |
| 643 | { |
| 644 | unsigned char c = buffer[i]; |
| 645 | if (c == '\n') |
| 646 | { |
| 647 | tmp = (wxChar)c; |
| 648 | linelng = 0; |
| 649 | } |
| 650 | else if (c < 32 || c > 127 || c == '\'') |
| 651 | tmp.Printf(_T("\\x%02x"), c); |
| 652 | else if (c == '\\') |
| 653 | tmp = _T("\\\\"); |
| 654 | else |
| 655 | tmp = (wxChar)c; |
| 656 | if (linelng > 70) |
| 657 | { |
| 658 | linelng = 0; |
| 659 | output << _T("\\\n"); |
| 660 | } |
| 661 | output << tmp; |
| 662 | linelng += tmp.Length(); |
| 663 | } |
| 664 | |
| 665 | delete[] buffer; |
| 666 | |
| 667 | output += _T("'''\n\n"); |
| 668 | |
| 669 | return output; |
| 670 | } |
| 671 | |
| 672 | |
| 673 | void XmlResApp::MakePackagePython(const wxArrayString& flist) |
| 674 | { |
| 675 | wxFFile file(parOutput, wxT("wt")); |
| 676 | size_t i; |
| 677 | |
| 678 | if (flagVerbose) |
| 679 | wxPrintf(_T("creating Python source file ") + parOutput + _T("...\n")); |
| 680 | |
| 681 | file.Write( |
| 682 | _T("#\n") |
| 683 | _T("# This file was automatically generated by wxrc, do not edit by hand.\n") |
| 684 | _T("#\n\n") |
| 685 | _T("import wx\n") |
| 686 | _T("import wx.xrc\n\n") |
| 687 | ); |
| 688 | |
| 689 | |
| 690 | file.Write(_T("def ") + parFuncname + _T("():\n")); |
| 691 | |
| 692 | for (i = 0; i < flist.Count(); i++) |
| 693 | file.Write( |
| 694 | FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i)); |
| 695 | |
| 696 | file.Write( |
| 697 | _T(" # check if the memory filesystem handler has been loaded yet, and load it if not\n") |
| 698 | _T(" wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value')\n") |
| 699 | _T(" fsys = wx.FileSystem()\n") |
| 700 | _T(" f = fsys.OpenFile('memory:XRC_resource/dummy_file')\n") |
| 701 | _T(" wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file')\n") |
| 702 | _T(" if f is not None:\n") |
| 703 | _T(" f.Destroy()\n") |
| 704 | _T(" else:\n") |
| 705 | _T(" wx.FileSystem.AddHandler(wx.MemoryFSHandler())\n") |
| 706 | _T("\n") |
| 707 | _T(" # load all the strings as memory files and load into XmlRes\n") |
| 708 | ); |
| 709 | |
| 710 | |
| 711 | for (i = 0; i < flist.Count(); i++) |
| 712 | { |
| 713 | wxString s; |
| 714 | s.Printf(_T(" wx.MemoryFSHandler.AddFile('XRC_resource/") + flist[i] + |
| 715 | _T("', xml_res_file_%i)\n"), i); |
| 716 | file.Write(s); |
| 717 | } |
| 718 | for (i = 0; i < parFiles.Count(); i++) |
| 719 | { |
| 720 | file.Write(_T(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/") + |
| 721 | GetInternalFileName(parFiles[i], flist) + _T("')\n")); |
| 722 | } |
| 723 | |
| 724 | file.Write(_T("\n")); |
| 725 | } |
| 726 | |
| 727 | |
| 728 | |
| 729 | void XmlResApp::OutputGettext() |
| 730 | { |
| 731 | wxArrayString str = FindStrings(); |
| 732 | |
| 733 | wxFFile fout; |
| 734 | if (parOutput.empty()) |
| 735 | fout.Attach(stdout); |
| 736 | else |
| 737 | fout.Open(parOutput, wxT("wt")); |
| 738 | |
| 739 | for (size_t i = 0; i < str.GetCount(); i++) |
| 740 | fout.Write(_T("_(\"") + str[i] + _T("\");\n")); |
| 741 | |
| 742 | if (!parOutput) fout.Detach(); |
| 743 | } |
| 744 | |
| 745 | |
| 746 | |
| 747 | wxArrayString XmlResApp::FindStrings() |
| 748 | { |
| 749 | wxArrayString arr, a2; |
| 750 | |
| 751 | for (size_t i = 0; i < parFiles.Count(); i++) |
| 752 | { |
| 753 | if (flagVerbose) |
| 754 | wxPrintf(_T("processing ") + parFiles[i] + _T("...\n")); |
| 755 | |
| 756 | wxXmlDocument doc; |
| 757 | if (!doc.Load(parFiles[i])) |
| 758 | { |
| 759 | wxLogError(_T("Error parsing file ") + parFiles[i]); |
| 760 | retCode = 1; |
| 761 | continue; |
| 762 | } |
| 763 | a2 = FindStrings(doc.GetRoot()); |
| 764 | WX_APPEND_ARRAY(arr, a2); |
| 765 | } |
| 766 | |
| 767 | return arr; |
| 768 | } |
| 769 | |
| 770 | |
| 771 | |
| 772 | static wxString ConvertText(const wxString& str) |
| 773 | { |
| 774 | wxString str2; |
| 775 | const wxChar *dt; |
| 776 | |
| 777 | for (dt = str.c_str(); *dt; dt++) |
| 778 | { |
| 779 | if (*dt == wxT('_')) |
| 780 | { |
| 781 | if ( *(++dt) == wxT('_') ) |
| 782 | str2 << wxT('_'); |
| 783 | else |
| 784 | str2 << wxT('&') << *dt; |
| 785 | } |
| 786 | else |
| 787 | { |
| 788 | switch (*dt) |
| 789 | { |
| 790 | case wxT('\n') : str2 << wxT("\\n"); break; |
| 791 | case wxT('\t') : str2 << wxT("\\t"); break; |
| 792 | case wxT('\r') : str2 << wxT("\\r"); break; |
| 793 | case wxT('\\') : if ((*(dt+1) != 'n') && |
| 794 | (*(dt+1) != 't') && |
| 795 | (*(dt+1) != 'r')) |
| 796 | str2 << wxT("\\\\"); |
| 797 | else |
| 798 | str2 << wxT("\\"); |
| 799 | break; |
| 800 | case wxT('"') : str2 << wxT("\\\""); break; |
| 801 | default : str2 << *dt; break; |
| 802 | } |
| 803 | } |
| 804 | } |
| 805 | |
| 806 | return str2; |
| 807 | } |
| 808 | |
| 809 | |
| 810 | wxArrayString XmlResApp::FindStrings(wxXmlNode *node) |
| 811 | { |
| 812 | wxArrayString arr; |
| 813 | |
| 814 | wxXmlNode *n = node; |
| 815 | if (n == NULL) return arr; |
| 816 | n = n->GetChildren(); |
| 817 | |
| 818 | while (n) |
| 819 | { |
| 820 | if ((node->GetType() == wxXML_ELEMENT_NODE) && |
| 821 | // parent is an element, i.e. has subnodes... |
| 822 | (n->GetType() == wxXML_TEXT_NODE || |
| 823 | n->GetType() == wxXML_CDATA_SECTION_NODE) && |
| 824 | // ...it is textnode... |
| 825 | ( |
| 826 | node/*not n!*/->GetName() == _T("label") || |
| 827 | (node/*not n!*/->GetName() == _T("value") && |
| 828 | !n->GetContent().IsNumber()) || |
| 829 | node/*not n!*/->GetName() == _T("help") || |
| 830 | node/*not n!*/->GetName() == _T("longhelp") || |
| 831 | node/*not n!*/->GetName() == _T("tooltip") || |
| 832 | node/*not n!*/->GetName() == _T("htmlcode") || |
| 833 | node/*not n!*/->GetName() == _T("title") || |
| 834 | node/*not n!*/->GetName() == _T("item") |
| 835 | )) |
| 836 | // ...and known to contain translatable string |
| 837 | { |
| 838 | if (!flagGettext || |
| 839 | node->GetPropVal(_T("translate"), _T("1")) != _T("0")) |
| 840 | { |
| 841 | arr.Add(ConvertText(n->GetContent())); |
| 842 | } |
| 843 | } |
| 844 | |
| 845 | // subnodes: |
| 846 | if (n->GetType() == wxXML_ELEMENT_NODE) |
| 847 | { |
| 848 | wxArrayString a2 = FindStrings(n); |
| 849 | WX_APPEND_ARRAY(arr, a2); |
| 850 | } |
| 851 | |
| 852 | n = n->GetNext(); |
| 853 | } |
| 854 | return arr; |
| 855 | } |