]> git.saurik.com Git - wxWidgets.git/blame - utils/wxrc/wxrc.cpp
load any files, not only XPMs, in wxIcon(wxIconLocation)
[wxWidgets.git] / utils / wxrc / wxrc.cpp
CommitLineData
56d2f750
VS
1/////////////////////////////////////////////////////////////////////////////
2// Name: wxrc.cpp
3// Purpose: XML resource compiler
4// Author: Vaclav Slavik
5// Created: 2000/03/05
6// RCS-ID: $Id$
7// Copyright: (c) 2000 Vaclav Slavik
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
ab7ce33c 11#if defined(__GNUG__) && !defined(__APPLE__)
56d2f750
VS
12 #pragma implementation
13 #pragma interface
14#endif
15
16// For compilers that support precompilation, includes "wx/wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20 #pragma hdrstop
21#endif
22
23// for all others, include the necessary headers (this file is usually all you
24// need because it includes almost all "standard" wxWindows headers
25#ifndef WX_PRECOMP
26 #include "wx/wx.h"
27#endif
28
29#include "wx/cmdline.h"
cecc483e 30#include "wx/xml/xml.h"
56d2f750 31#include "wx/ffile.h"
4249ec2c 32#include "wx/filename.h"
f6853b4a
VS
33#include "wx/wfstream.h"
34
35
cecc483e 36class XmlResApp : public wxAppConsole
56d2f750
VS
37{
38public:
031dfec8 39
56d2f750
VS
40 virtual int OnRun();
41
42private:
43
44 void ParseParams(const wxCmdLineParser& cmdline);
45 void CompileRes();
46 wxArrayString PrepareTempFiles();
f6853b4a
VS
47 void FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath);
48
a7501aeb 49 wxString GetInternalFileName(const wxString& name, const wxArrayString& flist);
56d2f750
VS
50 void DeleteTempFiles(const wxArrayString& flist);
51 void MakePackageZIP(const wxArrayString& flist);
52 void MakePackageCPP(const wxArrayString& flist);
b8b8c49b 53 void MakePackagePython(const wxArrayString& flist);
c8b7a961
VS
54
55 void OutputGettext();
56 wxArrayString FindStrings();
57 wxArrayString FindStrings(wxXmlNode *node);
56d2f750 58
b8b8c49b 59 bool flagVerbose, flagCPP, flagPython, flagGettext;
56d2f750
VS
60 wxString parOutput, parFuncname, parOutputPath;
61 wxArrayString parFiles;
62 int retCode;
63};
64
65IMPLEMENT_APP(XmlResApp)
66
67int XmlResApp::OnRun()
68{
69 static const wxCmdLineEntryDesc cmdLineDesc[] =
70 {
2b5f62a0 71 { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show help message"),
99cd20be 72 wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
2b5f62a0
VZ
73 { wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose") },
74 { wxCMD_LINE_SWITCH, _T("c"), _T("cpp-code"), _T("output C++ source rather than .rsc file") },
75 { wxCMD_LINE_SWITCH, _T("p"), _T("python-code"), _T("output wxPython source rather than .rsc file") },
76 { wxCMD_LINE_SWITCH, _T("g"), _T("gettext"), _T("output list of translatable strings (to stdout or file if -o used)") },
77 { wxCMD_LINE_OPTION, _T("n"), _T("function"), _T("C++/Python function name (with -c or -p) [InitXmlResource]") },
78 { wxCMD_LINE_OPTION, _T("o"), _T("output"), _T("output file [resource.xrs/cpp]") },
99cd20be 79#if 0 // not yet implemented
2b5f62a0 80 { wxCMD_LINE_OPTION, _T("l"), _T("list-of-handlers", _T("output list of neccessary handlers to this file" },
99cd20be 81#endif
2b5f62a0 82 { wxCMD_LINE_PARAM, NULL, NULL, _T("input file(s)"),
99cd20be
VS
83 wxCMD_LINE_VAL_STRING,
84 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_OPTION_MANDATORY },
56d2f750
VS
85
86 { wxCMD_LINE_NONE }
87 };
88
89 wxCmdLineParser parser(cmdLineDesc, argc, argv);
90
91 switch (parser.Parse())
92 {
93 case -1:
94 return 0;
95 break;
96
97 case 0:
98 retCode = 0;
99 ParseParams(parser);
c8b7a961
VS
100 if (flagGettext)
101 OutputGettext();
102 else
103 CompileRes();
56d2f750
VS
104 return retCode;
105 break;
106
107 default:
108 return 1;
109 break;
110 }
111}
112
113
114
115
116void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
117{
2b5f62a0
VZ
118 flagGettext = cmdline.Found(_T("g"));
119 flagVerbose = cmdline.Found(_T("v"));
120 flagCPP = cmdline.Found(_T("c"));
121 flagPython = cmdline.Found(_T("p"));
56d2f750 122
2b5f62a0 123 if (!cmdline.Found(_T("o"), &parOutput))
c8b7a961
VS
124 {
125 if (flagGettext)
126 parOutput = wxEmptyString;
127 else
b8b8c49b
VS
128 {
129 if (flagCPP)
2b5f62a0 130 parOutput = _T("resource.cpp");
b8b8c49b 131 else if (flagPython)
2b5f62a0 132 parOutput = _T("resource.py");
b8b8c49b 133 else
2b5f62a0 134 parOutput = _T("resource.xrs");
b8b8c49b 135 }
c8b7a961 136 }
4249ec2c
VS
137 wxFileName fn(parOutput);
138 fn.Normalize();
139 parOutput = fn.GetFullPath();
56d2f750 140 parOutputPath = wxPathOnly(parOutput);
2b5f62a0 141 if (!parOutputPath) parOutputPath = _T(".");
56d2f750 142
2b5f62a0
VZ
143 if (!cmdline.Found(_T("n"), &parFuncname))
144 parFuncname = _T("InitXmlResource");
56d2f750
VS
145
146 for (size_t i = 0; i < cmdline.GetParamCount(); i++)
147 parFiles.Add(cmdline.GetParam(i));
148}
149
150
151
152
153void XmlResApp::CompileRes()
154{
155 wxArrayString files = PrepareTempFiles();
156
157 wxRemoveFile(parOutput);
158
56d2f750
VS
159 if (!retCode)
160 {
161 if (flagCPP)
162 MakePackageCPP(files);
b8b8c49b
VS
163 else if (flagPython)
164 MakePackagePython(files);
56d2f750
VS
165 else
166 MakePackageZIP(files);
167 }
168
169 DeleteTempFiles(files);
170}
171
172
a7501aeb
VS
173wxString XmlResApp::GetInternalFileName(const wxString& name, const wxArrayString& flist)
174{
175 wxString name2 = name;
2b5f62a0
VZ
176 name2.Replace(_T(":"), _T("_"));
177 name2.Replace(_T("/"), _T("_"));
178 name2.Replace(_T("\\"), _T("_"));
179 name2.Replace(_T("*"), _T("_"));
180 name2.Replace(_T("?"), _T("_"));
a7501aeb 181
2b5f62a0 182 wxString s = wxFileNameFromPath(parOutput) + _T("$") + name2;
a7501aeb
VS
183
184 if (wxFileExists(s) && flist.Index(s) == wxNOT_FOUND)
185 {
186 for (int i = 0;; i++)
187 {
2b5f62a0 188 s.Printf(wxFileNameFromPath(parOutput) + _T("$%03i-") + name2, i);
a7501aeb
VS
189 if (!wxFileExists(s) || flist.Index(s) != wxNOT_FOUND)
190 break;
191 }
192 }
193 return s;
194}
56d2f750
VS
195
196wxArrayString XmlResApp::PrepareTempFiles()
197{
198 wxArrayString flist;
199
200 for (size_t i = 0; i < parFiles.Count(); i++)
201 {
202 if (flagVerbose)
2b5f62a0 203 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
56d2f750
VS
204
205 wxXmlDocument doc;
206
207 if (!doc.Load(parFiles[i]))
208 {
2b5f62a0 209 wxLogError(_T("Error parsing file ") + parFiles[i]);
56d2f750
VS
210 retCode = 1;
211 continue;
212 }
213
f6853b4a
VS
214 wxString name, ext, path;
215 wxSplitPath(parFiles[i], &path, &name, &ext);
216
217 FindFilesInXML(doc.GetRoot(), flist, path);
56d2f750 218
a7501aeb
VS
219 wxString internalName = GetInternalFileName(parFiles[i], flist);
220
4249ec2c 221 doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName);
a7501aeb 222 flist.Add(internalName);
56d2f750
VS
223 }
224
225 return flist;
226}
227
228
4249ec2c
VS
229// Does 'node' contain filename information at all?
230static bool NodeContainsFilename(wxXmlNode *node)
231{
232 // Any bitmaps:
233 if (node->GetName() == _T("bitmap"))
234 return TRUE;
235
236 // URLs in wxHtmlWindow:
237 if (node->GetName() == _T("url"))
238 return TRUE;
239
240 // wxBitmapButton:
241 wxXmlNode *parent = node->GetParent();
242 if (parent != NULL &&
243 parent->GetPropVal(_T("class"), _T("")) == _T("wxBitmapButton") &&
244 (node->GetName() == _T("focus") ||
245 node->GetName() == _T("disabled") ||
246 node->GetName() == _T("selected")))
247 return TRUE;
248
249 // wxBitmap or wxIcon toplevel resources:
250 if (node->GetName() == _T("object"))
251 {
252 wxString klass = node->GetPropVal(_T("class"), wxEmptyString);
253 if (klass == _T("wxBitmap") || klass == _T("wxIcon"))
254 return TRUE;
255 }
256
257 return FALSE;
258}
56d2f750 259
f6853b4a
VS
260// find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
261void XmlResApp::FindFilesInXML(wxXmlNode *node, wxArrayString& flist, const wxString& inputPath)
262{
2b5f62a0
VZ
263 // Is 'node' XML node element?
264 if (node == NULL) return;
265 if (node->GetType() != wxXML_ELEMENT_NODE) return;
266
4249ec2c 267 bool containsFilename = NodeContainsFilename(node);
2b5f62a0
VZ
268
269 wxXmlNode *n = node->GetChildren();
f6853b4a
VS
270 while (n)
271 {
2b5f62a0 272 if (containsFilename &&
f6853b4a 273 (n->GetType() == wxXML_TEXT_NODE ||
2b5f62a0 274 n->GetType() == wxXML_CDATA_SECTION_NODE))
f6853b4a
VS
275 {
276 wxString fullname;
2b5f62a0
VZ
277 if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty())
278 fullname = n->GetContent();
279 else
4249ec2c 280 fullname = inputPath + wxFILE_SEP_PATH + n->GetContent();
a7501aeb
VS
281
282 if (flagVerbose)
2b5f62a0
VZ
283 wxPrintf(_T("adding ") + fullname + _T("...\n"));
284
a7501aeb 285 wxString filename = GetInternalFileName(n->GetContent(), flist);
f6853b4a 286 n->SetContent(filename);
f6853b4a 287
2b5f62a0
VZ
288 if (flist.Index(filename) == wxNOT_FOUND)
289 flist.Add(filename);
f6853b4a
VS
290
291 wxFileInputStream sin(fullname);
4249ec2c 292 wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename);
f6853b4a
VS
293 sin.Read(sout); // copy the stream
294 }
2b5f62a0 295
f6853b4a
VS
296 // subnodes:
297 if (n->GetType() == wxXML_ELEMENT_NODE)
298 FindFilesInXML(n, flist, inputPath);
2b5f62a0 299
f6853b4a
VS
300 n = n->GetNext();
301 }
302}
303
304
305
56d2f750
VS
306void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
307{
308 for (size_t i = 0; i < flist.Count(); i++)
4249ec2c 309 wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]);
56d2f750
VS
310}
311
312
313
314void XmlResApp::MakePackageZIP(const wxArrayString& flist)
315{
316 wxString files;
317
318 for (size_t i = 0; i < flist.Count(); i++)
2b5f62a0 319 files += flist[i] + _T(" ");
56d2f750
VS
320 files.RemoveLast();
321
322 if (flagVerbose)
2b5f62a0 323 wxPrintf(_T("compressing ") + parOutput + _T("...\n"));
4249ec2c
VS
324
325 wxString cwd = wxGetCwd();
326 wxSetWorkingDirectory(parOutputPath);
327 int execres = wxExecute(_T("zip -9 -j ") +
328 wxString(flagVerbose ? _T("") : _T("-q ")) +
329 parOutput + _T(" ") + files, TRUE);
330 wxSetWorkingDirectory(cwd);
331 if (execres == -1)
56d2f750 332 {
2b5f62a0
VZ
333 wxLogError(_T("Unable to execute zip program. Make sure it is in the path."));
334 wxLogError(_T("You can download it at http://www.cdrom.com/pub/infozip/"));
56d2f750
VS
335 retCode = 1;
336 return;
337 }
338}
339
340
341
342
343static wxString FileToCppArray(wxString filename, int num)
344{
345 wxString output;
56d2f750 346 wxString tmp;
f6853b4a 347 wxString snum;
5851504d 348 wxFFile file(filename, wxT("rb"));
56d2f750
VS
349 size_t lng = file.Length();
350
2b5f62a0
VZ
351 snum.Printf(_T("%i"), num);
352 output.Printf(_T("static size_t xml_res_size_") + snum + _T(" = %i;\n"), lng);
353 output += _T("static unsigned char xml_res_file_") + snum + _T("[] = {\n");
e066e256
VS
354 // we cannot use string literals because MSVC is dumb wannabe compiler
355 // with arbitrary limitation to 2048 strings :(
56d2f750
VS
356
357 unsigned char *buffer = new unsigned char[lng];
358 file.Read(buffer, lng);
359
f6853b4a 360 for (size_t i = 0, linelng = 0; i < lng; i++)
56d2f750 361 {
2b5f62a0
VZ
362 tmp.Printf(_T("%i"), buffer[i]);
363 if (i != 0) output << _T(',');
e066e256 364 if (linelng > 70)
f6853b4a
VS
365 {
366 linelng = 0;
2b5f62a0 367 output << _T("\n");
f6853b4a 368 }
e066e256
VS
369 output << tmp;
370 linelng += tmp.Length()+1;
56d2f750
VS
371 }
372
373 delete[] buffer;
374
2b5f62a0 375 output += _T("};\n\n");
56d2f750
VS
376
377 return output;
378}
379
380
381void XmlResApp::MakePackageCPP(const wxArrayString& flist)
382{
5851504d 383 wxFFile file(parOutput, wxT("wt"));
56d2f750
VS
384 size_t i;
385
386 if (flagVerbose)
2b5f62a0 387 wxPrintf(_T("creating C++ source file ") + parOutput + _T("...\n"));
56d2f750 388
2b5f62a0
VZ
389 file.Write(_T("")
390_T("//\n")
391_T("// This file was automatically generated by wxrc, do not edit by hand.\n")
392_T("//\n\n")
393_T("#include <wx/wxprec.h>\n")
394_T("\n")
395_T("#ifdef __BORLANDC__\n")
396_T(" #pragma hdrstop\n")
397_T("#endif\n")
398_T("\n")
399_T("#ifndef WX_PRECOMP\n")
400_T(" #include <wx/wx.h>\n")
401_T("#endif\n")
402_T("")
403_T("#include <wx/filesys.h>\n")
404_T("#include <wx/fs_mem.h>\n")
405_T("#include <wx/xrc/xmlres.h>\n")
406_T("#include <wx/xrc/xh_all.h>\n")
407_T("\n"));
56d2f750
VS
408
409 for (i = 0; i < flist.Count(); i++)
4249ec2c
VS
410 file.Write(
411 FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
56d2f750 412
2b5f62a0 413 file.Write(_T("")
5851504d 414_T("void ") + parFuncname + wxT("()\n")
2b5f62a0
VZ
415_T("{\n")
416_T("\n")
417_T(" // Check for memory FS. If not present, load the handler:\n")
418_T(" {\n")
5851504d 419_T(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));\n")
2b5f62a0 420_T(" wxFileSystem fsys;\n")
5851504d
VS
421_T(" wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));\n")
422_T(" wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));\n")
2b5f62a0
VZ
423_T(" if (f) delete f;\n")
424_T(" else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n")
425_T(" }\n")
426_T("\n"));
56d2f750
VS
427
428 for (i = 0; i < flist.Count(); i++)
429 {
430 wxString s;
5851504d
VS
431 s.Printf(_T(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/") + flist[i] +
432 _T("\"), xml_res_file_%i, xml_res_size_%i);\n"), i, i);
56d2f750
VS
433 file.Write(s);
434 }
f6853b4a
VS
435
436 for (i = 0; i < parFiles.Count(); i++)
437 {
5851504d
VS
438 file.Write(_T(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/") +
439 GetInternalFileName(parFiles[i], flist) + _T("\"));\n"));
f6853b4a 440 }
56d2f750 441
2b5f62a0 442 file.Write(_T("}\n"));
56d2f750 443
f6853b4a 444
56d2f750 445}
c8b7a961 446
b8b8c49b
VS
447static wxString FileToPythonArray(wxString filename, int num)
448{
449 wxString output;
450 wxString tmp;
451 wxString snum;
5851504d 452 wxFFile file(filename, wxT("rb"));
b8b8c49b
VS
453 size_t lng = file.Length();
454
2b5f62a0
VZ
455 snum.Printf(_T("%i"), num);
456 output = _T(" xml_res_file_") + snum + _T(" = \"\"\"\\\n");
b8b8c49b
VS
457
458 unsigned char *buffer = new unsigned char[lng];
459 file.Read(buffer, lng);
460
461 for (size_t i = 0, linelng = 0; i < lng; i++)
462 {
463 unsigned char c = buffer[i];
464 if (c == '\n')
465 {
466 tmp = (wxChar)c;
467 linelng = 0;
468 }
469 else if (c < 32 || c > 127)
2b5f62a0 470 tmp.Printf(_T("\\x%02x"), c);
b8b8c49b 471 else if (c == '\\')
2b5f62a0 472 tmp = _T("\\\\");
b8b8c49b
VS
473 else
474 tmp = (wxChar)c;
475 if (linelng > 70)
476 {
477 linelng = 0;
2b5f62a0 478 output << _T("\\\n");
b8b8c49b
VS
479 }
480 output << tmp;
481 linelng += tmp.Length();
482 }
483
484 delete[] buffer;
485
2b5f62a0 486 output += _T("\"\"\"\n\n");
b8b8c49b
VS
487
488 return output;
489}
490
491
492void XmlResApp::MakePackagePython(const wxArrayString& flist)
493{
5851504d 494 wxFFile file(parOutput, wxT("wt"));
b8b8c49b
VS
495 size_t i;
496
497 if (flagVerbose)
2b5f62a0 498 wxPrintf(_T("creating Python source file ") + parOutput + _T("...\n"));
b8b8c49b
VS
499
500 file.Write(
2b5f62a0
VZ
501 _T("#\n")
502 _T("# This file was automatically generated by wxrc, do not edit by hand.\n")
503 _T("#\n\n")
504 _T("from wxPython.wx import *\n")
505 _T("from wxPython.xrc import *\n\n")
b8b8c49b
VS
506 );
507
508
2b5f62a0 509 file.Write(_T("def ") + parFuncname + _T("():\n"));
b8b8c49b
VS
510
511 for (i = 0; i < flist.Count(); i++)
4249ec2c
VS
512 file.Write(
513 FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
b8b8c49b
VS
514
515 for (i = 0; i < flist.Count(); i++)
516 {
517 wxString s;
2b5f62a0 518 s.Printf(_T(" wxXmlResource_Get().LoadFromString(xml_res_file_%i)\n"), i);
b8b8c49b
VS
519 file.Write(s);
520 }
521}
522
c8b7a961
VS
523
524
525void XmlResApp::OutputGettext()
526{
527 wxArrayString str = FindStrings();
528
529 wxFFile fout;
530 if (!parOutput) fout.Attach(stdout);
5851504d 531 else fout.Open(parOutput, wxT("wt"));
c8b7a961
VS
532
533 for (size_t i = 0; i < str.GetCount(); i++)
0653d364 534 fout.Write(_T("_(\"") + str[i] + _T("\");\n"));
c8b7a961
VS
535
536 if (!parOutput) fout.Detach();
537}
538
539
540
541wxArrayString XmlResApp::FindStrings()
542{
543 wxArrayString arr, a2;
544
545 for (size_t i = 0; i < parFiles.Count(); i++)
546 {
547 if (flagVerbose)
2b5f62a0 548 wxPrintf(_T("processing ") + parFiles[i] + _T("...\n"));
c8b7a961
VS
549
550 wxXmlDocument doc;
551 if (!doc.Load(parFiles[i]))
552 {
2b5f62a0 553 wxLogError(_T("Error parsing file ") + parFiles[i]);
c8b7a961
VS
554 retCode = 1;
555 continue;
556 }
557 a2 = FindStrings(doc.GetRoot());
558 WX_APPEND_ARRAY(arr, a2);
559 }
560
561 return arr;
562}
563
564
565
c109ef11
VS
566static wxString ConvertText(const wxString& str)
567{
568 wxString str2;
569 const wxChar *dt;
570
571 for (dt = str.c_str(); *dt; dt++)
572 {
573 if (*dt == wxT('_'))
574 {
575 if ( *(++dt) == wxT('_') )
576 str2 << wxT('_');
577 else
578 str2 << wxT('&') << *dt;
579 }
580 else
581 {
582 switch (*dt)
583 {
584 case wxT('\n') : str2 << wxT("\\n"); break;
585 case wxT('\t') : str2 << wxT("\\t"); break;
586 case wxT('\r') : str2 << wxT("\\r"); break;
2b5f62a0
VZ
587 case wxT('\\') : if ((*(dt+1) != 'n') &&
588 (*(dt+1) != 't') &&
589 (*(dt+1) != 'r'))
590 str2 << wxT("\\\\");
591 else
592 str2 << wxT("\\");
593 break;
904a226c 594 case wxT('"') : str2 << wxT("\\\""); break;
c109ef11
VS
595 default : str2 << *dt; break;
596 }
597 }
598 }
599
600 return str2;
601}
602
603
c8b7a961
VS
604wxArrayString XmlResApp::FindStrings(wxXmlNode *node)
605{
606 wxArrayString arr;
607
608 wxXmlNode *n = node;
609 if (n == NULL) return arr;
610 n = n->GetChildren();
611
612 while (n)
613 {
614 if ((node->GetType() == wxXML_ELEMENT_NODE) &&
615 // parent is an element, i.e. has subnodes...
616 (n->GetType() == wxXML_TEXT_NODE ||
617 n->GetType() == wxXML_CDATA_SECTION_NODE) &&
618 // ...it is textnode...
619 (
620 node/*not n!*/->GetName() == _T("label") ||
621 (node/*not n!*/->GetName() == _T("value") &&
622 !n->GetContent().IsNumber()) ||
623 node/*not n!*/->GetName() == _T("help") ||
624 node/*not n!*/->GetName() == _T("longhelp") ||
625 node/*not n!*/->GetName() == _T("tooltip") ||
626 node/*not n!*/->GetName() == _T("htmlcode") ||
0653d364
VS
627 node/*not n!*/->GetName() == _T("title") ||
628 node/*not n!*/->GetName() == _T("item")
c8b7a961 629 ))
c109ef11 630 // ...and known to contain translatable string
c8b7a961 631 {
c109ef11 632 arr.Add(ConvertText(n->GetContent()));
c8b7a961
VS
633 }
634
635 // subnodes:
636 if (n->GetType() == wxXML_ELEMENT_NODE)
637 {
638 wxArrayString a2 = FindStrings(n);
639 WX_APPEND_ARRAY(arr, a2);
640 }
641
642 n = n->GetNext();
643 }
644 return arr;
645}