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