fixed some bugs in wxrc compiler
[wxWidgets.git] / utils / wxrc / wxrc.cpp
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
11 #ifdef __GNUG__
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"
30 #include "wx/xml/xml.h"
31 #include "wx/xml/xmlio.h"
32 #include "wx/ffile.h"
33
34 /*
35 #if wxUSE_GUI
36 #error "You must compile the resource compiler with wxBase!"
37 #endif
38 */
39
40 class XmlResApp : public wxApp
41 {
42 public:
43
44 #if wxUSE_GUI
45 bool OnInit();
46 #else
47 virtual int OnRun();
48 #endif
49
50 private:
51
52 void ParseParams(const wxCmdLineParser& cmdline);
53 void CompileRes();
54 wxArrayString PrepareTempFiles();
55 void DeleteTempFiles(const wxArrayString& flist);
56 void MakePackageZIP(const wxArrayString& flist);
57 void MakePackageCPP(const wxArrayString& flist);
58
59 bool flagVerbose, flagCPP, flagCompress;
60 wxString parOutput, parFuncname, parOutputPath;
61 wxArrayString parFiles;
62 int retCode;
63 };
64
65 IMPLEMENT_APP(XmlResApp)
66
67 #if wxUSE_GUI
68 bool XmlResApp::OnInit()
69 #else
70 int XmlResApp::OnRun()
71 #endif
72 {
73 static const wxCmdLineEntryDesc cmdLineDesc[] =
74 {
75 { wxCMD_LINE_SWITCH, "v", "verbose", "be verbose" },
76 { wxCMD_LINE_SWITCH, "c", "cpp-code", "output C++ source rather than .rsc file" },
77 { wxCMD_LINE_SWITCH, "u", "uncompressed", "do not compress .xml files (C++ only)" },
78 { wxCMD_LINE_OPTION, "n", "function", "C++ function name (with -c) [InitXmlResource]" },
79 { wxCMD_LINE_OPTION, "o", "output", "output file [resource.rsc/cpp]" },
80 { wxCMD_LINE_OPTION, "l", "list-of-handlers", "output list of neccessary handlers to this file" },
81
82 { wxCMD_LINE_PARAM, NULL, NULL, "input file",
83 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE },
84
85 { wxCMD_LINE_NONE }
86 };
87
88 wxXmlDocument::AddHandler(new wxXmlIOHandlerBinZ);
89
90 wxCmdLineParser parser(cmdLineDesc, argc, argv);
91
92 switch (parser.Parse())
93 {
94 case -1:
95 return 0;
96 break;
97
98 case 0:
99 retCode = 0;
100 ParseParams(parser);
101 CompileRes();
102 #if wxUSE_GUI
103 return FALSE;
104 #else
105 return retCode;
106 #endif
107 break;
108
109 default:
110 #if wxUSE_GUI
111 return FALSE;
112 #else
113 return 1;
114 #endif
115 break;
116 }
117 }
118
119
120
121
122 void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
123 {
124 flagVerbose = cmdline.Found("v");
125 flagCPP = cmdline.Found("c");
126 flagCompress = flagCPP && !cmdline.Found("u");
127
128 if (!cmdline.Found("o", &parOutput))
129 parOutput = flagCPP ? "resource.cpp" : "resource.rsc";
130 parOutputPath = wxPathOnly(parOutput);
131 if (!parOutputPath) parOutputPath = ".";
132
133 if (!cmdline.Found("n", &parFuncname))
134 parFuncname = "InitXmlResource";
135
136 for (size_t i = 0; i < cmdline.GetParamCount(); i++)
137 parFiles.Add(cmdline.GetParam(i));
138 }
139
140
141
142
143 void XmlResApp::CompileRes()
144 {
145 wxArrayString files = PrepareTempFiles();
146
147 wxRemoveFile(parOutput);
148
149 if (!retCode)
150 {
151 if (flagCPP)
152 MakePackageCPP(files);
153 else
154 MakePackageZIP(files);
155 }
156
157 DeleteTempFiles(files);
158 }
159
160
161
162 wxArrayString XmlResApp::PrepareTempFiles()
163 {
164 wxArrayString flist;
165
166 for (size_t i = 0; i < parFiles.Count(); i++)
167 {
168 if (flagVerbose)
169 wxPrintf("processing " + parFiles[i] + "...\n");
170
171 wxXmlDocument doc;
172
173 if (!doc.Load(parFiles[i]))
174 {
175 wxLogError("Error parsing file " + parFiles[i]);
176 retCode = 1;
177 continue;
178 }
179
180 wxString name, ext;
181 wxSplitPath(parFiles[i], NULL, &name, &ext);
182
183 doc.Save(parOutputPath + "/" + name + ".xmb", flagCompress ? wxXML_IO_BINZ : wxXML_IO_BIN);
184 flist.Add(name + ".xmb");
185 }
186
187 return flist;
188 }
189
190
191
192 void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
193 {
194 for (size_t i = 0; i < flist.Count(); i++)
195 wxRemoveFile(parOutputPath + "/" + flist[i]);
196 }
197
198
199
200 void XmlResApp::MakePackageZIP(const wxArrayString& flist)
201 {
202 wxString files;
203
204 for (size_t i = 0; i < flist.Count(); i++)
205 files += flist[i] + " ";
206 files.RemoveLast();
207
208 if (flagVerbose)
209 wxPrintf("compressing " + parOutput + "...\n");
210
211 if (wxExecute("zip -9 -j " + wxString(flagVerbose ? "" : "-q ") +
212 parOutput + " " + files, TRUE) == -1)
213 {
214 wxLogError("Unable to execute zip program. Make sure it is in the path.");
215 wxLogError("You can download it at http://www.cdrom.com/pub/infozip/");
216 retCode = 1;
217 return;
218 }
219 }
220
221
222
223
224 static wxString FileToCppArray(wxString filename, int num)
225 {
226 wxString output;
227 wxString snum;
228 wxString tmp;
229 wxFFile file(filename, "rb");
230 size_t lng = file.Length();
231
232 snum.Printf("%i", num);
233 output.Printf("static size_t xml_res_size_" + snum + " = %i;\n", lng);
234 output += "static unsigned char xml_res_file_" + snum + "[] = {";
235
236 unsigned char *buffer = new unsigned char[lng];
237 file.Read(buffer, lng);
238
239 for (size_t i = 0; i < lng; i++)
240 {
241 if (i % 16 == 0) output += "\n";
242 tmp.Printf("0x%02X", buffer[i]);
243 output += tmp;
244 if (i != lng-1) output += ",";
245 }
246
247 delete[] buffer;
248
249 output += "\n};\n\n";
250
251 return output;
252 }
253
254
255 void XmlResApp::MakePackageCPP(const wxArrayString& flist)
256 {
257 wxFFile file(parOutput, "wt");
258 size_t i;
259
260 if (flagVerbose)
261 wxPrintf("creating C++ source file " + parOutput + "...\n");
262
263 file.Write("\
264 #include \"wx/wxprec.h\"\n\
265 \n\
266 #ifdef __BORLANDC__\n\
267 #pragma hdrstop\n\
268 #endif\n\
269 \n\
270 #ifndef WX_PRECOMP\n\
271 #include \"wx/wx.h\"\n\
272 #endif\n\
273 \
274 #include \"wx/filesys.h\"\n\
275 #include \"wx/fs_mem.h\"\n\
276 #include \"wx/xml/xmlres.h\"\n\
277 #include \"wx/xml/xh_all.h\"\n\
278 \n");
279
280 for (i = 0; i < flist.Count(); i++)
281 file.Write(FileToCppArray(flist[i], i));
282
283 file.Write("\
284 void " + parFuncname + "()\n\
285 {\n\
286 \n\
287 // Check for memory FS. If not present, load the handler:\n\
288 {\n\
289 wxMemoryFSHandler::AddFile(\"xml_resource/dummy_file\", \"dummy one\");\n\
290 wxFileSystem fsys;\n\
291 wxFSFile *f = fsys.OpenFile(\"memory:xml_resource/dummy_file\");\n\
292 wxMemoryFSHandler::RemoveFile(\"xml_resource/dummy_file\");\n\
293 if (f) delete f;\n\
294 else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n\
295 }\n\
296 \n");
297
298 for (i = 0; i < flist.Count(); i++)
299 {
300 wxString s;
301 s.Printf(" wxMemoryFSHandler::AddFile(\"xml_resource/" + flist[i] +
302 "\", xml_res_file_%i, xml_res_size_%i);\n"
303 " wxTheXmlResource->Load(\"memory:xml_resource/" + flist[i] +
304 "\");\n", i, i);
305 file.Write(s);
306 }
307
308 file.Write("\n}\n");
309
310 }