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