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