]> git.saurik.com Git - wxWidgets.git/blob - contrib/utils/convertrc/rc2xml.cpp
glibc's vswprintf doesn't nul terminate on truncation.
[wxWidgets.git] / contrib / utils / convertrc / rc2xml.cpp
1 // rc2xml.cpp: implementation of the rc2xml class.
2 //Author: Brian Gavin 9/24/00
3 //License: wxWindows License
4 /*
5 How to use:
6 #include "rc2xml.h"
7 ...
8 rc2xml trans;
9 trans->Convert("Myfile.rc","Myfile.xml");
10 */
11 /* TODO
12 1. Figure how to fix memory leaks in all wxLists in this class
13 2. Find a way to rename MS Windows fonts so that they work
14 cross platform (wxGTK,etc)
15 3. Be able to abort incorrectly formatted files without crashing
16 */
17
18 // For compilers that support precompilation, includes "wx/wx.h".
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 // for all others, include the necessary headers (this file is usually all you
26 // need because it includes almost all "standard" wxWidgets headers
27 #ifndef WX_PRECOMP
28 #include "wx/wx.h"
29 #endif
30
31
32 #include "rc2xml.h"
33 #include "wx/image.h"
34 #include "wx/deprecated/setup.h"
35 #include "wx/deprecated/resource.h"
36 #include "wx/textfile.h"
37 #include "wx/tokenzr.h"
38
39
40
41 //////////////////////////////////////////////////////////////////////
42 // Construction/Destruction
43 //////////////////////////////////////////////////////////////////////
44
45 rc2xml::rc2xml()
46 {
47 m_done=false;
48 m_bitmaplist=new wxList(wxKEY_STRING);
49 m_stringtable=new wxList(wxKEY_STRING);
50 m_iconlist = new wxList(wxKEY_STRING);
51 m_resourcelist =new wxList(wxKEY_INTEGER);
52 }
53
54 rc2xml::~rc2xml()
55 {
56 delete m_bitmaplist;
57 delete m_stringtable;
58 delete m_iconlist;
59 delete m_resourcelist;
60 }
61
62 bool rc2xml::Convert(wxString rcfile, wxString xmlfile)
63 {
64 m_rc.Open(rcfile.c_str());
65 m_filesize=m_rc.Length();
66
67
68 m_workingpath=wxPathOnly(rcfile);
69
70 m_targetpath=wxPathOnly(xmlfile) + _T("\\");
71
72
73
74 wxSetWorkingDirectory(m_workingpath);
75
76
77 bool result;
78 result=m_xmlfile.Open(xmlfile.c_str(),_T("w+t"));
79 wxASSERT_MSG(result,_T("Couldn't create XML file"));
80 if (!result)
81 return false;
82
83
84 /* Write Basic header for XML file */
85 m_xmlfile.Write(_T("<?xml version=\"1.0\" ?>\n"));
86 m_xmlfile.Write(_T("<resource>\n"));
87
88 //Read resource.h
89 ParseResourceHeader();
90 //Gather all the resource we need for toolbars,menus, and etc
91 FirstPass();
92 m_done=false;
93 m_rc.Seek(0);
94 //Read in dialogs, toolbars,menus
95 SecondPass();
96
97 m_xmlfile.Write(_T("</resource>\n"));
98 m_xmlfile.Close();
99 m_rc.Close();
100 wxMessageBox(_("Conversion complete."), _("Done"),
101 wxOK | wxICON_INFORMATION);
102
103 return true;
104 }
105
106
107 void rc2xml::ParseDialog(wxString dlgname)
108 {
109 wxString token;
110 static int dlgid=999;
111 dlgid++;
112 /* Make sure that this really is a dialog
113 microsoft reuses the keyword DIALOG for other things
114 */
115 token=PeekToken();
116 //Microsoft notation?
117 while ((token==_T("DISCARDABLE"))
118 ||(token==_T("LOADONCALL"))||(token==_T("MOVEABLE")))
119 {
120 token=GetToken();
121 token=PeekToken();
122 }
123 //Error isn't a Dialog resource eject eject
124 if (!token.IsNumber())
125 return;
126
127 //Record x,y,width,height
128 int x,y,width,height;
129 ReadRect(x,y,width,height);
130 //Get Title
131 token=GetToken();
132 wxString title;
133 wxString ptsize,face;
134
135 m_xmlfile.Write(_T("\t<object class=\"wxDialog\""));
136 //Avoid duplicate names this way
137 dlgname.Replace(_T("IDD_"),_T("DLG_"));
138 WriteBasicInfo(x,y,width,height,dlgname);
139 WriteTitle(title);
140
141
142 while ((token!=_T("BEGIN"))&(token!=_T("{")))
143 {
144 if (token==_T("CAPTION"))
145 {
146 title=GetQuoteField();
147 }
148
149 //TODO fix face name so that it is cross platform name
150 // FONT 8, "MS Sans Serif"
151 if (token==_T("FONT"))
152 {
153 ptsize=GetToken();
154 face=GetQuoteField();
155 m_xmlfile.Write(_T("\t\t<font>\n"));
156 m_xmlfile.Write(_T("\t\t\t<size>")+ptsize+_T("</size>\n"));
157 m_xmlfile.Write(_T("\t\t\t<face>")+face+_T("</face>\n"));
158 m_xmlfile.Write(_T("\t\t</font>\n"));
159 }
160
161 token=GetToken();
162 }
163
164 ParseControls();
165 m_xmlfile.Write(_T("\t</object>\n"));
166 }
167
168 /*
169 BEGIN
170 EDITTEXT IDC_BANDS,36,83,22,14,ES_AUTOHSCROLL | ES_NUMBER | NOT
171 WS_TABSTOP
172 LTEXT "Bands",IDC_STATIC,11,86,21,8
173 EDITTEXT IDC_NAME,10,3,75,14,ES_AUTOHSCROLL
174 END
175 */
176 void rc2xml::ParseControls()
177 {
178 wxString token;
179 wxString label,varname;
180
181 token=GetToken();
182 while ((token!=_T("END"))&(token!=_T("}")))
183 {
184 if (token==_T("AUTOCHECKBOX"))
185 {
186 label=GetQuoteField();
187 varname=GetToken();
188 ParseCheckBox(label,varname);
189 }
190 else
191 if (token==_T("AUTORADIOBUTTON"))
192 {
193 label=GetQuoteField();
194 varname=GetToken();
195 ParseRadioButton(label,varname);
196 }
197 else
198 if (token==_T("LTEXT"))
199 {
200 label=GetQuoteField();
201 varname=GetToken();
202 ParseStaticText(label,varname);
203 }
204 else if (token==_T("EDITTEXT"))
205 {
206 varname=GetToken();
207 ParseTextCtrl(varname);
208 }
209 else if ((token==_T("PUSHBUTTON"))||(token==_T("DEFPUSHBUTTON")))
210 {
211 label=GetQuoteField();
212 varname=GetToken();
213 ParsePushButton(label,varname);
214 }
215 else if (token==_T("GROUPBOX"))
216 {
217 label=GetQuoteField();
218 varname=GetToken();
219 ParseGroupBox(label,varname);
220 }
221 else if (token==_T("COMBOBOX"))
222 {
223 varname=GetToken();
224 ParseComboBox(varname);
225 }
226 else if (token==_T("CONTROL"))
227 ParseControlMS();
228 else if (token==_T("LISTBOX"))
229 {
230 varname=GetToken();
231 ParseListBox(varname);
232 }
233 else if (token==_T("ICON"))
234 ParseIconStatic();
235 else if (token==_T("SCROLLBAR"))
236 ParseScrollBar();
237 token=GetToken();
238 }
239
240 }
241 //LTEXT "Radius",IDC_STATIC,9,67,23,8
242 void rc2xml::ParseStaticText(wxString phrase, wxString varname)
243 {
244 wxString token;
245 token=PeekToken();
246 while (!token.IsNumber())
247 {
248 token=GetToken();
249 token=PeekToken();
250 }
251 int x,y,width,height;
252 ReadRect(x,y,width,height);
253
254 m_xmlfile.Write(_T("\t\t<object class=\"wxStaticText\""));
255 WriteBasicInfo(x,y,width,height,varname);WriteLabel(phrase);
256 m_xmlfile.Write(_T("\t\t</object>\n"));
257
258 }
259 //EDITTEXT IDC_RADIUS,36,65,40,14,ES_AUTOHSCROLL
260 void rc2xml::ParseTextCtrl(wxString varname)
261 {
262 wxString token;
263 wxString style;
264 token=PeekToken();
265 while (!token.IsNumber())
266 {
267 token=GetToken();
268 token=PeekToken();
269 }
270 int x,y,width,height;
271 ReadRect(x,y,width,height);
272 //TODO
273 //style=GetToken();
274 m_xmlfile.Write(_T("\t\t<object class=\"wxTextCtrl\""));
275 WriteBasicInfo(x,y,width,height,varname);
276 m_xmlfile.Write(_T("\t\t</object>\n"));
277
278 }
279 //AUTOCHECKBOX "&log.", ID_XLOG, 25, 24, 21, 12
280 void rc2xml::ParseCheckBox(wxString phrase, wxString varname)
281 {
282 wxString token;
283 token=PeekToken();
284 while (!token.IsNumber())
285 {
286 token=GetToken();
287 token=PeekToken();
288 }
289 int x,y,width,height;
290 ReadRect(x,y,width,height);
291
292 m_xmlfile.Write(_T("\t\t<object class=\"wxCheckBox\""));
293 WriteBasicInfo(x,y,width,height,varname);
294 WriteLabel(phrase);
295 m_xmlfile.Write(_T("\t\t</object>\n"));
296
297 }
298 //AUTORADIOBUTTON "&text", ID_SW10, 13, 12, 68, 10, BS_AUTORADIOBUTTON | WS_GROUP
299 void rc2xml::ParseRadioButton(wxString phrase, wxString varname)
300 {
301 wxString token,style;
302 int x,y,width,height;
303 bool GotOrs;
304 GotOrs = ReadOrs(token);
305 if (ReadRect(x,y,width,height))
306 if (GotOrs==false)
307 ReadOrs(token);
308 if (token.Find(_T("WS_GROUP")) != wxNOT_FOUND)
309 style += _T("wxRB_GROUP");
310
311 m_xmlfile.Write(_T("\t\t<object class=\"wxRadioButton\""));
312 WriteBasicInfo(x,y,width,height,varname);
313 WriteLabel(phrase);
314 WriteStyle(style);
315 m_xmlfile.Write(_T("\t\t</object>\n"));
316
317 }
318
319 //PUSHBUTTON "Create/Update",IDC_CREATE,15,25,53,13,NOT WS_TABSTOP
320 void rc2xml::ParsePushButton(wxString phrase, wxString varname)
321 {
322 wxString token;
323
324 token=PeekToken();
325 while (!token.IsNumber())
326 {
327 token=GetToken();
328 token=PeekToken();
329 }
330 int x,y,width,height;
331 ReadRect(x,y,width,height);
332
333 m_xmlfile.Write(_T("\t\t<object class=\"wxButton\""));
334 WriteBasicInfo(x,y,width,height,varname);
335 WriteLabel(phrase);
336 m_xmlfile.Write(_T("\t\t</object>\n"));
337
338 }
339
340
341 bool rc2xml::Separator(int ch)
342 {
343 //if ((ch==' ')|(ch==',')|(ch==13)|(ch==10)|(ch=='|')|(ch=='\t'))
344 if ((ch==' ')|(ch==',')|(ch==13)|(ch==10)|(ch=='\t'))
345 return true;
346
347 if (ch==EOF)
348 {
349 m_done=true;
350 return true;
351 }
352
353 return false;
354 }
355
356 void rc2xml::ParseGroupBox(wxString phrase, wxString varname)
357 {
358 // GROUPBOX "Rotate",IDC_STATIC,1,1,71,79
359 wxString token;
360 token=PeekToken();
361 while (!token.IsNumber())
362 {
363 token=GetToken();
364 token=PeekToken();
365 }
366 int x,y,width,height;
367 ReadRect(x,y,width,height);
368
369 m_xmlfile.Write(_T("\t\t<object class=\"wxStaticBox\""));
370 WriteBasicInfo(x,y,width,height,varname);
371 WriteLabel(phrase);
372 m_xmlfile.Write(_T("\t\t</object>\n"));
373 }
374
375 bool rc2xml::ReadRect(int & x, int & y, int & width, int & height)
376 {
377 x=wxAtoi(GetToken());
378 y=wxAtoi(GetToken());
379 width=wxAtoi(GetToken());
380 bool ret;
381 wxString tmp = GetToken(&ret);
382 height=wxAtoi(tmp);
383 return ret; // check for more parameters
384 }
385
386 wxString rc2xml::GetToken(bool *listseparator)
387 {
388 wxString token=wxEmptyString;
389
390 if (m_rc.Eof())
391 {
392 m_done=true;
393 return token;
394 }
395
396 int ch=0;
397 ReadChar(ch);
398 if (ch==EOF)
399 {
400 m_done=true;
401 return token;
402 }
403
404 while (Separator(ch))
405 {
406 ReadChar(ch);
407 if (m_done)
408 return token;
409 }
410
411 if (ch==EOF)
412 {
413 m_done=true;
414 }
415
416
417 while (!Separator(ch))
418 {
419 token += (char)ch;
420 ReadChar(ch);
421 }
422
423 if (ch == EOF)
424 m_done = true;
425
426 if (listseparator)
427 *listseparator = (ch == ',');
428 return token;
429 }
430
431 wxString rc2xml::GetQuoteField()
432 {
433 wxString phrase;
434 //ASCII code 34 "
435 int ch=0;
436 int ch1=0;
437
438 ReadChar(ch);
439
440 // !! Changed by MS, 15th/11/04. Can now read strings such as
441 // """Catapult"" - blah blah", ...
442
443 while (ch!=34)
444 ReadChar(ch);
445
446 // found first '"'
447 while (true)
448 {
449 ReadChar(ch);
450 if (ch == 34)
451 {
452 // another quote?
453 ReadChar(ch1);
454 if (ch1 != 34)
455 {
456 // real end of string..
457 break;
458 }
459
460 // add a single quote - fall through
461 }
462 phrase+=(char)ch;
463 }
464
465 return phrase;
466 }
467
468 // string in stringtable may contain embedded quotes
469 // escape characters retained to allow strings to be rewritten
470 wxString rc2xml::GetStringQuote()
471 {
472 wxString phrase;
473 //ASCII code 34 "
474 bool done=false;
475 int ch=0,lastch=0;
476 ReadChar(ch);
477
478 while (ch!=34)
479 ReadChar(ch);
480
481 ReadChar(ch);
482 while (done==false)
483 {
484 if ((ch==34)&&(lastch!='\\'))
485 {
486 wxFileOffset p = m_rc.Tell();
487 ReadChar(ch);
488 // RC supports "", for embedded quote, as well as \"
489 if (ch==34)
490 phrase+='\\';
491 else
492 {
493 m_rc.Seek(p);
494 done = true;
495 }
496 }
497 if (done==true)
498 break;
499 if (ch=='\r')
500 ReadChar(ch); // skip
501 if ((ch=='\n')&&(lastch=='\\')) // lastch <should> be this
502 phrase+='n'; // escape
503 else
504 phrase+=(char)ch;
505
506 lastch=ch;
507 ReadChar(ch);
508 }
509
510 return phrase;
511 }
512
513 void rc2xml::ReadChar(int &ch)
514 {
515 wxFileOffset result = m_rc.Tell();
516
517 if((result>=m_filesize))
518 m_done=true;
519
520 result = m_rc.Read(&ch,1);
521
522 if( result == wxInvalidOffset )
523 m_done=true;
524
525 if(ch==EOF)
526 m_done=true;
527 }
528
529 void rc2xml::ParseComboBox(wxString varname)
530 {
531 /* COMBOBOX IDC_SCALECOMBO,10,110,48,52,CBS_DROPDOWNLIST | CBS_SORT |
532 WS_VSCROLL | WS_TABSTOP */
533 wxString token,style;
534 int x,y,width,height;
535 bool GotOrs;
536 GotOrs = ReadOrs(token);
537 if (ReadRect(x,y,width,height))
538 if (GotOrs==false)
539 ReadOrs(token);
540
541 m_xmlfile.Write(_T("\t\t<object class=\"wxComboBox\""));
542 WriteBasicInfo(x,y,width,height,varname);
543 if (token.Find(_T("CBS_SIMPLE")) != wxNOT_FOUND)
544 WriteStyle(_T("wxCB_SIMPLE"));
545 if (token.Find(_T("CBS_SORT")) != wxNOT_FOUND)
546 WriteStyle(_T("wxCB_SORT"));
547 if (token.Find(_T("CBS_DISABLENOSCROLL")) != wxNOT_FOUND)
548 WriteStyle(_T("wxLB_ALWAYS_SB"));
549 m_xmlfile.Write(_T("\n\t\t</object>\n"));
550
551 }
552
553 void rc2xml::ParseMenu(wxString varname)
554 {
555 wxString token=wxEmptyString;
556
557 //Write menubar to xml file
558 m_xmlfile.Write(_T("\t<object class=\"wxMenuBar\""));
559 //Avoid duplicate names this way
560 varname.Replace(_T("IDR_"),_T("MB_"));
561 WriteName(varname);
562 m_xmlfile.Write(_T(">\n"));
563
564 while ((token!=_T("BEGIN"))&(token!=_T("{")))
565 token=GetToken();
566
567 while ((token!=_T("END"))&(token!=_T("}")))
568 {
569 token=GetToken();
570 token.MakeUpper();
571
572 if (token==_T("POPUP"))
573 {
574 ParsePopupMenu();
575 }
576 }
577 m_xmlfile.Write(_T("\t</object>\n"));
578 }
579
580 void rc2xml::ParsePopupMenu()
581 {
582 static int menucount=0;
583 menucount++;
584 wxString token,name,msg,longhelp,tip;
585 token=GetQuoteField();
586
587 //Remove \t because it causes problems
588
589 //spot=token.First("\\t");
590 //token=token.Left(spot);
591
592 //Write Menu item
593 //Generate a fake name since RC menus don't have one
594 name << _T("Menu_") << menucount;
595 m_xmlfile.Write(_T("\t\t<object class=\"wxMenu\""));
596 WriteName(name);
597 m_xmlfile.Write(_T(">\n"));
598 WriteLabel(token);
599
600 while ((token!=_T("BEGIN"))&(token!=_T("{")))
601 token=GetToken();
602
603 while ((token!=_T("END"))&(token!=_T("}")))
604 {
605 token=GetToken();
606 token.MakeUpper();
607
608 if (token==_T("POPUP"))
609 ParsePopupMenu();
610
611 if (token==_T("MENUITEM"))
612 ParseMenuItem();
613 }
614 m_xmlfile.Write(_T("\t\t\t</object>\n"));
615 }
616
617 wxString rc2xml::PeekToken()
618 {
619 wxFileOffset p = m_rc.Tell();
620 wxString token=GetToken();
621
622 m_rc.Seek(p);
623 return token;
624 }
625
626 //MS Windows pain in the butt CONTROL
627 void rc2xml::ParseControlMS()
628 {
629 wxString token = PeekToken();
630
631 if (token.Contains(_T("\"")))
632 ParseNormalMSControl();
633 else
634 ParseWeirdMSControl();
635 }
636
637 /* CONTROL "Slider1",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH |
638 TBS_NOTICKS | WS_TABSTOP,52,73,100,15
639 */
640
641 void rc2xml::ParseSlider(wxString WXUNUSED(label), wxString varname)
642 {
643 wxString token,style;
644 ReadOrs(token);
645 if (token.Find(_T("TBS_VERT"))!=wxNOT_FOUND)
646 style+=_T("wxSL_VERTICAL");
647 //MFC RC Default is horizontal
648 else
649 style+=_T("wxSL_HORIZONTAL");
650
651 int x,y,width,height;
652 ReadRect(x,y,width,height);
653 m_xmlfile.Write(_T("\t\t<object class=\"wxSlider\""));
654 WriteBasicInfo(x,y,width,height,varname);
655 WriteStyle(style);
656 m_xmlfile.Write(_T("\n\t\t</object>\n"));
657
658 }
659 /*
660 CONTROL "Progress1",CG_IDC_PROGDLG_PROGRESS,"msctls_progress32",
661 WS_BORDER,15,52,154,13
662 */
663 void rc2xml::ParseProgressBar(wxString WXUNUSED(label), wxString varname)
664 {
665 wxString token,style;
666 ReadOrs(token);
667
668 int x,y,width,height;
669 ReadRect(x,y,width,height);
670
671 //Always horizontal in MFC
672 m_xmlfile.Write(_T("\t\t<object class=\"wxGauge\""));
673 WriteBasicInfo(x,y,width,height,varname);
674 WriteStyle(style);
675 m_xmlfile.Write(_T("\t\t</object>\n"));
676 }
677
678 bool rc2xml::ReadOrs(wxString & orstring)
679 {
680 wxString token;
681
682 token=PeekToken();
683 if (token.IsNumber())
684 return false;
685 orstring=GetToken();
686
687 while(PeekToken()==_T("|"))
688 {
689 //Grab |
690 orstring+=GetToken();
691 //Grab next token
692 orstring+=GetToken();
693 }
694 return true;
695 }
696
697 //Is it a checkbutton or a radiobutton or a pushbutton or a groupbox
698 void rc2xml::ParseCtrlButton(wxString label, wxString varname)
699 {
700 wxString token;
701 wxFileOffset p = m_rc.Tell();
702 ReadOrs(token);
703 m_rc.Seek(p);
704
705 if (token.Find(_T("BS_AUTOCHECKBOX"))!=wxNOT_FOUND)
706 ParseCheckBox(label, varname);
707 else if ((token.Find(_T("BS_AUTORADIOBUTTON"))!=wxNOT_FOUND)||
708 (token.Find(_T("BS_RADIOBUTTON"))!=wxNOT_FOUND))
709 ParseRadioButton(label, varname);
710 else if (token.Find(_T("BS_GROUPBOX"))!=wxNOT_FOUND)
711 ParseGroupBox(label, varname);
712 else // if ((token.Find("BS_PUSHBUTTON")!=wxNOT_FOUND)||
713 // (token.Find("BS_DEFPUSHBUTTON")!=wxNOT_FOUND))
714 ParsePushButton(label, varname); // make default case
715 }
716
717 void rc2xml::WriteSize(int width, int height)
718 {
719 wxString msg;
720 msg << _T(" <size>") << width << _T(",") << height << _T("d</size>");
721 m_xmlfile.Write(msg);
722 }
723
724 void rc2xml::WritePosition(int x, int y)
725 {
726 wxString msg;
727 msg << _T(" <pos>") << x << _T(",") << y << _T("d</pos>");
728 m_xmlfile.Write(msg);
729 }
730
731 void rc2xml::WriteTitle(wxString title)
732 {
733 wxString msg;
734 msg=_T("\t\t<title>")+title+_T("</title>\n");
735 m_xmlfile.Write(msg);
736 }
737
738 void rc2xml::WriteName(wxString name)
739 {
740
741 //Try to convert any number ids into names
742 name=LookUpId(name);
743 //Replace common MS ids with wxWidgets ids
744 //I didn't do everyone of them
745 if (name==_T("IDOK"))
746 name=_T("wxID_OK");
747 else if (name==_T("IDCANCEL"))
748 name=_T("wxID_CANCEL");
749 else if (name==_T("IDAPPLY"))
750 name=_T("wxID_APPLY");
751 else if (name==_T("ID_FILE_OPEN"))
752 name=_T("wxID_OPEN");
753 else if (name==_T("ID_FILE_CLOSE"))
754 name=_T("wxID_CLOSE");
755 else if (name==_T("ID_FILE_SAVE"))
756 name=_T("wxID_SAVE");
757 else if (name==_T("ID_FILE_SAVE_AS"))
758 name=_T("wxID_SAVEAS");
759 else if (name==_T("ID_APP_EXIT"))
760 name=_T("wxID_EXIT");
761 else if (name==_T("ID_FILE_PRINT"))
762 name=_T("wxID_PRINT");
763 else if (name==_T("ID_FILE_PRINT_PREVIEW"))
764 name=_T("wxID_PREVIEW");
765 else if (name==_T("ID_FILE_PRINT_SETUP"))
766 name=_T("wxID_PRINT_SETUP");
767 else if (name==_T("ID_APP_ABOUT"))
768 name=_T("wxID_ABOUT");
769 else if (name==_T("ID_EDIT_UNDO"))
770 name=_T("wxID_UNDO");
771 else if (name==_T("ID_EDIT_CUT"))
772 name=_T("wxID_CUT");
773 else if (name==_T("ID_EDIT_COPY"))
774 name=_T("wxID_COPY");
775 else if (name==_T("ID_EDIT_PASTE"))
776 name=_T("wxID_PASTE");
777 else if (name==_T("IDYES"))
778 name=_T("wxID_YES");
779 else if (name==_T("IDNO"))
780 name=_T("wxID_NO");
781 else if (name==_T("IDHELP"))
782 name=_T("wxID_HELP");
783
784 m_xmlfile.Write(_T(" name= \"")+name+_T("\""));
785 }
786
787 void rc2xml::WriteLabel(wxString label)
788 {
789 label.Replace(_T("&"),_T("$"));
790 // changes by MS, handle '<' '>' characters within a label.
791 label.Replace(_T("<"),_T("&lt;"));
792 label.Replace(_T(">"),_T("&gt;"));
793 m_xmlfile.Write(_T("\t\t\t<label>")+label+_T("</label>\n"));
794 }
795
796 void rc2xml::WriteBasicInfo(int x, int y, int width, int height, wxString name)
797 {
798 WriteName(name);
799 m_xmlfile.Write(_T(">\n"));
800 m_xmlfile.Write(_T("\t\t\t"));
801 WritePosition(x,y);
802 WriteSize(width,height);
803 m_xmlfile.Write(_T("\n"));
804 }
805
806 void rc2xml::WriteStyle(wxString style)
807 {
808 if (style.Length()==0)
809 return;
810 m_xmlfile.Write(_T("\t\t\t<style>")+style+_T("</style>\n"));
811 }
812 /*
813 LISTBOX IDC_LIST1,16,89,48,40,LBS_SORT | LBS_MULTIPLESEL |
814 LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
815 */
816 void rc2xml::ParseListBox(wxString varname)
817 {
818 wxString token;
819 token=PeekToken();
820 while (!token.IsNumber())
821 {
822 token=GetToken();
823 token=PeekToken();
824 }
825 int x,y,width,height;
826 ReadRect(x,y,width,height);
827
828 m_xmlfile.Write(_T("\t\t<object class=\"wxListBox\""));
829 WriteBasicInfo(x,y,width,height,varname);
830 m_xmlfile.Write(_T("\n\t\t</object>\n"));
831
832 }
833 /*
834 CONTROL "",IDC_RICHEDIT1,"RICHEDIT",ES_AUTOHSCROLL | WS_BORDER |
835 WS_TABSTOP,103,110,40,14
836 */
837 void rc2xml::ParseRichEdit(wxString WXUNUSED(label), wxString varname)
838 {
839 wxString token;
840 //while (ReadOrs(token));
841 ReadOrs(token);
842 int x,y,width,height;
843 ReadRect(x,y,width,height);
844 wxString style;
845 //Make it a rich text control
846 style+=_T("wxTE_MULTILINE ");
847 m_xmlfile.Write(_T("\t\t<object class=\"wxTextCtrl\""));
848 WriteBasicInfo(x,y,width,height,varname);
849 WriteStyle(style);
850 m_xmlfile.Write(_T("\t\t</object>\n"));
851
852 }
853 /*
854 CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS,209,72,
855 19,26
856 */
857 void rc2xml::ParseSpinCtrl(wxString WXUNUSED(label), wxString varname)
858 {
859 wxString token,style;
860
861 ReadOrs(token);
862 if (token.Find(_T("UDS_HORZ"))!=wxNOT_FOUND)
863 style=_T("wxSP_HORIZONTAL");
864 //MFC default
865 else
866 style=_T("wxSP_VERTICAL");
867
868 int x,y,width,height;
869 ReadRect(x,y,width,height);
870 m_xmlfile.Write(_T("\t\t<object class=\"wxSpinButton\""));
871 WriteBasicInfo(x,y,width,height,varname);
872 WriteStyle(style);
873 m_xmlfile.Write(_T("\n\t\t</object>\n"));
874
875 }
876
877 void rc2xml::FirstPass()
878 {
879 wxString token,prevtok;
880 while (!m_done)
881 {
882 token=GetToken();
883 if (token==_T("BITMAP"))
884 ParseBitmap(prevtok);
885 else if (token==_T("STRINGTABLE"))
886 ParseStringTable(prevtok);
887 else if (token==_T("ICON"))
888 ParseIcon(prevtok);
889
890 prevtok=token;
891 }
892 }
893
894 void rc2xml::ParseBitmap(wxString varname)
895 {
896 wxString token;
897 wxString *bitmapfile;
898
899 token=PeekToken();
900 //Microsoft notation?
901 if (token==_T("DISCARDABLE"))
902 {
903 token=GetToken();
904 token=PeekToken();
905 }
906 bitmapfile=new wxString;
907 *bitmapfile=GetQuoteField();
908 m_bitmaplist->Append(varname,bitmapfile);
909
910 }
911
912
913 void rc2xml::SecondPass()
914 {
915 wxString token,prevtok;
916 while (!m_done)
917 {
918 token=GetToken();
919 if ((token==_T("DIALOG"))||(token==_T("DIALOGEX")))
920 ParseDialog(prevtok);
921 else if (token==_T("MENU"))
922 ParseMenu(prevtok);
923 else if (token==_T("TOOLBAR"))
924 ParseToolBar(prevtok);
925
926 prevtok=token;
927 }
928
929 }
930
931 void rc2xml::ParseToolBar(wxString varname)
932 {
933 wxString token;
934 token=GetToken();
935 wxASSERT_MSG(token==_T("DISCARDABLE"),_T("Error in toolbar parsing"));
936 //Look up bitmap for toolbar and load
937 wxNode *node=m_bitmaplist->Find(LookUpId(varname));
938 wxString *bitmappath;
939 bitmappath=(wxString *)node->GetData();
940 wxBitmap bitmap;
941 if (!bitmap.LoadFile(*bitmappath,wxBITMAP_TYPE_BMP ))
942 wxLogError(_T("Unable to load bitmap:")+*bitmappath);
943
944 //Write toolbar to xml file
945 m_xmlfile.Write(_T("\t<object class=\"wxToolBar\""));
946 //Avoid duplicate names this way
947 varname.Replace(_T("IDR_"),_T("TB_"));
948 WriteName(varname);
949 m_xmlfile.Write(_T(">\n"));
950 wxString style;
951 style+=_T("wxTB_FLAT");
952 WriteStyle(style);
953
954
955 //Grab width and height
956 int width,height;
957 width=wxAtoi(GetToken());
958 height=wxAtoi(GetToken());
959
960 int c=0;
961 wxString buttonname,msg,tip,longhelp;
962 token=GetToken();
963 while ((token!=_T("BEGIN"))&(token!=_T("{")))
964 token=GetToken();
965
966 while ((token!=_T("END"))&(token!=_T("}")))
967 {
968 if (token==_T("BUTTON"))
969 {
970 buttonname=GetToken();
971 m_xmlfile.Write(_T("\t\t\t<object class=\"tool\""));
972 WriteName(buttonname);
973 m_xmlfile.Write(_T(">\n"));
974 //Write tool tip if any
975 if (LookUpString(buttonname,msg))
976 {
977 SplitHelp(msg,tip,longhelp);
978 m_xmlfile.Write(_T("\t\t\t\t<tooltip>")+tip+_T("</tooltip>\n"));
979 m_xmlfile.Write(_T("\t\t<longhelp>")+longhelp+_T("</longhelp>\n"));
980 }
981 //Make a bitmap file name
982 buttonname=CleanName(buttonname);
983 buttonname+=_T(".bmp");
984 m_xmlfile.Write(_T("\t\t\t\t<bitmap>")+buttonname+_T("</bitmap>\n"));
985 WriteToolButton(buttonname,c,width,height,bitmap);
986 m_xmlfile.Write(_T("\t\t\t</object>\n"));
987 c++;
988 }
989 else if (token==_T("SEPARATOR"))
990 {
991 m_xmlfile.Write(_T("\t\t\t<object class=\"separator\"/>\n"));
992 }
993 token=GetToken();
994 }
995 m_xmlfile.Write(_T("\t</object>\n"));
996 }
997
998 //Extract bitmaps from larger toolbar bitmap
999 void rc2xml::WriteToolButton(wxString name,int index, int width, int height, wxBitmap bitmap)
1000 {
1001 int x;
1002 x=index*width;
1003 wxRect r(x,0,width,height);
1004 wxBitmap little;
1005 little=bitmap.GetSubBitmap(r);
1006 little.SaveFile(m_targetpath+name,wxBITMAP_TYPE_BMP);
1007 }
1008
1009 void rc2xml::ParseStringTable(wxString WXUNUSED(varname))
1010 {
1011 wxString token;
1012 token=GetToken();
1013 while ((token!=_T("BEGIN"))&(token!=_T("{")))
1014 token=GetToken();
1015 token=GetToken();
1016 wxString *msg;
1017
1018 while ((token!=_T("END"))&(token!=_T("}")))
1019 {
1020 msg=new wxString;
1021 *msg=GetStringQuote();
1022 m_stringtable->Append(token,msg);
1023 token=GetToken();
1024 }
1025 }
1026
1027 bool rc2xml::LookUpString(wxString strid,wxString & st)
1028 {
1029 wxNode *node=m_stringtable->Find(strid);
1030 wxString *s;
1031 if (node==NULL)
1032 return false;
1033
1034 s=(wxString *)node->GetData();
1035 st=*s;
1036
1037 return true;
1038 }
1039
1040 bool rc2xml::SplitHelp(wxString msg, wxString &shorthelp, wxString &longhelp)
1041 {
1042 int spot;
1043 spot=msg.Find(_T("\\n"));
1044 if (spot==wxNOT_FOUND)
1045 {
1046 shorthelp=msg;
1047 longhelp=msg;
1048 }
1049
1050 longhelp=msg.Left(spot);
1051 spot=msg.Length()-spot-2;
1052 shorthelp=msg.Right(spot);
1053 return true;
1054 }
1055
1056 void rc2xml::ParseMenuItem()
1057 {
1058 wxString token,name,msg,tip,longhelp;
1059 //int spot;
1060 if (PeekToken()==_T("SEPARATOR"))
1061 {
1062 m_xmlfile.Write(_T("\t\t\t<object class=\"separator\"/>\n"));
1063 return;
1064 }
1065
1066 token=GetQuoteField();
1067 name=GetToken();
1068 //Remove \t because it causes problems
1069 //spot=token.First("\\t");
1070 //token=token.Left(spot);
1071 m_xmlfile.Write(_T("\t\t\t<object class=\"wxMenuItem\""));
1072 WriteName(name);
1073 m_xmlfile.Write(_T(">\n"));
1074 WriteLabel(token);
1075 //Look up help if any listed in stringtable
1076 //can't assume numbers correlate, restrict to string identifiers
1077 if ((!name.IsNumber())&&(LookUpString(name,msg)))
1078 {
1079 SplitHelp(msg,tip,longhelp);
1080 m_xmlfile.Write(_T("\t\t\t<help>")
1081 +longhelp+_T("</help>\n"));
1082 }
1083 //look for extra attributes like checked and break
1084 wxString ptoken;
1085 ptoken=PeekToken();
1086 ptoken.MakeUpper();
1087 while ((ptoken!=_T("MENUITEM"))&(ptoken!=_T("POPUP"))&(ptoken!=_T("END")))
1088 {
1089 token=GetToken();
1090 ptoken.MakeUpper();
1091 if (token==_T("CHECKED"))
1092 m_xmlfile.Write(_T("\t\t\t<checkable>1</checkable>\n"));
1093 else if (token==_T("MENUBREAK"))
1094 ;
1095 //m_xmlfile.Write("\t\t\t</break>\n");
1096 else if (token==_T("GRAYED"))
1097 ;
1098 else
1099 wxLogError(_T("Unknown Menu Item token:")+token);
1100
1101 ptoken=PeekToken();
1102 ptoken.MakeUpper();
1103 }
1104 m_xmlfile.Write(_T("\t\t\t</object>\n"));
1105
1106 }
1107
1108 //ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20
1109 void rc2xml::ParseIconStatic()
1110 {
1111 wxString token;
1112 wxString varname,iconname;
1113 token = PeekToken();
1114 if (token.Contains(_T("\"")))
1115 iconname = GetQuoteField();
1116 else
1117 iconname=GetToken();
1118 //Look up icon
1119 varname=GetToken();
1120
1121 int x,y,width,height;
1122 ReadRect(x,y,width,height);
1123
1124 m_xmlfile.Write(_T("\t\t<object class=\"wxStaticBitmap\""));
1125 WriteBasicInfo(x,y,width,height,varname);
1126 //Save icon as a bitmap
1127 WriteIcon(iconname);
1128 m_xmlfile.Write(_T("\t\t</object>\n"));
1129
1130 }
1131 //IDR_MAINFRAME ICON DISCARDABLE "res\\mfcexample.ico"
1132 void rc2xml::ParseIcon(wxString varname)
1133 {
1134 wxString token;
1135 wxString *iconfile;
1136 iconfile=new wxString;
1137 token=PeekToken();
1138
1139 *iconfile=GetQuoteField();
1140 m_iconlist->Append(varname,iconfile);
1141
1142
1143 }
1144
1145 wxString rc2xml::CleanName(wxString name)
1146 {
1147 name.MakeLower();
1148 name.Replace(_T("id_"),wxEmptyString);
1149 name.Replace(_T("idr_"),wxEmptyString);
1150 name.Replace(_T("idb_"),wxEmptyString);
1151 name.Replace(_T("idc_"),wxEmptyString);
1152
1153 name.Replace(_T(".ico"),wxEmptyString);
1154
1155 name.Replace(_T(".bmp"),wxEmptyString);
1156 return name;
1157 }
1158 // And the award for most messed up control goes to...
1159 // CONTROL IDB_FACE,IDC_STATIC,"Static",SS_BITMAP,26,62,32,30
1160 void rc2xml::ParseStaticBitmap(wxString bitmapname, wxString varname)
1161 {
1162 wxString token;
1163 //Grab SS_BITMAP
1164 ReadOrs(token);
1165
1166
1167 int x,y,width,height;
1168 ReadRect(x,y,width,height);
1169
1170 m_xmlfile.Write(_T("\t\t<object class=\"wxStaticBitmap\""));
1171 WriteBasicInfo(x,y,width,height,varname);
1172 WriteBitmap(bitmapname);
1173 m_xmlfile.Write(_T("\t\t</object>\n"));
1174
1175 }
1176
1177 void rc2xml::ParseNormalMSControl()
1178 {
1179 wxString label=GetQuoteField();
1180 wxString varname=GetToken();
1181 wxString kindctrl=GetQuoteField();
1182 kindctrl.MakeUpper();
1183
1184 if (kindctrl==_T("MSCTLS_UPDOWN32"))
1185 ParseSpinCtrl(label,varname);
1186 else if (kindctrl==_T("MSCTLS_TRACKBAR32"))
1187 ParseSlider(label,varname);
1188 else if (kindctrl==_T("MSCTLS_PROGRESS32"))
1189 ParseProgressBar(label,varname);
1190 else if (kindctrl==_T("SYSTREEVIEW32"))
1191 ParseTreeCtrl(label,varname);
1192 else if (kindctrl==_T("SYSMONTHCAL32"))
1193 ParseCalendar(label,varname);
1194 else if (kindctrl==_T("SYSLISTVIEW32"))
1195 ParseListCtrl(label,varname);
1196 else if (kindctrl==_T("BUTTON"))
1197 ParseCtrlButton(label,varname);
1198 else if (kindctrl==_T("RICHEDIT"))
1199 ParseRichEdit(label,varname);
1200 else if (kindctrl==_T("STATIC"))
1201 {
1202 wxString token;
1203 wxFileOffset p = m_rc.Tell();
1204 ReadOrs(token);
1205 m_rc.Seek(p);
1206 if (token.Find(_T("SS_BITMAP"))!=wxNOT_FOUND)
1207 ParseStaticBitmap(label,varname);
1208 else
1209 ParseStaticText(label,varname);
1210 }
1211 else if (kindctrl==_T("EDIT"))
1212 ParseTextCtrl(varname);
1213 else if (kindctrl==_T("LISTBOX"))
1214 ParseListBox(varname);
1215 else if (kindctrl==_T("COMBOBOX"))
1216 ParseComboBox(varname);
1217 }
1218
1219 void rc2xml::ParseWeirdMSControl()
1220 {
1221 wxString id = GetToken();
1222 wxString varname = GetToken();
1223 wxString kindctrl = GetQuoteField();
1224 kindctrl.MakeUpper();
1225 // CONTROL IDB_FACE,IDC_STATIC,"Static",SS_BITMAP,26,62,32,30
1226 if (kindctrl==_T("STATIC"))
1227 {
1228 if (PeekToken()==_T("SS_BITMAP"))
1229 ParseStaticBitmap(id,varname);
1230 else
1231 wxLogError(_T("Unknown MS Control Static token"));
1232 }
1233 }
1234
1235 //SCROLLBAR IDC_SCROLLBAR1,219,56,10,40,SBS_VERT
1236 void rc2xml::ParseScrollBar()
1237 {
1238 wxString token;
1239 wxString varname;
1240
1241 varname=GetToken();
1242 int x,y,width,height;
1243 ReadRect(x,y,width,height);
1244 wxString style;
1245
1246 ReadOrs(token);
1247
1248 if (token.Find(_T("SBS_VERT"))!=wxNOT_FOUND)
1249 style=_T("wxSB_VERTICAL");
1250 //Default MFC style is horizontal
1251 else
1252 style=_T("wxSB_HORIZONTAL");
1253
1254 m_xmlfile.Write(_T("\t\t<object class=\"wxScrollBar\""));
1255 WriteBasicInfo(x,y,width,height,varname);
1256 WriteStyle(style);
1257 m_xmlfile.Write(_T("\n\t\t</object>\n"));
1258
1259 }
1260 // CONTROL "Tree1",IDC_TREE1,"SysTreeView32",WS_BORDER | WS_TABSTOP,
1261 // 7,7,66,61
1262
1263 void rc2xml::ParseTreeCtrl(wxString WXUNUSED(label), wxString varname)
1264 {
1265 wxString token;
1266 //while (ReadOrs(token));
1267 ReadOrs(token);
1268 int x,y,width,height;
1269 ReadRect(x,y,width,height);
1270 m_xmlfile.Write(_T("\t\t<object class=\"wxTreeCtrl\""));
1271 WriteBasicInfo(x,y,width,height,varname);
1272 m_xmlfile.Write(_T("\t\t</object>\n"));
1273
1274 }
1275 // CONTROL "MonthCalendar1",IDC_MONTHCALENDAR1,"SysMonthCal32",
1276 //MCS_NOTODAY | WS_TABSTOP,105,71,129,89
1277
1278 void rc2xml::ParseCalendar(wxString WXUNUSED(label), wxString varname)
1279 {
1280 wxString token;
1281 //while (ReadOrs(token));
1282 ReadOrs(token);
1283 int x,y,width,height;
1284 ReadRect(x,y,width,height);
1285 m_xmlfile.Write(_T("\t\t<object class=\"wxCalendarCtrl\""));
1286 WriteBasicInfo(x,y,width,height,varname);
1287 m_xmlfile.Write(_T("\t\t</object>\n"));
1288 }
1289 // CONTROL "List1",IDC_LIST1,"SysListView32",WS_BORDER | WS_TABSTOP,
1290 // 7,89,68,71
1291
1292 void rc2xml::ParseListCtrl(wxString WXUNUSED(label), wxString varname)
1293 {
1294 wxString token;
1295 //while (ReadOrs(token));
1296 ReadOrs(token);
1297 int x,y,width,height;
1298 ReadRect(x,y,width,height);
1299 m_xmlfile.Write(_T("\t\t<object class=\"wxListCtrl\""));
1300 WriteBasicInfo(x,y,width,height,varname);
1301 m_xmlfile.Write(_T("\t\t</object>\n"));
1302
1303 }
1304
1305 void rc2xml::WriteBitmap(wxString bitmapname)
1306 {
1307 //Look up bitmap
1308 wxNode *node=m_bitmaplist->Find(LookUpId(bitmapname));
1309 if (node==NULL)
1310 {
1311 m_xmlfile.Write(_T("\t\t\t<bitmap>missingfile</bitmap>\n"));
1312 wxLogError(_T("Unable to find bitmap:")+bitmapname);
1313 return;
1314 }
1315
1316 wxString *bitmappath;
1317 bitmappath=(wxString *)node->GetData();
1318
1319 bitmapname=wxFileNameFromPath(*bitmappath);
1320 wxBitmap bitmap;
1321 if (!bitmap.LoadFile(*bitmappath,wxBITMAP_TYPE_BMP ))
1322 wxLogError(_T("Unable to load bitmap:")+*bitmappath);
1323
1324 //Make a bitmap file name
1325 bitmapname=CleanName(bitmapname);
1326 bitmapname+=_T(".bmp");
1327 m_xmlfile.Write(_T("\t\t\t<bitmap>")+bitmapname+_T("</bitmap>\n"));
1328 bitmap.SaveFile(m_targetpath+bitmapname,wxBITMAP_TYPE_BMP);
1329 }
1330
1331 void rc2xml::WriteIcon(wxString iconname)
1332 {
1333 wxNode *node=m_iconlist->Find(iconname);
1334 if (node==NULL)
1335 {
1336 m_xmlfile.Write(_T("\t\t\t<bitmap>missing_file</bitmap>\n"));
1337 wxLogError(_T("Unable to find icon:")+iconname);
1338 }
1339 wxString *iconpath;
1340 iconpath=(wxString *)node->GetData();
1341 wxIcon icon;
1342 wxBitmap bitmap;
1343 if (!icon.LoadFile(*iconpath,wxBITMAP_TYPE_ICO ))
1344 wxLogError(_T("Unable to load icon:")+*iconpath);
1345 #ifdef __WXMSW__
1346 bitmap.CopyFromIcon(icon);
1347 #else
1348 bitmap = icon;
1349 #endif
1350 iconname=wxFileNameFromPath(*iconpath);
1351 //Make a bitmap file name
1352 iconname=CleanName(iconname);
1353 iconname+=_T(".bmp");
1354 m_xmlfile.Write(_T("\t\t\t<bitmap>")+iconname+_T("</bitmap>\n"));
1355 bitmap.SaveFile(m_targetpath+iconname,wxBITMAP_TYPE_BMP);
1356
1357
1358 }
1359 /*Unfortunately sometimes the great MSVC Resource editor decides
1360 to use numbers instead of the word id. I have no idea why they
1361 do this, but that is the way it is.
1362 */
1363 /* this is a quick and dirty way to parse the resource.h file
1364 it will not recognize #ifdef so it can be easily fooled
1365 */
1366 void rc2xml::ParseResourceHeader()
1367 {
1368 wxTextFile r;
1369 //Attempt to load resource.h in current path
1370 if (!r.Open(_T("resource.h")))
1371 {
1372 wxLogError(_T("Warining Unable to load resource.h file"));
1373 return;
1374 }
1375
1376 wxString str;
1377 wxString id,v;
1378 wxStringTokenizer tok;
1379 wxString *varname;
1380
1381
1382 long n;
1383
1384 //Read through entire file
1385 for ( str = r.GetFirstLine(); !r.Eof(); str = r.GetNextLine() )
1386 {
1387 if (str.Find(_T("#define"))!=wxNOT_FOUND)
1388 {
1389 tok.SetString(str);
1390 //Just ignore #define token
1391 tok.GetNextToken();
1392 v=tok.GetNextToken();
1393 id=tok.GetNextToken();
1394 if (id.IsNumber())
1395 {
1396 varname=new wxString;
1397 id.ToLong(&n);
1398 *varname=v;
1399 m_resourcelist->Append(n,varname);
1400 }
1401 }
1402 }
1403
1404
1405
1406 }
1407
1408
1409 wxString rc2xml::LookUpId(wxString id)
1410 {
1411 wxString st;
1412
1413 if (!id.IsNumber())
1414 return id;
1415 long n;
1416 id.ToLong(&n);
1417 wxNode *node=m_resourcelist->Find(n);
1418 wxString *s;
1419 if (node==NULL)
1420 return id;
1421
1422 s=(wxString *)node->GetData();
1423 st=*s;
1424 return st;
1425 }