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