fix compilation due to wxCmdLineEntryDesc changes once again
[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->GetAttribute(_T("class"),&classValue)
69 && node->GetAttribute(_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, "h", "help", "show help message", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
245 { wxCMD_LINE_SWITCH, "v", "verbose", "be verbose" },
246 { wxCMD_LINE_SWITCH, "e", "extra-cpp-code", "output C++ header file with XRC derived classes" },
247 { wxCMD_LINE_SWITCH, "c", "cpp-code", "output C++ source rather than .rsc file" },
248 { wxCMD_LINE_SWITCH, "p", "python-code", "output wxPython source rather than .rsc file" },
249 { wxCMD_LINE_SWITCH, "g", "gettext", "output list of translatable strings (to stdout or file if -o used)" },
250 { wxCMD_LINE_OPTION, "n", "function", "C++/Python function name (with -c or -p) [InitXmlResource]" },
251 { wxCMD_LINE_OPTION, "o", "output", "output file [resource.xrs/cpp]" },
252 #if 0 // not yet implemented
253 { wxCMD_LINE_OPTION, "l", "list-of-handlers", "output list of necessary handlers to this file" },
254 #endif
255 { wxCMD_LINE_PARAM, NULL, NULL, "input file(s)",
256 wxCMD_LINE_VAL_STRING,
257 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_OPTION_MANDATORY },
258
259 wxCMD_LINE_DESC_END
260 };
261
262 wxCmdLineParser parser(cmdLineDesc, argc, argv);
263
264 switch (parser.Parse())
265 {
266 case -1:
267 return 0;
268
269 case 0:
270 retCode = 0;
271 ParseParams(parser);
272 if (flagGettext)
273 OutputGettext();
274 else
275 CompileRes();
276 return retCode;
277 }
278 return 1;
279 }
280
281
282
283
284 void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
285 {
286 flagGettext = cmdline.Found("g");
287 flagVerbose = cmdline.Found("v");
288 flagCPP = cmdline.Found("c");
289 flagPython = cmdline.Found("p");
290 flagH = flagCPP && cmdline.Found("e");
291
292
293 if (!cmdline.Found("o", &parOutput))
294 {
295 if (flagGettext)
296 parOutput = wxEmptyString;
297 else
298 {
299 if (flagCPP)
300 parOutput = _T("resource.cpp");
301 else if (flagPython)
302 parOutput = _T("resource.py");
303 else
304 parOutput = _T("resource.xrs");
305 }
306 }
307 if (!parOutput.empty())
308 {
309 wxFileName fn(parOutput);
310 fn.Normalize();
311 parOutput = fn.GetFullPath();
312 parOutputPath = wxPathOnly(parOutput);
313 }
314 if (!parOutputPath) parOutputPath = _T(".");
315
316 if (!cmdline.Found("n", &parFuncname))
317 parFuncname = _T("InitXmlResource");
318
319 for (size_t i = 0; i < cmdline.GetParamCount(); i++)
320 {
321 #ifdef __WINDOWS__
322 wxString fn=wxFindFirstFile(cmdline.GetParam(i), wxFILE);
323 while (!fn.empty())
324 {
325 parFiles.Add(fn);
326 fn=wxFindNextFile();
327 }
328 #else
329 parFiles.Add(cmdline.GetParam(i));
330 #endif
331 }
332 }
333
334
335
336
337 void XmlResApp::CompileRes()
338 {
339 wxArrayString files = PrepareTempFiles();
340
341 wxRemoveFile(parOutput);
342
343 if (!retCode)
344 {
345 if (flagCPP){
346 MakePackageCPP(files);
347 if (flagH)
348 GenCPPHeader();
349 }
350 else if (flagPython)
351 MakePackagePython(files);
352 else
353 MakePackageZIP(files);
354 }
355
356 DeleteTempFiles(files);
357 }
358
359
360 wxString XmlResApp::GetInternalFileName(const wxString& name, const wxArrayString& flist)
361 {
362 wxString name2 = name;
363 name2.Replace(_T(":"), _T("_"));
364 name2.Replace(_T("/"), _T("_"));
365 name2.Replace(_T("\\"), _T("_"));
366 name2.Replace(_T("*"), _T("_"));
367 name2.Replace(_T("?"), _T("_"));
368
369 wxString s = wxFileNameFromPath(parOutput) + _T("$") + name2;
370
371 if (wxFileExists(s) && flist.Index(s) == wxNOT_FOUND)
372 {
373 for (int i = 0;; i++)
374 {
375 s.Printf(wxFileNameFromPath(parOutput) + _T("$%03i-") + name2, i);
376 if (!wxFileExists(s) || flist.Index(s) != wxNOT_FOUND)
377 break;
378 }
379 }
380 return s;
381 }
382
383 wxArrayString XmlResApp::PrepareTempFiles()
384 {
385 wxArrayString flist;
386
387 for (size_t i = 0; i < parFiles.GetCount(); i++)
388 {
389 if (flagVerbose)
390 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
391
392 wxXmlDocument doc;
393
394 if (!doc.Load(parFiles[i]))
395 {
396 wxLogError(_T("Error parsing file ") + parFiles[i]);
397 retCode = 1;
398 continue;
399 }
400
401 wxString name, ext, path;
402 wxSplitPath(parFiles[i], &path, &name, &ext);
403
404 FindFilesInXML(doc.GetRoot(), flist, path);
405 if (flagH)
406 {
407 wxXmlNode* node = (doc.GetRoot())->GetChildren();
408 wxString classValue,nameValue;
409 while(node){
410 if(node->GetName() == _T("object")
411 && node->GetAttribute(_T("class"),&classValue)
412 && node->GetAttribute(_T("name"),&nameValue)){
413
414 aXRCWndClassData.Add(
415 XRCWndClassData(nameValue,classValue,node)
416 );
417 }
418 node = node -> GetNext();
419 }
420 }
421 wxString internalName = GetInternalFileName(parFiles[i], flist);
422
423 doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName);
424 flist.Add(internalName);
425 }
426
427 return flist;
428 }
429
430
431 // Does 'node' contain filename information at all?
432 static bool NodeContainsFilename(wxXmlNode *node)
433 {
434 const wxString name = node->GetName();
435
436 // Any bitmaps (bitmap2 is used for disabled toolbar buttons):
437 if ( name == _T("bitmap") || name == _T("bitmap2") )
438 return true;
439
440 if ( name == _T("icon") )
441 return true;
442
443 // wxBitmapButton:
444 wxXmlNode *parent = node->GetParent();
445 if (parent != NULL &&
446 parent->GetAttribute(_T("class"), _T("")) == _T("wxBitmapButton") &&
447 (name == _T("focus") ||
448 name == _T("disabled") ||
449 name == _T("hover") ||
450 name == _T("selected")))
451 return true;
452
453 // wxBitmap or wxIcon toplevel resources:
454 if ( name == _T("object") )
455 {
456 wxString klass = node->GetAttribute(_T("class"), wxEmptyString);
457 if (klass == _T("wxBitmap") ||
458 klass == _T("wxIcon") ||
459 klass == _T("data") )
460 return true;
461 }
462
463 // URLs in wxHtmlWindow:
464 if ( name == _T("url") &&
465 parent != NULL &&
466 parent->GetAttribute(_T("class"), _T("")) == _T("wxHtmlWindow") )
467 {
468 // FIXME: this is wrong for e.g. http:// URLs
469 return true;
470 }
471
472 return false;
473 }
474
475 // find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
476 void XmlResApp::FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath)
477 {
478 // Is 'node' XML node element?
479 if (node == NULL) return;
480 if (node->GetType() != wxXML_ELEMENT_NODE) return;
481
482 bool containsFilename = NodeContainsFilename(node);
483
484 wxXmlNode *n = node->GetChildren();
485 while (n)
486 {
487 if (containsFilename &&
488 (n->GetType() == wxXML_TEXT_NODE ||
489 n->GetType() == wxXML_CDATA_SECTION_NODE))
490 {
491 wxString fullname;
492 if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty())
493 fullname = n->GetContent();
494 else
495 fullname = inputPath + wxFILE_SEP_PATH + n->GetContent();
496
497 if (flagVerbose)
498 wxPrintf(_T("adding ") + fullname + _T("...\n"));
499
500 wxString filename = GetInternalFileName(n->GetContent(), flist);
501 n->SetContent(filename);
502
503 if (flist.Index(filename) == wxNOT_FOUND)
504 flist.Add(filename);
505
506 wxFileInputStream sin(fullname);
507 wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename);
508 sin.Read(sout); // copy the stream
509 }
510
511 // subnodes:
512 if (n->GetType() == wxXML_ELEMENT_NODE)
513 FindFilesInXML(n, flist, inputPath);
514
515 n = n->GetNext();
516 }
517 }
518
519
520
521 void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
522 {
523 for (size_t i = 0; i < flist.GetCount(); i++)
524 wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]);
525 }
526
527
528
529 void XmlResApp::MakePackageZIP(const wxArrayString& flist)
530 {
531 wxString files;
532
533 for (size_t i = 0; i < flist.GetCount(); i++)
534 files += flist[i] + _T(" ");
535 files.RemoveLast();
536
537 if (flagVerbose)
538 wxPrintf(_T("compressing ") + parOutput + _T("...\n"));
539
540 wxString cwd = wxGetCwd();
541 wxSetWorkingDirectory(parOutputPath);
542 int execres = wxExecute(_T("zip -9 -j ") +
543 wxString(flagVerbose ? _T("\"") : _T("-q \"")) +
544 parOutput + _T("\" ") + files, true);
545 wxSetWorkingDirectory(cwd);
546 if (execres == -1)
547 {
548 wxLogError(_T("Unable to execute zip program. Make sure it is in the path."));
549 wxLogError(_T("You can download it at http://www.cdrom.com/pub/infozip/"));
550 retCode = 1;
551 return;
552 }
553 }
554
555
556
557 static wxString FileToCppArray(wxString filename, int num)
558 {
559 wxString output;
560 wxString tmp;
561 wxString snum;
562 wxFFile file(filename, wxT("rb"));
563 wxFileOffset offset = file.Length();
564 wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
565
566 const size_t lng = wx_truncate_cast(size_t, offset);
567 wxASSERT_MSG( lng == offset, wxT("Huge file not supported") );
568
569 snum.Printf(_T("%i"), num);
570 output.Printf(_T("static size_t xml_res_size_") + snum + _T(" = %i;\n"), lng);
571 output += _T("static unsigned char xml_res_file_") + snum + _T("[] = {\n");
572 // we cannot use string literals because MSVC is dumb wannabe compiler
573 // with arbitrary limitation to 2048 strings :(
574
575 unsigned char *buffer = new unsigned char[lng];
576 file.Read(buffer, lng);
577
578 for (size_t i = 0, linelng = 0; i < lng; i++)
579 {
580 tmp.Printf(_T("%i"), buffer[i]);
581 if (i != 0) output << _T(',');
582 if (linelng > 70)
583 {
584 linelng = 0;
585 output << _T("\n");
586 }
587 output << tmp;
588 linelng += tmp.Length()+1;
589 }
590
591 delete[] buffer;
592
593 output += _T("};\n\n");
594
595 return output;
596 }
597
598
599 void XmlResApp::MakePackageCPP(const wxArrayString& flist)
600 {
601 wxFFile file(parOutput, wxT("wt"));
602 size_t i;
603
604 if (flagVerbose)
605 wxPrintf(_T("creating C++ source file ") + parOutput + _T("...\n"));
606
607 file.Write(""
608 "//\n"
609 "// This file was automatically generated by wxrc, do not edit by hand.\n"
610 "//\n\n"
611 "#include <wx/wxprec.h>\n"
612 "\n"
613 "#ifdef __BORLANDC__\n"
614 " #pragma hdrstop\n"
615 "#endif\n"
616 "\n"
617 ""
618 "#include <wx/filesys.h>\n"
619 "#include <wx/fs_mem.h>\n"
620 "#include <wx/xrc/xmlres.h>\n"
621 "#include <wx/xrc/xh_all.h>\n"
622 "\n"
623 "#if wxCHECK_VERSION(2,8,5) && wxABI_VERSION >= 20805\n"
624 " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
625 " wxMemoryFSHandler::AddFileWithMimeType(name, data, size, mime)\n"
626 "#else\n"
627 " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
628 " wxMemoryFSHandler::AddFile(name, data, size)\n"
629 "#endif\n"
630 "\n");
631
632 for (i = 0; i < flist.GetCount(); i++)
633 file.Write(
634 FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
635
636 file.Write(""
637 "void " + parFuncname + "()\n"
638 "{\n"
639 "\n"
640 " // Check for memory FS. If not present, load the handler:\n"
641 " {\n"
642 " wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));\n"
643 " wxFileSystem fsys;\n"
644 " wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));\n"
645 " wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));\n"
646 " if (f) delete f;\n"
647 " else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n"
648 " }\n"
649 "\n");
650
651 for (i = 0; i < flist.GetCount(); i++)
652 {
653 wxString s;
654
655 wxString mime;
656 wxString ext = wxFileName(flist[i]).GetExt();
657 if ( ext.Lower() == _T("xrc") )
658 mime = _T("text/xml");
659 else
660 {
661 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
662 if ( ft )
663 ft->GetMimeType(&mime);
664 }
665
666 s.Printf(" XRC_ADD_FILE(wxT(\"XRC_resource/" + flist[i] +
667 "\"), xml_res_file_%i, xml_res_size_%i, _T(\"%s\"));\n",
668 i, i, mime.c_str());
669 file.Write(s);
670 }
671
672 for (i = 0; i < parFiles.GetCount(); i++)
673 {
674 file.Write(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/" +
675 GetInternalFileName(parFiles[i], flist) + "\"));\n");
676 }
677
678 file.Write("}\n");
679
680
681 }
682
683 void XmlResApp::GenCPPHeader()
684 {
685 wxString fileSpec = ((parOutput.BeforeLast('.')).AfterLast('/')).AfterLast('\\');
686 wxString heaFileName = fileSpec + _T(".h");
687
688 wxFFile file(heaFileName, wxT("wt"));
689 file.Write(
690 "//\n"
691 "// This file was automatically generated by wxrc, do not edit by hand.\n"
692 "//\n\n"
693 "#ifndef __" + fileSpec + "_h__\n"
694 "#define __" + fileSpec + "_h__\n"
695 );
696 for(size_t i=0;i<aXRCWndClassData.GetCount();++i){
697 aXRCWndClassData.Item(i).GenerateHeaderCode(file);
698 }
699 file.Write(
700 "\nvoid \n"
701 + parFuncname
702 + "();\n#endif\n");
703 }
704
705 static wxString FileToPythonArray(wxString filename, int num)
706 {
707 wxString output;
708 wxString tmp;
709 wxString snum;
710 wxFFile file(filename, wxT("rb"));
711 wxFileOffset offset = file.Length();
712 wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
713
714 const size_t lng = wx_truncate_cast(size_t, offset);
715 wxASSERT_MSG( offset == lng, wxT("Huge file not supported") );
716
717 snum.Printf(_T("%i"), num);
718 output = " xml_res_file_" + snum + " = '''\\\n";
719
720 unsigned char *buffer = new unsigned char[lng];
721 file.Read(buffer, lng);
722
723 for (size_t i = 0, linelng = 0; i < lng; i++)
724 {
725 unsigned char c = buffer[i];
726 if (c == '\n')
727 {
728 tmp = (wxChar)c;
729 linelng = 0;
730 }
731 else if (c < 32 || c > 127 || c == '\'')
732 tmp.Printf(_T("\\x%02x"), c);
733 else if (c == '\\')
734 tmp = _T("\\\\");
735 else
736 tmp = (wxChar)c;
737 if (linelng > 70)
738 {
739 linelng = 0;
740 output << _T("\\\n");
741 }
742 output << tmp;
743 linelng += tmp.Length();
744 }
745
746 delete[] buffer;
747
748 output += _T("'''\n\n");
749
750 return output;
751 }
752
753
754 void XmlResApp::MakePackagePython(const wxArrayString& flist)
755 {
756 wxFFile file(parOutput, wxT("wt"));
757 size_t i;
758
759 if (flagVerbose)
760 wxPrintf(_T("creating Python source file ") + parOutput + _T("...\n"));
761
762 file.Write(
763 "#\n"
764 "# This file was automatically generated by wxrc, do not edit by hand.\n"
765 "#\n\n"
766 "import wx\n"
767 "import wx.xrc\n\n"
768 );
769
770
771 file.Write("def " + parFuncname + "():\n");
772
773 for (i = 0; i < flist.GetCount(); i++)
774 file.Write(
775 FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
776
777 file.Write(
778 " # check if the memory filesystem handler has been loaded yet, and load it if not\n"
779 " wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value')\n"
780 " fsys = wx.FileSystem()\n"
781 " f = fsys.OpenFile('memory:XRC_resource/dummy_file')\n"
782 " wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file')\n"
783 " if f is not None:\n"
784 " f.Destroy()\n"
785 " else:\n"
786 " wx.FileSystem.AddHandler(wx.MemoryFSHandler())\n"
787 "\n"
788 " # load all the strings as memory files and load into XmlRes\n"
789 );
790
791
792 for (i = 0; i < flist.GetCount(); i++)
793 {
794 wxString s;
795 s.Printf(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist[i] +
796 "', xml_res_file_%i)\n", i);
797 file.Write(s);
798 }
799 for (i = 0; i < parFiles.GetCount(); i++)
800 {
801 file.Write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" +
802 GetInternalFileName(parFiles[i], flist) + "')\n");
803 }
804
805 file.Write("\n");
806 }
807
808
809
810 void XmlResApp::OutputGettext()
811 {
812 wxArrayString str = FindStrings();
813
814 wxFFile fout;
815 if (parOutput.empty())
816 fout.Attach(stdout);
817 else
818 fout.Open(parOutput, wxT("wt"));
819
820 for (size_t i = 0; i < str.GetCount(); i++)
821 fout.Write("_(\"" + str[i] + "\");\n");
822
823 if (!parOutput) fout.Detach();
824 }
825
826
827
828 wxArrayString XmlResApp::FindStrings()
829 {
830 wxArrayString arr, a2;
831
832 for (size_t i = 0; i < parFiles.GetCount(); i++)
833 {
834 if (flagVerbose)
835 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
836
837 wxXmlDocument doc;
838 if (!doc.Load(parFiles[i]))
839 {
840 wxLogError(_T("Error parsing file ") + parFiles[i]);
841 retCode = 1;
842 continue;
843 }
844 a2 = FindStrings(doc.GetRoot());
845 WX_APPEND_ARRAY(arr, a2);
846 }
847
848 return arr;
849 }
850
851
852
853 static wxString ConvertText(const wxString& str)
854 {
855 wxString str2;
856 const wxChar *dt;
857
858 for (dt = str.c_str(); *dt; dt++)
859 {
860 if (*dt == wxT('_'))
861 {
862 if ( *(++dt) == wxT('_') )
863 str2 << wxT('_');
864 else
865 str2 << wxT('&') << *dt;
866 }
867 else
868 {
869 switch (*dt)
870 {
871 case wxT('\n') : str2 << wxT("\\n"); break;
872 case wxT('\t') : str2 << wxT("\\t"); break;
873 case wxT('\r') : str2 << wxT("\\r"); break;
874 case wxT('\\') : if ((*(dt+1) != 'n') &&
875 (*(dt+1) != 't') &&
876 (*(dt+1) != 'r'))
877 str2 << wxT("\\\\");
878 else
879 str2 << wxT("\\");
880 break;
881 case wxT('"') : str2 << wxT("\\\""); break;
882 default : str2 << *dt; break;
883 }
884 }
885 }
886
887 return str2;
888 }
889
890
891 wxArrayString XmlResApp::FindStrings(wxXmlNode *node)
892 {
893 wxArrayString arr;
894
895 wxXmlNode *n = node;
896 if (n == NULL) return arr;
897 n = n->GetChildren();
898
899 while (n)
900 {
901 if ((node->GetType() == wxXML_ELEMENT_NODE) &&
902 // parent is an element, i.e. has subnodes...
903 (n->GetType() == wxXML_TEXT_NODE ||
904 n->GetType() == wxXML_CDATA_SECTION_NODE) &&
905 // ...it is textnode...
906 (
907 node/*not n!*/->GetName() == _T("label") ||
908 (node/*not n!*/->GetName() == _T("value") &&
909 !n->GetContent().IsNumber()) ||
910 node/*not n!*/->GetName() == _T("help") ||
911 node/*not n!*/->GetName() == _T("longhelp") ||
912 node/*not n!*/->GetName() == _T("tooltip") ||
913 node/*not n!*/->GetName() == _T("htmlcode") ||
914 node/*not n!*/->GetName() == _T("title") ||
915 node/*not n!*/->GetName() == _T("item")
916 ))
917 // ...and known to contain translatable string
918 {
919 if (!flagGettext ||
920 node->GetAttribute(_T("translate"), _T("1")) != _T("0"))
921 {
922 arr.Add(ConvertText(n->GetContent()));
923 }
924 }
925
926 // subnodes:
927 if (n->GetType() == wxXML_ELEMENT_NODE)
928 {
929 wxArrayString a2 = FindStrings(n);
930 WX_APPEND_ARRAY(arr, a2);
931 }
932
933 n = n->GetNext();
934 }
935 return arr;
936 }