1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: XML resource compiler
4 // Author: Vaclav Slavik
7 // Copyright: (c) 2000 Vaclav Slavik
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
23 // for all others, include the necessary headers (this file is usually all you
24 // need because it includes almost all "standard" wxWindows headers
29 #include "wx/cmdline.h"
30 #include "wx/xml/xml.h"
31 #include "wx/xml/xmlio.h"
33 #include "wx/wfstream.h"
41 #error "You must compile the resource compiler with wxBase!"
45 class XmlResApp
: public wxApp
57 void ParseParams(const wxCmdLineParser
& cmdline
);
59 wxArrayString
PrepareTempFiles();
60 void FindFilesInXML(wxXmlNode
*node
, wxArrayString
& flist
, const wxString
& inputPath
);
62 void DeleteTempFiles(const wxArrayString
& flist
);
63 void MakePackageZIP(const wxArrayString
& flist
);
64 void MakePackageCPP(const wxArrayString
& flist
);
67 wxArrayString
FindStrings();
68 wxArrayString
FindStrings(wxXmlNode
*node
);
70 bool flagVerbose
, flagCPP
, flagCompress
, flagGettext
;
71 wxString parOutput
, parFuncname
, parOutputPath
;
72 wxArrayString parFiles
;
76 IMPLEMENT_APP(XmlResApp
)
79 bool XmlResApp::OnInit()
81 int XmlResApp::OnRun()
84 static const wxCmdLineEntryDesc cmdLineDesc
[] =
86 { wxCMD_LINE_SWITCH
, "h", "help", "show help message" },
87 { wxCMD_LINE_SWITCH
, "v", "verbose", "be verbose" },
88 { wxCMD_LINE_SWITCH
, "c", "cpp-code", "output C++ source rather than .rsc file" },
89 { wxCMD_LINE_SWITCH
, "u", "uncompressed", "do not compress .xml files (C++ only)" },
90 { wxCMD_LINE_SWITCH
, "g", "gettext", "output .po catalog (to stdout or file if -o used)" },
91 { wxCMD_LINE_OPTION
, "n", "function", "C++ function name (with -c) [InitXmlResource]" },
92 { wxCMD_LINE_OPTION
, "o", "output", "output file [resource.xrs/cpp]" },
93 { wxCMD_LINE_OPTION
, "l", "list-of-handlers", "output list of neccessary handlers to this file" },
95 { wxCMD_LINE_PARAM
, NULL
, NULL
, "input file(s)",
96 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_MULTIPLE
},
101 wxXmlDocument::AddHandler(new wxXmlIOHandlerBinZ
);
103 wxCmdLineParser
parser(cmdLineDesc
, argc
, argv
);
105 switch (parser
.Parse())
138 void XmlResApp::ParseParams(const wxCmdLineParser
& cmdline
)
140 flagGettext
= cmdline
.Found("g");
141 flagVerbose
= cmdline
.Found("v");
142 flagCPP
= cmdline
.Found("c");
143 flagCompress
= flagCPP
&& !cmdline
.Found("u");
145 if (!cmdline
.Found("o", &parOutput
))
148 parOutput
= wxEmptyString
;
150 parOutput
= flagCPP
? "resource.cpp" : "resource.xrs";
152 parOutputPath
= wxPathOnly(parOutput
);
153 if (!parOutputPath
) parOutputPath
= ".";
155 if (!cmdline
.Found("n", &parFuncname
))
156 parFuncname
= "InitXmlResource";
158 for (size_t i
= 0; i
< cmdline
.GetParamCount(); i
++)
159 parFiles
.Add(cmdline
.GetParam(i
));
165 void XmlResApp::CompileRes()
167 wxArrayString files
= PrepareTempFiles();
169 wxRemoveFile(parOutput
);
174 MakePackageCPP(files
);
176 MakePackageZIP(files
);
179 DeleteTempFiles(files
);
184 wxArrayString
XmlResApp::PrepareTempFiles()
188 for (size_t i
= 0; i
< parFiles
.Count(); i
++)
191 wxPrintf("processing " + parFiles
[i
] + "...\n");
195 if (!doc
.Load(parFiles
[i
]))
197 wxLogError("Error parsing file " + parFiles
[i
]);
202 wxString name
, ext
, path
;
203 wxSplitPath(parFiles
[i
], &path
, &name
, &ext
);
205 FindFilesInXML(doc
.GetRoot(), flist
, path
);
207 doc
.Save(parOutputPath
+ "/" + name
+ ".xrc", flagCompress
? wxXML_IO_BINZ
: wxXML_IO_BIN
);
208 flist
.Add(name
+ ".xrc");
216 // find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
217 void XmlResApp::FindFilesInXML(wxXmlNode
*node
, wxArrayString
& flist
, const wxString
& inputPath
)
220 if (n
== NULL
) return;
221 n
= n
->GetChildren();
225 if ((node
->GetType() == wxXML_ELEMENT_NODE
) &&
226 // parent is an element, i.e. has subnodes...
227 (n
->GetType() == wxXML_TEXT_NODE
||
228 n
->GetType() == wxXML_CDATA_SECTION_NODE
) &&
229 // ...it is textnode...
230 (node
/*not n!*/->GetName() == "bitmap"))
231 // ...and known to contain filename
234 wxString filename
= n
->GetContent();
235 if (wxIsAbsolutePath(n
->GetContent())) fullname
= n
->GetContent();
236 else fullname
= inputPath
+ "/" + n
->GetContent();
238 filename
.Replace("/", "_");
239 filename
.Replace("\\", "_");
240 filename
.Replace("*", "_");
241 filename
.Replace("?", "_");
242 n
->SetContent(filename
);
245 wxPrintf("adding " + filename
+ "...\n");
249 wxFileInputStream
sin(fullname
);
250 wxFileOutputStream
sout(parOutputPath
+ "/" + filename
);
251 sin
.Read(sout
); // copy the stream
255 if (n
->GetType() == wxXML_ELEMENT_NODE
)
256 FindFilesInXML(n
, flist
, inputPath
);
264 void XmlResApp::DeleteTempFiles(const wxArrayString
& flist
)
266 for (size_t i
= 0; i
< flist
.Count(); i
++)
267 wxRemoveFile(parOutputPath
+ "/" + flist
[i
]);
272 void XmlResApp::MakePackageZIP(const wxArrayString
& flist
)
276 for (size_t i
= 0; i
< flist
.Count(); i
++)
277 files
+= flist
[i
] + " ";
281 wxPrintf("compressing " + parOutput
+ "...\n");
283 if (wxExecute("zip -9 -j " + wxString(flagVerbose
? "" : "-q ") +
284 parOutput
+ " " + files
, TRUE
) == -1)
286 wxLogError("Unable to execute zip program. Make sure it is in the path.");
287 wxLogError("You can download it at http://www.cdrom.com/pub/infozip/");
296 static wxString
FileToCppArray(wxString filename
, int num
)
301 wxFFile
file(filename
, "rb");
302 size_t lng
= file
.Length();
304 snum
.Printf("%i", num
);
305 output
.Printf("static size_t xml_res_size_" + snum
+ " = %i;\n", lng
);
306 output
+= "static unsigned char xml_res_file_" + snum
+ "[] = {\n";
307 // we cannot use string literals because MSVC is dumb wannabe compiler
308 // with arbitrary limitation to 2048 strings :(
310 unsigned char *buffer
= new unsigned char[lng
];
311 file
.Read(buffer
, lng
);
313 for (size_t i
= 0, linelng
= 0; i
< lng
; i
++)
315 tmp
.Printf("%i", buffer
[i
]);
316 if (i
!= 0) output
<< ',';
323 linelng
+= tmp
.Length()+1;
334 void XmlResApp::MakePackageCPP(const wxArrayString
& flist
)
336 wxFFile
file(parOutput
, "wt");
340 wxPrintf("creating C++ source file " + parOutput
+ "...\n");
343 #include \"wx/wxprec.h\"\n\
345 #ifdef __BORLANDC__\n\
349 #ifndef WX_PRECOMP\n\
350 #include \"wx/wx.h\"\n\
353 #include \"wx/filesys.h\"\n\
354 #include \"wx/fs_mem.h\"\n\
355 #include \"wx/xml/xmlres.h\"\n\
356 #include \"wx/xml/xh_all.h\"\n\
359 for (i
= 0; i
< flist
.Count(); i
++)
360 file
.Write(FileToCppArray(flist
[i
], i
));
363 void " + parFuncname
+ "()\n\
366 // Check for memory FS. If not present, load the handler:\n\
368 wxMemoryFSHandler::AddFile(\"xml_resource/dummy_file\", \"dummy one\");\n\
369 wxFileSystem fsys;\n\
370 wxFSFile *f = fsys.OpenFile(\"memory:xml_resource/dummy_file\");\n\
371 wxMemoryFSHandler::RemoveFile(\"xml_resource/dummy_file\");\n\
373 else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n\
377 for (i
= 0; i
< flist
.Count(); i
++)
380 s
.Printf(" wxMemoryFSHandler::AddFile(\"xml_resource/" + flist
[i
] +
381 "\", xml_res_file_%i, xml_res_size_%i);\n", i
, i
);
385 for (i
= 0; i
< parFiles
.Count(); i
++)
387 wxString name
, ext
, path
;
388 wxSplitPath(parFiles
[i
], &path
, &name
, &ext
);
389 file
.Write(" wxTheXmlResource->Load(\"memory:xml_resource/" +
390 name
+ ".xrc" + "\");\n");
400 void XmlResApp::OutputGettext()
402 wxArrayString str
= FindStrings();
405 if (!parOutput
) fout
.Attach(stdout
);
406 else fout
.Open(parOutput
, _T("wt"));
408 for (size_t i
= 0; i
< str
.GetCount(); i
++)
409 fout
.Write(_T("msgid \"") + str
[i
] + _T("\"\nmsgstr \"\"\n\n"));
411 if (!parOutput
) fout
.Detach();
416 wxArrayString
XmlResApp::FindStrings()
418 wxArrayString arr
, a2
;
420 for (size_t i
= 0; i
< parFiles
.Count(); i
++)
423 wxPrintf("processing " + parFiles
[i
] + "...\n");
426 if (!doc
.Load(parFiles
[i
]))
428 wxLogError("Error parsing file " + parFiles
[i
]);
432 a2
= FindStrings(doc
.GetRoot());
433 WX_APPEND_ARRAY(arr
, a2
);
441 wxArrayString
XmlResApp::FindStrings(wxXmlNode
*node
)
446 if (n
== NULL
) return arr
;
447 n
= n
->GetChildren();
451 if ((node
->GetType() == wxXML_ELEMENT_NODE
) &&
452 // parent is an element, i.e. has subnodes...
453 (n
->GetType() == wxXML_TEXT_NODE
||
454 n
->GetType() == wxXML_CDATA_SECTION_NODE
) &&
455 // ...it is textnode...
457 node
/*not n!*/->GetName() == _T("label") ||
458 (node
/*not n!*/->GetName() == _T("value") &&
459 !n
->GetContent().IsNumber()) ||
460 node
/*not n!*/->GetName() == _T("help") ||
461 node
/*not n!*/->GetName() == _T("longhelp") ||
462 node
/*not n!*/->GetName() == _T("tooltip") ||
463 node
/*not n!*/->GetName() == _T("htmlcode") ||
464 node
/*not n!*/->GetName() == _T("title")
466 // ...and known to contain filename
468 arr
.Add(n
->GetContent());
472 if (n
->GetType() == wxXML_ELEMENT_NODE
)
474 wxArrayString a2
= FindStrings(n
);
475 WX_APPEND_ARRAY(arr
, a2
);