]> git.saurik.com Git - wxWidgets.git/blob - utils/wxrc/wxrc.cpp
Fixed wxAtomicInc/Dec() to not use asm/atomic.h header on Linux - it's kernel interna...
[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, _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->GetAttribute(_T("class"),&classValue)
413 && node->GetAttribute(_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 // wxBitmapButton:
445 wxXmlNode *parent = node->GetParent();
446 if (parent != NULL &&
447 parent->GetAttribute(_T("class"), _T("")) == _T("wxBitmapButton") &&
448 (name == _T("focus") ||
449 name == _T("disabled") ||
450 name == _T("hover") ||
451 name == _T("selected")))
452 return true;
453
454 // wxBitmap or wxIcon toplevel resources:
455 if ( name == _T("object") )
456 {
457 wxString klass = node->GetAttribute(_T("class"), wxEmptyString);
458 if (klass == _T("wxBitmap") ||
459 klass == _T("wxIcon") ||
460 klass == _T("data") )
461 return true;
462 }
463
464 // URLs in wxHtmlWindow:
465 if ( name == _T("url") &&
466 parent != NULL &&
467 parent->GetAttribute(_T("class"), _T("")) == _T("wxHtmlWindow") )
468 {
469 // FIXME: this is wrong for e.g. http:// URLs
470 return true;
471 }
472
473 return false;
474 }
475
476 // find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
477 void XmlResApp::FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath)
478 {
479 // Is 'node' XML node element?
480 if (node == NULL) return;
481 if (node->GetType() != wxXML_ELEMENT_NODE) return;
482
483 bool containsFilename = NodeContainsFilename(node);
484
485 wxXmlNode *n = node->GetChildren();
486 while (n)
487 {
488 if (containsFilename &&
489 (n->GetType() == wxXML_TEXT_NODE ||
490 n->GetType() == wxXML_CDATA_SECTION_NODE))
491 {
492 wxString fullname;
493 if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty())
494 fullname = n->GetContent();
495 else
496 fullname = inputPath + wxFILE_SEP_PATH + n->GetContent();
497
498 if (flagVerbose)
499 wxPrintf(_T("adding ") + fullname + _T("...\n"));
500
501 wxString filename = GetInternalFileName(n->GetContent(), flist);
502 n->SetContent(filename);
503
504 if (flist.Index(filename) == wxNOT_FOUND)
505 flist.Add(filename);
506
507 wxFileInputStream sin(fullname);
508 wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename);
509 sin.Read(sout); // copy the stream
510 }
511
512 // subnodes:
513 if (n->GetType() == wxXML_ELEMENT_NODE)
514 FindFilesInXML(n, flist, inputPath);
515
516 n = n->GetNext();
517 }
518 }
519
520
521
522 void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
523 {
524 for (size_t i = 0; i < flist.GetCount(); i++)
525 wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]);
526 }
527
528
529
530 void XmlResApp::MakePackageZIP(const wxArrayString& flist)
531 {
532 wxString files;
533
534 for (size_t i = 0; i < flist.GetCount(); i++)
535 files += flist[i] + _T(" ");
536 files.RemoveLast();
537
538 if (flagVerbose)
539 wxPrintf(_T("compressing ") + parOutput + _T("...\n"));
540
541 wxString cwd = wxGetCwd();
542 wxSetWorkingDirectory(parOutputPath);
543 int execres = wxExecute(_T("zip -9 -j ") +
544 wxString(flagVerbose ? _T("\"") : _T("-q \"")) +
545 parOutput + _T("\" ") + files, true);
546 wxSetWorkingDirectory(cwd);
547 if (execres == -1)
548 {
549 wxLogError(_T("Unable to execute zip program. Make sure it is in the path."));
550 wxLogError(_T("You can download it at http://www.cdrom.com/pub/infozip/"));
551 retCode = 1;
552 return;
553 }
554 }
555
556
557
558 static wxString FileToCppArray(wxString filename, int num)
559 {
560 wxString output;
561 wxString tmp;
562 wxString snum;
563 wxFFile file(filename, wxT("rb"));
564 wxFileOffset offset = file.Length();
565 wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
566
567 const size_t lng = wx_truncate_cast(size_t, offset);
568 wxASSERT_MSG( lng == offset, wxT("Huge file not supported") );
569
570 snum.Printf(_T("%i"), num);
571 output.Printf(_T("static size_t xml_res_size_") + snum + _T(" = %i;\n"), lng);
572 output += _T("static unsigned char xml_res_file_") + snum + _T("[] = {\n");
573 // we cannot use string literals because MSVC is dumb wannabe compiler
574 // with arbitrary limitation to 2048 strings :(
575
576 unsigned char *buffer = new unsigned char[lng];
577 file.Read(buffer, lng);
578
579 for (size_t i = 0, linelng = 0; i < lng; i++)
580 {
581 tmp.Printf(_T("%i"), buffer[i]);
582 if (i != 0) output << _T(',');
583 if (linelng > 70)
584 {
585 linelng = 0;
586 output << _T("\n");
587 }
588 output << tmp;
589 linelng += tmp.Length()+1;
590 }
591
592 delete[] buffer;
593
594 output += _T("};\n\n");
595
596 return output;
597 }
598
599
600 void XmlResApp::MakePackageCPP(const wxArrayString& flist)
601 {
602 wxFFile file(parOutput, wxT("wt"));
603 size_t i;
604
605 if (flagVerbose)
606 wxPrintf(_T("creating C++ source file ") + parOutput + _T("...\n"));
607
608 file.Write(""
609 "//\n"
610 "// This file was automatically generated by wxrc, do not edit by hand.\n"
611 "//\n\n"
612 "#include <wx/wxprec.h>\n"
613 "\n"
614 "#ifdef __BORLANDC__\n"
615 " #pragma hdrstop\n"
616 "#endif\n"
617 "\n"
618 ""
619 "#include <wx/filesys.h>\n"
620 "#include <wx/fs_mem.h>\n"
621 "#include <wx/xrc/xmlres.h>\n"
622 "#include <wx/xrc/xh_all.h>\n"
623 "\n"
624 "#if wxCHECK_VERSION(2,8,5) && wxABI_VERSION >= 20805\n"
625 " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
626 " wxMemoryFSHandler::AddFileWithMimeType(name, data, size, mime)\n"
627 "#else\n"
628 " #define XRC_ADD_FILE(name, data, size, mime) \\\n"
629 " wxMemoryFSHandler::AddFile(name, data, size)\n"
630 "#endif\n"
631 "\n");
632
633 for (i = 0; i < flist.GetCount(); i++)
634 file.Write(
635 FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
636
637 file.Write(""
638 "void " + parFuncname + "()\n"
639 "{\n"
640 "\n"
641 " // Check for memory FS. If not present, load the handler:\n"
642 " {\n"
643 " wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));\n"
644 " wxFileSystem fsys;\n"
645 " wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));\n"
646 " wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));\n"
647 " if (f) delete f;\n"
648 " else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n"
649 " }\n"
650 "\n");
651
652 for (i = 0; i < flist.GetCount(); i++)
653 {
654 wxString s;
655
656 wxString mime;
657 wxString ext = wxFileName(flist[i]).GetExt();
658 if ( ext.Lower() == _T("xrc") )
659 mime = _T("text/xml");
660 else
661 {
662 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
663 if ( ft )
664 ft->GetMimeType(&mime);
665 }
666
667 s.Printf(" XRC_ADD_FILE(wxT(\"XRC_resource/" + flist[i] +
668 "\"), xml_res_file_%i, xml_res_size_%i, _T(\"%s\"));\n",
669 i, i, mime.c_str());
670 file.Write(s);
671 }
672
673 for (i = 0; i < parFiles.GetCount(); i++)
674 {
675 file.Write(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/" +
676 GetInternalFileName(parFiles[i], flist) + "\"));\n");
677 }
678
679 file.Write("}\n");
680
681
682 }
683
684 void XmlResApp::GenCPPHeader()
685 {
686 wxString fileSpec = ((parOutput.BeforeLast('.')).AfterLast('/')).AfterLast('\\');
687 wxString heaFileName = fileSpec + _T(".h");
688
689 wxFFile file(heaFileName, wxT("wt"));
690 file.Write(
691 "//\n"
692 "// This file was automatically generated by wxrc, do not edit by hand.\n"
693 "//\n\n"
694 "#ifndef __" + fileSpec + "_h__\n"
695 "#define __" + fileSpec + "_h__\n"
696 );
697 for(size_t i=0;i<aXRCWndClassData.GetCount();++i){
698 aXRCWndClassData.Item(i).GenerateHeaderCode(file);
699 }
700 file.Write(
701 "\nvoid \n"
702 + parFuncname
703 + "();\n#endif\n");
704 }
705
706 static wxString FileToPythonArray(wxString filename, int num)
707 {
708 wxString output;
709 wxString tmp;
710 wxString snum;
711 wxFFile file(filename, wxT("rb"));
712 wxFileOffset offset = file.Length();
713 wxASSERT_MSG( offset >= 0 , wxT("Invalid file length") );
714
715 const size_t lng = wx_truncate_cast(size_t, offset);
716 wxASSERT_MSG( offset == lng, wxT("Huge file not supported") );
717
718 snum.Printf(_T("%i"), num);
719 output = " xml_res_file_" + snum + " = '''\\\n";
720
721 unsigned char *buffer = new unsigned char[lng];
722 file.Read(buffer, lng);
723
724 for (size_t i = 0, linelng = 0; i < lng; i++)
725 {
726 unsigned char c = buffer[i];
727 if (c == '\n')
728 {
729 tmp = (wxChar)c;
730 linelng = 0;
731 }
732 else if (c < 32 || c > 127 || c == '\'')
733 tmp.Printf(_T("\\x%02x"), c);
734 else if (c == '\\')
735 tmp = _T("\\\\");
736 else
737 tmp = (wxChar)c;
738 if (linelng > 70)
739 {
740 linelng = 0;
741 output << _T("\\\n");
742 }
743 output << tmp;
744 linelng += tmp.Length();
745 }
746
747 delete[] buffer;
748
749 output += _T("'''\n\n");
750
751 return output;
752 }
753
754
755 void XmlResApp::MakePackagePython(const wxArrayString& flist)
756 {
757 wxFFile file(parOutput, wxT("wt"));
758 size_t i;
759
760 if (flagVerbose)
761 wxPrintf(_T("creating Python source file ") + parOutput + _T("...\n"));
762
763 file.Write(
764 "#\n"
765 "# This file was automatically generated by wxrc, do not edit by hand.\n"
766 "#\n\n"
767 "import wx\n"
768 "import wx.xrc\n\n"
769 );
770
771
772 file.Write("def " + parFuncname + "():\n");
773
774 for (i = 0; i < flist.GetCount(); i++)
775 file.Write(
776 FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
777
778 file.Write(
779 " # check if the memory filesystem handler has been loaded yet, and load it if not\n"
780 " wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value')\n"
781 " fsys = wx.FileSystem()\n"
782 " f = fsys.OpenFile('memory:XRC_resource/dummy_file')\n"
783 " wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file')\n"
784 " if f is not None:\n"
785 " f.Destroy()\n"
786 " else:\n"
787 " wx.FileSystem.AddHandler(wx.MemoryFSHandler())\n"
788 "\n"
789 " # load all the strings as memory files and load into XmlRes\n"
790 );
791
792
793 for (i = 0; i < flist.GetCount(); i++)
794 {
795 wxString s;
796 s.Printf(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist[i] +
797 "', xml_res_file_%i)\n", i);
798 file.Write(s);
799 }
800 for (i = 0; i < parFiles.GetCount(); i++)
801 {
802 file.Write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" +
803 GetInternalFileName(parFiles[i], flist) + "')\n");
804 }
805
806 file.Write("\n");
807 }
808
809
810
811 void XmlResApp::OutputGettext()
812 {
813 wxArrayString str = FindStrings();
814
815 wxFFile fout;
816 if (parOutput.empty())
817 fout.Attach(stdout);
818 else
819 fout.Open(parOutput, wxT("wt"));
820
821 for (size_t i = 0; i < str.GetCount(); i++)
822 fout.Write("_(\"" + str[i] + "\");\n");
823
824 if (!parOutput) fout.Detach();
825 }
826
827
828
829 wxArrayString XmlResApp::FindStrings()
830 {
831 wxArrayString arr, a2;
832
833 for (size_t i = 0; i < parFiles.GetCount(); i++)
834 {
835 if (flagVerbose)
836 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
837
838 wxXmlDocument doc;
839 if (!doc.Load(parFiles[i]))
840 {
841 wxLogError(_T("Error parsing file ") + parFiles[i]);
842 retCode = 1;
843 continue;
844 }
845 a2 = FindStrings(doc.GetRoot());
846 WX_APPEND_ARRAY(arr, a2);
847 }
848
849 return arr;
850 }
851
852
853
854 static wxString ConvertText(const wxString& str)
855 {
856 wxString str2;
857 const wxChar *dt;
858
859 for (dt = str.c_str(); *dt; dt++)
860 {
861 if (*dt == wxT('_'))
862 {
863 if ( *(++dt) == wxT('_') )
864 str2 << wxT('_');
865 else
866 str2 << wxT('&') << *dt;
867 }
868 else
869 {
870 switch (*dt)
871 {
872 case wxT('\n') : str2 << wxT("\\n"); break;
873 case wxT('\t') : str2 << wxT("\\t"); break;
874 case wxT('\r') : str2 << wxT("\\r"); break;
875 case wxT('\\') : if ((*(dt+1) != 'n') &&
876 (*(dt+1) != 't') &&
877 (*(dt+1) != 'r'))
878 str2 << wxT("\\\\");
879 else
880 str2 << wxT("\\");
881 break;
882 case wxT('"') : str2 << wxT("\\\""); break;
883 default : str2 << *dt; break;
884 }
885 }
886 }
887
888 return str2;
889 }
890
891
892 wxArrayString XmlResApp::FindStrings(wxXmlNode *node)
893 {
894 wxArrayString arr;
895
896 wxXmlNode *n = node;
897 if (n == NULL) return arr;
898 n = n->GetChildren();
899
900 while (n)
901 {
902 if ((node->GetType() == wxXML_ELEMENT_NODE) &&
903 // parent is an element, i.e. has subnodes...
904 (n->GetType() == wxXML_TEXT_NODE ||
905 n->GetType() == wxXML_CDATA_SECTION_NODE) &&
906 // ...it is textnode...
907 (
908 node/*not n!*/->GetName() == _T("label") ||
909 (node/*not n!*/->GetName() == _T("value") &&
910 !n->GetContent().IsNumber()) ||
911 node/*not n!*/->GetName() == _T("help") ||
912 node/*not n!*/->GetName() == _T("longhelp") ||
913 node/*not n!*/->GetName() == _T("tooltip") ||
914 node/*not n!*/->GetName() == _T("htmlcode") ||
915 node/*not n!*/->GetName() == _T("title") ||
916 node/*not n!*/->GetName() == _T("item")
917 ))
918 // ...and known to contain translatable string
919 {
920 if (!flagGettext ||
921 node->GetAttribute(_T("translate"), _T("1")) != _T("0"))
922 {
923 arr.Add(ConvertText(n->GetContent()));
924 }
925 }
926
927 // subnodes:
928 if (n->GetType() == wxXML_ELEMENT_NODE)
929 {
930 wxArrayString a2 = FindStrings(n);
931 WX_APPEND_ARRAY(arr, a2);
932 }
933
934 n = n->GetNext();
935 }
936 return arr;
937 }