home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / contrib / utils / wxrc / wxrc.cpp < prev    next >
C/C++ Source or Header  |  2002-09-08  |  17KB  |  623 lines

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