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