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