wxrc.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  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. // wxAnimationCtrl animations:
  426. if ( name == wxS("animation") )
  427. return true;
  428. // URLs in wxHtmlWindow:
  429. if ( name == wxT("url") &&
  430. parent != NULL &&
  431. parent->GetAttribute(wxT("class"), wxT("")) == wxT("wxHtmlWindow") )
  432. {
  433. // FIXME: this is wrong for e.g. http:// URLs
  434. return true;
  435. }
  436. return false;
  437. }
  438. // find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
  439. void XmlResApp::FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath)
  440. {
  441. // Is 'node' XML node element?
  442. if (node == NULL) return;
  443. if (node->GetType() != wxXML_ELEMENT_NODE) return;
  444. bool containsFilename = NodeContainsFilename(node);
  445. wxXmlNode *n = node->GetChildren();
  446. while (n)
  447. {
  448. if (containsFilename &&
  449. (n->GetType() == wxXML_TEXT_NODE ||
  450. n->GetType() == wxXML_CDATA_SECTION_NODE))
  451. {
  452. wxString fullname;
  453. if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty())
  454. fullname = n->GetContent();
  455. else
  456. fullname = inputPath + wxFILE_SEP_PATH + n->GetContent();
  457. if (flagVerbose)
  458. wxPrintf(wxT("adding ") + fullname + wxT("...\n"));
  459. wxString filename = GetInternalFileName(n->GetContent(), flist);
  460. n->SetContent(filename);
  461. if (flist.Index(filename) == wxNOT_FOUND)
  462. flist.Add(filename);
  463. wxFileInputStream sin(fullname);
  464. wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename);
  465. sin.Read(sout); // copy the stream
  466. }
  467. // subnodes:
  468. if (n->GetType() == wxXML_ELEMENT_NODE)
  469. FindFilesInXML(n, flist, inputPath);
  470. n = n->GetNext();
  471. }
  472. }
  473. void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
  474. {
  475. for (size_t i = 0; i < flist.GetCount(); i++)
  476. wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]);
  477. }
  478. void XmlResApp::MakePackageZIP(const wxArrayString& flist)
  479. {
  480. wxString files;
  481. for (size_t i = 0; i < flist.GetCount(); i++)
  482. files += flist[i] + wxT(" ");
  483. files.RemoveLast();
  484. if (flagVerbose)
  485. wxPrintf(wxT("compressing ") + parOutput + wxT("...\n"));
  486. wxString cwd = wxGetCwd();
  487. wxSetWorkingDirectory(parOutputPath);
  488. int execres = wxExecute(wxT("zip -9 -j ") +
  489. wxString(flagVerbose ? wxT("\"") : wxT("-q \"")) +
  490. parOutput + wxT("\" ") + files,
  491. wxEXEC_BLOCK);
  492. wxSetWorkingDirectory(cwd);
  493. if (execres == -1)
  494. {
  495. wxLogError(wxT("Unable to execute zip program. Make sure it is in the path."));
  496. wxLogError(wxT("You can download it at http://www.cdrom.com/pub/infozip/"));
  497. retCode = 1;
  498. return;
  499. }
  500. }
  501. static wxString FileToCppArray(wxString filename, int num)
  502. {
  503. wxString output;
  504. wxString tmp;
  505. wxString snum;
  506. wxFFile file(filename, wxT("rb"));
  507. wxFileOffset offset = file.Length();
  508. wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
  509. const size_t lng = wx_truncate_cast(size_t, offset);
  510. wxASSERT_MSG( static_cast<wxFileOffset>(lng) == offset,
  511. wxT("Huge file not supported") );
  512. snum.Printf(wxT("%i"), num);
  513. output.Printf(wxT("static size_t xml_res_size_") + snum + wxT(" = %lu;\n"),
  514. static_cast<unsigned long>(lng));
  515. output += wxT("static unsigned char xml_res_file_") + snum + wxT("[] = {\n");
  516. // we cannot use string literals because MSVC is dumb wannabe compiler
  517. // with arbitrary limitation to 2048 strings :(
  518. unsigned char *buffer = new unsigned char[lng];
  519. file.Read(buffer, lng);
  520. for (size_t i = 0, linelng = 0; i < lng; i++)
  521. {
  522. tmp.Printf(wxT("%i"), buffer[i]);
  523. if (i != 0) output << wxT(',');
  524. if (linelng > 70)
  525. {
  526. linelng = 0;
  527. output << wxT("\n");
  528. }
  529. output << tmp;
  530. linelng += tmp.Length()+1;
  531. }
  532. delete[] buffer;
  533. output += wxT("};\n\n");
  534. return output;
  535. }
  536. void XmlResApp::MakePackageCPP(const wxArrayString& flist)
  537. {
  538. wxFFile file(parOutput, wxT("wt"));
  539. unsigned i;
  540. if (flagVerbose)
  541. wxPrintf(wxT("creating C++ source file ") + parOutput + wxT("...\n"));
  542. file.Write(""
  543. "//\n"
  544. "// This file was automatically generated by wxrc, do not edit by hand.\n"
  545. "//\n\n"
  546. "#include <wx/wxprec.h>\n"
  547. "\n"
  548. "#ifdef __BORLANDC__\n"
  549. " #pragma hdrstop\n"
  550. "#endif\n"
  551. "\n"
  552. ""
  553. "#include <wx/filesys.h>\n"
  554. "#include <wx/fs_mem.h>\n"
  555. "#include <wx/xrc/xmlres.h>\n"
  556. "#include <wx/xrc/xh_all.h>\n"
  557. "\n"
  558. "#if wxCHECK_VERSION(2,8,5) && wxABI_VERSION >= 20805\n"
  559. " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
  560. " wxMemoryFSHandler::AddFileWithMimeType(name, data, size, mime)\n"
  561. "#else\n"
  562. " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
  563. " wxMemoryFSHandler::AddFile(name, data, size)\n"
  564. "#endif\n"
  565. "\n");
  566. for (i = 0; i < flist.GetCount(); i++)
  567. file.Write(
  568. FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
  569. file.Write(""
  570. "void " + parFuncname + "()\n"
  571. "{\n"
  572. "\n"
  573. " // Check for memory FS. If not present, load the handler:\n"
  574. " {\n"
  575. " wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));\n"
  576. " wxFileSystem fsys;\n"
  577. " wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));\n"
  578. " wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));\n"
  579. " if (f) delete f;\n"
  580. " else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n"
  581. " }\n"
  582. "\n");
  583. for (i = 0; i < flist.GetCount(); i++)
  584. {
  585. wxString s;
  586. wxString mime;
  587. wxString ext = wxFileName(flist[i]).GetExt();
  588. if ( ext.Lower() == wxT("xrc") )
  589. mime = wxT("text/xml");
  590. #if wxUSE_MIMETYPE
  591. else
  592. {
  593. wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
  594. if ( ft )
  595. {
  596. ft->GetMimeType(&mime);
  597. delete ft;
  598. }
  599. }
  600. #endif // wxUSE_MIMETYPE
  601. s.Printf(" XRC_ADD_FILE(wxT(\"XRC_resource/" + flist[i] +
  602. "\"), xml_res_file_%u, xml_res_size_%u, wxT(\"%s\"));\n",
  603. i, i, mime.c_str());
  604. file.Write(s);
  605. }
  606. for (i = 0; i < parFiles.GetCount(); i++)
  607. {
  608. file.Write(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/" +
  609. GetInternalFileName(parFiles[i], flist) + "\"));\n");
  610. }
  611. file.Write("}\n");
  612. }
  613. void XmlResApp::GenCPPHeader()
  614. {
  615. // Generate the output header in the same directory as the source file.
  616. wxFileName headerName(parOutput);
  617. headerName.SetExt("h");
  618. wxFFile file(headerName.GetFullPath(), wxT("wt"));
  619. file.Write(
  620. "//\n"
  621. "// This file was automatically generated by wxrc, do not edit by hand.\n"
  622. "//\n\n"
  623. "#ifndef __" + headerName.GetName() + "_h__\n"
  624. "#define __" + headerName.GetName() + "_h__\n"
  625. );
  626. for(size_t i=0;i<aXRCWndClassData.GetCount();++i){
  627. aXRCWndClassData.Item(i).GenerateHeaderCode(file);
  628. }
  629. file.Write(
  630. "\nvoid \n"
  631. + parFuncname
  632. + "();\n#endif\n");
  633. }
  634. static wxString FileToPythonArray(wxString filename, int num)
  635. {
  636. wxString output;
  637. wxString tmp;
  638. wxString snum;
  639. wxFFile file(filename, wxT("rb"));
  640. wxFileOffset offset = file.Length();
  641. wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
  642. const size_t lng = wx_truncate_cast(size_t, offset);
  643. wxASSERT_MSG( static_cast<wxFileOffset>(lng) == offset,
  644. wxT("Huge file not supported") );
  645. snum.Printf(wxT("%i"), num);
  646. output = " xml_res_file_" + snum + " = '''\\\n";
  647. unsigned char *buffer = new unsigned char[lng];
  648. file.Read(buffer, lng);
  649. for (size_t i = 0, linelng = 0; i < lng; i++)
  650. {
  651. unsigned char c = buffer[i];
  652. if (c == '\n')
  653. {
  654. tmp = (wxChar)c;
  655. linelng = 0;
  656. }
  657. else if (c < 32 || c > 127 || c == '\'')
  658. tmp.Printf(wxT("\\x%02x"), c);
  659. else if (c == '\\')
  660. tmp = wxT("\\\\");
  661. else
  662. tmp = (wxChar)c;
  663. if (linelng > 70)
  664. {
  665. linelng = 0;
  666. output << wxT("\\\n");
  667. }
  668. output << tmp;
  669. linelng += tmp.Length();
  670. }
  671. delete[] buffer;
  672. output += wxT("'''\n\n");
  673. return output;
  674. }
  675. void XmlResApp::MakePackagePython(const wxArrayString& flist)
  676. {
  677. wxFFile file(parOutput, wxT("wt"));
  678. unsigned i;
  679. if (flagVerbose)
  680. wxPrintf(wxT("creating Python source file ") + parOutput + wxT("...\n"));
  681. file.Write(
  682. "#\n"
  683. "# This file was automatically generated by wxrc, do not edit by hand.\n"
  684. "#\n\n"
  685. "import wx\n"
  686. "import wx.xrc\n\n"
  687. );
  688. file.Write("def " + parFuncname + "():\n");
  689. for (i = 0; i < flist.GetCount(); i++)
  690. file.Write(
  691. FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
  692. file.Write(
  693. " # check if the memory filesystem handler has been loaded yet, and load it if not\n"
  694. " wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value')\n"
  695. " fsys = wx.FileSystem()\n"
  696. " f = fsys.OpenFile('memory:XRC_resource/dummy_file')\n"
  697. " wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file')\n"
  698. " if f is not None:\n"
  699. " f.Destroy()\n"
  700. " else:\n"
  701. " wx.FileSystem.AddHandler(wx.MemoryFSHandler())\n"
  702. "\n"
  703. " # load all the strings as memory files and load into XmlRes\n"
  704. );
  705. for (i = 0; i < flist.GetCount(); i++)
  706. {
  707. wxString s;
  708. s.Printf(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist[i] +
  709. "', xml_res_file_%u)\n", i);
  710. file.Write(s);
  711. }
  712. for (i = 0; i < parFiles.GetCount(); i++)
  713. {
  714. file.Write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" +
  715. GetInternalFileName(parFiles[i], flist) + "')\n");
  716. }
  717. file.Write("\n");
  718. }
  719. void XmlResApp::OutputGettext()
  720. {
  721. ExtractedStrings str = FindStrings();
  722. wxFFile fout;
  723. if (parOutput.empty())
  724. fout.Attach(stdout);
  725. else
  726. fout.Open(parOutput, wxT("wt"));
  727. for (ExtractedStrings::const_iterator i = str.begin(); i != str.end(); ++i)
  728. {
  729. const wxFileName filename(i->filename);
  730. wxString s;
  731. s.Printf("#line %d \"%s\"\n",
  732. i->lineNo, filename.GetFullPath(wxPATH_UNIX));
  733. fout.Write(s);
  734. fout.Write("_(\"" + i->str + "\");\n");
  735. }
  736. if (!parOutput) fout.Detach();
  737. }
  738. ExtractedStrings XmlResApp::FindStrings()
  739. {
  740. ExtractedStrings arr, a2;
  741. for (size_t i = 0; i < parFiles.GetCount(); i++)
  742. {
  743. if (flagVerbose)
  744. wxPrintf(wxT("processing ") + parFiles[i] + wxT("...\n"));
  745. wxXmlDocument doc;
  746. if (!doc.Load(parFiles[i]))
  747. {
  748. wxLogError(wxT("Error parsing file ") + parFiles[i]);
  749. retCode = 1;
  750. continue;
  751. }
  752. a2 = FindStrings(parFiles[i], doc.GetRoot());
  753. WX_APPEND_ARRAY(arr, a2);
  754. }
  755. return arr;
  756. }
  757. static wxString ConvertText(const wxString& str)
  758. {
  759. wxString str2;
  760. const wxChar *dt;
  761. for (dt = str.c_str(); *dt; dt++)
  762. {
  763. if (*dt == wxT('_'))
  764. {
  765. if ( *(dt+1) == 0 )
  766. str2 << wxT('_');
  767. else if ( *(++dt) == wxT('_') )
  768. str2 << wxT('_');
  769. else
  770. str2 << wxT('&') << *dt;
  771. }
  772. else
  773. {
  774. switch (*dt)
  775. {
  776. case wxT('\n') : str2 << wxT("\\n"); break;
  777. case wxT('\t') : str2 << wxT("\\t"); break;
  778. case wxT('\r') : str2 << wxT("\\r"); break;
  779. case wxT('\\') : if ((*(dt+1) != 'n') &&
  780. (*(dt+1) != 't') &&
  781. (*(dt+1) != 'r'))
  782. str2 << wxT("\\\\");
  783. else
  784. str2 << wxT("\\");
  785. break;
  786. case wxT('"') : str2 << wxT("\\\""); break;
  787. default : str2 << *dt; break;
  788. }
  789. }
  790. }
  791. return str2;
  792. }
  793. ExtractedStrings
  794. XmlResApp::FindStrings(const wxString& filename, wxXmlNode *node)
  795. {
  796. ExtractedStrings arr;
  797. wxXmlNode *n = node;
  798. if (n == NULL) return arr;
  799. n = n->GetChildren();
  800. while (n)
  801. {
  802. if ((node->GetType() == wxXML_ELEMENT_NODE) &&
  803. // parent is an element, i.e. has subnodes...
  804. (n->GetType() == wxXML_TEXT_NODE ||
  805. n->GetType() == wxXML_CDATA_SECTION_NODE) &&
  806. // ...it is textnode...
  807. (
  808. node/*not n!*/->GetName() == wxT("label") ||
  809. (node/*not n!*/->GetName() == wxT("value") &&
  810. !n->GetContent().IsNumber()) ||
  811. node/*not n!*/->GetName() == wxT("help") ||
  812. node/*not n!*/->GetName() == wxT("longhelp") ||
  813. node/*not n!*/->GetName() == wxT("tooltip") ||
  814. node/*not n!*/->GetName() == wxT("htmlcode") ||
  815. node/*not n!*/->GetName() == wxT("title") ||
  816. node/*not n!*/->GetName() == wxT("item") ||
  817. node/*not n!*/->GetName() == wxT("message") ||
  818. node/*not n!*/->GetName() == wxT("note") ||
  819. node/*not n!*/->GetName() == wxT("defaultdirectory") ||
  820. node/*not n!*/->GetName() == wxT("defaultfilename") ||
  821. node/*not n!*/->GetName() == wxT("defaultfolder") ||
  822. node/*not n!*/->GetName() == wxT("filter") ||
  823. node/*not n!*/->GetName() == wxT("caption")
  824. ))
  825. // ...and known to contain translatable string
  826. {
  827. if (!flagGettext ||
  828. node->GetAttribute(wxT("translate"), wxT("1")) != wxT("0"))
  829. {
  830. arr.push_back
  831. (
  832. ExtractedString
  833. (
  834. ConvertText(n->GetContent()),
  835. filename,
  836. n->GetLineNumber()
  837. )
  838. );
  839. }
  840. }
  841. // subnodes:
  842. if (n->GetType() == wxXML_ELEMENT_NODE)
  843. {
  844. ExtractedStrings a2 = FindStrings(filename, n);
  845. WX_APPEND_ARRAY(arr, a2);
  846. }
  847. n = n->GetNext();
  848. }
  849. return arr;
  850. }
  851. bool XmlResApp::Validate()
  852. {
  853. if ( flagVerbose )
  854. wxPuts("validating XRC files...");
  855. wxString schemaURI;
  856. if ( !parSchemaFile.empty() )
  857. {
  858. schemaURI = parSchemaFile;
  859. }
  860. else
  861. {
  862. schemaURI = "http://www.wxwidgets.org/wxxrc";
  863. // Normally, we'd use an OASIS XML catalog to map the URI to a local copy,
  864. // but Jing's catalog support (-C catalogFile) requires additional
  865. // dependency, resolver.jar, that is not commonly installed alongside Jing
  866. // by systems that package Jing. So do the (trivial) mapping manually here:
  867. wxString wxWinRoot;
  868. if ( wxGetEnv("WXWIN", &wxWinRoot) )
  869. {
  870. wxString schemaFile(wxWinRoot + "/misc/schema/xrc_schema.rnc");
  871. if ( wxFileExists(schemaFile) )
  872. schemaURI = schemaFile;
  873. }
  874. }
  875. wxString cmdline = wxString::Format("jing -c \"%s\"", schemaURI);
  876. for ( size_t i = 0; i < parFiles.GetCount(); i++ )
  877. cmdline << wxString::Format(" \"%s\"", parFiles[i]);
  878. int res = wxExecute(cmdline, wxEXEC_BLOCK);
  879. if (res == -1)
  880. {
  881. wxLogError("Running RELAX NG validator failed.");
  882. wxLogError("Please install Jing (http://www.thaiopensource.com/relaxng/jing.html).");
  883. wxLogError("See http://svn.wxwidgets.org/svn/wx/wxWidgets/trunk/misc/schema/README for more information.");
  884. return false;
  885. }
  886. if ( flagVerbose )
  887. {
  888. if ( res == 0 )
  889. wxPuts("XRC validation passed without errors.");
  890. else
  891. wxPuts("XRC validation failed, there are errors.");
  892. }
  893. return res == 0;
  894. }