wxrc.cpp 30 KB

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