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