home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / contrib / utils / wxrc / wxrc.cpp < prev    next >
C/C++ Source or Header  |  2002-11-14  |  18KB  |  642 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.2.5 2002/11/11 21:46:16 VS 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, _T("h"), _T("help"),  _T("show help message"), 
  88.               wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
  89.         { wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose") },
  90.         { wxCMD_LINE_SWITCH, _T("c"), _T("cpp-code"),  _T("output C++ source rather than .rsc file") },
  91.         { wxCMD_LINE_SWITCH, _T("p"), _T("python-code"),  _T("output wxPython source rather than .rsc file") },
  92.         { wxCMD_LINE_SWITCH, _T("g"), _T("gettext"),  _T("output list of translatable strings (to stdout or file if -o used)") },
  93.         { wxCMD_LINE_OPTION, _T("n"), _T("function"),  _T("C++/Python function name (with -c or -p) [InitXmlResource]") },
  94.         { wxCMD_LINE_OPTION, _T("o"), _T("output"),  _T("output file [resource.xrs/cpp]") },
  95. #if 0 // not yet implemented
  96.         { wxCMD_LINE_OPTION, _T("l"), _T("list-of-handlers",  _T("output list of neccessary handlers to this file" },
  97. #endif
  98.         { wxCMD_LINE_PARAM,  NULL, NULL, _T("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(_T("g"));
  143.     flagVerbose = cmdline.Found(_T("v"));
  144.     flagCPP = cmdline.Found(_T("c"));
  145.     flagPython = cmdline.Found(_T("p"));
  146.  
  147.     if (!cmdline.Found(_T("o"), &parOutput)) 
  148.     {
  149.         if (flagGettext)
  150.             parOutput = wxEmptyString;
  151.         else
  152.         {
  153.             if (flagCPP)
  154.                 parOutput = _T("resource.cpp");
  155.             else if (flagPython)
  156.                 parOutput = _T("resource.py");
  157.             else
  158.                 parOutput = _T("resource.xrs");
  159.         }
  160.     }
  161.     parOutputPath = wxPathOnly(parOutput);
  162.     if (!parOutputPath) parOutputPath = _T(".");
  163.  
  164.     if (!cmdline.Found(_T("n"), &parFuncname)) 
  165.         parFuncname = _T("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(_T(":"), _T("_"));
  198.     name2.Replace(_T("/"), _T("_"));
  199.     name2.Replace(_T("\\"), _T("_"));
  200.     name2.Replace(_T("*"), _T("_"));
  201.     name2.Replace(_T("?"), _T("_"));
  202.     
  203.     wxString s = wxFileNameFromPath(parOutput) + _T("$") + name2;
  204.  
  205.     if (wxFileExists(s) && flist.Index(s) == wxNOT_FOUND)
  206.     {        
  207.         for (int i = 0;; i++)
  208.         {
  209.             s.Printf(wxFileNameFromPath(parOutput) + _T("$%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(_T("processing ") + parFiles[i] +  _T("...\n"));
  225.  
  226.         wxXmlDocument doc;
  227.         
  228.         if (!doc.Load(parFiles[i]))
  229.         {
  230.             wxLogError(_T("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 + _T("/") + 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.     // Is 'node' XML node element?
  255.     if (node == NULL) return;
  256.     if (node->GetType() != wxXML_ELEMENT_NODE) return;
  257.  
  258.     // Does 'node' contain filename information at all?
  259.     bool containsFilename = (
  260.         // Any bitmaps:
  261.         (node->GetName() == _T("bitmap")) ||
  262.         // URLs in wxHtmlWindow:
  263.         (node->GetName() == _T("url")) ||
  264.         // wxBitmapButton:
  265.         (node->GetParent() != NULL && 
  266.          node->GetParent()->GetPropVal(_T("class"), _T("")) == _T("wxBitmapButton") &&
  267.            (node->GetName() == _T("focus") || 
  268.             node->GetName() == _T("disabled") ||
  269.             node->GetName() == _T("selected")))
  270.         );
  271.  
  272.     wxXmlNode *n = node->GetChildren();
  273.     while (n)
  274.     {
  275.         if (containsFilename &&
  276.             (n->GetType() == wxXML_TEXT_NODE || 
  277.              n->GetType() == wxXML_CDATA_SECTION_NODE))
  278.         {
  279.             wxString fullname;
  280.             if (wxIsAbsolutePath(n->GetContent()) || inputPath.empty())
  281.                 fullname = n->GetContent();
  282.             else
  283.                 fullname = inputPath + _T("/") + n->GetContent();
  284.  
  285.             if (flagVerbose) 
  286.                 wxPrintf(_T("adding     ") + fullname +  _T("...\n"));
  287.  
  288.             wxString filename = GetInternalFileName(n->GetContent(), flist);
  289.             n->SetContent(filename);
  290.  
  291.             if (flist.Index(filename) == wxNOT_FOUND)
  292.                 flist.Add(filename);
  293.  
  294.             wxFileInputStream sin(fullname);
  295.             wxFileOutputStream sout(parOutputPath + _T("/") + filename);
  296.             sin.Read(sout); // copy the stream
  297.         }
  298.  
  299.         // subnodes:
  300.         if (n->GetType() == wxXML_ELEMENT_NODE)
  301.             FindFilesInXML(n, flist, inputPath);
  302.  
  303.         n = n->GetNext();
  304.     }
  305. }
  306.  
  307.  
  308.  
  309. void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
  310. {
  311.     for (size_t i = 0; i < flist.Count(); i++)
  312.         wxRemoveFile(parOutputPath + _T("/") + flist[i]);
  313. }
  314.  
  315.  
  316.  
  317. void XmlResApp::MakePackageZIP(const wxArrayString& flist)
  318. {
  319.     wxString files;
  320.     
  321.     for (size_t i = 0; i < flist.Count(); i++)
  322.         files += flist[i] + _T(" ");
  323.     files.RemoveLast();
  324.     
  325.     if (flagVerbose) 
  326.         wxPrintf(_T("compressing ") + parOutput +  _T("...\n"));
  327.  
  328.     if (wxExecute(_T("zip -9 -j ") + wxString(flagVerbose ? _T("") : _T("-q ")) + 
  329.                   parOutput + _T(" ") + files, TRUE) == -1)
  330.     {
  331.         wxLogError(_T("Unable to execute zip program. Make sure it is in the path."));
  332.         wxLogError(_T("You can download it at http://www.cdrom.com/pub/infozip/"));
  333.         retCode = 1;
  334.         return;
  335.     }
  336. }
  337.  
  338.  
  339.  
  340.  
  341. static wxString FileToCppArray(wxString filename, int num)
  342. {
  343.     wxString output;
  344.     wxString tmp;
  345.     wxString snum;
  346.     wxFFile file(filename, "rb");
  347.     size_t lng = file.Length();
  348.     
  349.     snum.Printf(_T("%i"), num);
  350.     output.Printf(_T("static size_t xml_res_size_") + snum + _T(" = %i;\n"), lng);
  351.     output += _T("static unsigned char xml_res_file_") + snum + _T("[] = {\n");
  352.     // we cannot use string literals because MSVC is dumb wannabe compiler
  353.     // with arbitrary limitation to 2048 strings :(
  354.     
  355.     unsigned char *buffer = new unsigned char[lng];
  356.     file.Read(buffer, lng);
  357.     
  358.     for (size_t i = 0, linelng = 0; i < lng; i++)
  359.     {
  360.         tmp.Printf(_T("%i"), buffer[i]);
  361.         if (i != 0) output << _T(',');
  362.         if (linelng > 70)
  363.         {
  364.             linelng = 0;
  365.             output << _T("\n");
  366.         }
  367.         output << tmp;
  368.         linelng += tmp.Length()+1;
  369.     }
  370.     
  371.     delete[] buffer;
  372.     
  373.     output += _T("};\n\n");
  374.     
  375.     return output;
  376. }
  377.  
  378.  
  379. void XmlResApp::MakePackageCPP(const wxArrayString& flist)
  380. {
  381.     wxFFile file(parOutput, "wt");
  382.     size_t i;
  383.  
  384.     if (flagVerbose) 
  385.         wxPrintf(_T("creating C++ source file ") + parOutput +  _T("...\n"));
  386.     
  387.     file.Write(_T("")
  388. _T("//\n")
  389. _T("// This file was automatically generated by wxrc, do not edit by hand.\n")
  390. _T("//\n\n")
  391. _T("#include <wx/wxprec.h>\n")
  392. _T("\n")
  393. _T("#ifdef __BORLANDC__\n")
  394. _T("    #pragma hdrstop\n")
  395. _T("#endif\n")
  396. _T("\n")
  397. _T("#ifndef WX_PRECOMP\n")
  398. _T("    #include <wx/wx.h>\n")
  399. _T("#endif\n")
  400. _T("")
  401. _T("#include <wx/filesys.h>\n")
  402. _T("#include <wx/fs_mem.h>\n")
  403. _T("#include <wx/xrc/xmlres.h>\n")
  404. _T("#include <wx/xrc/xh_all.h>\n")
  405. _T("\n"));
  406.  
  407.     for (i = 0; i < flist.Count(); i++)
  408.         file.Write(FileToCppArray(flist[i], i));
  409.     
  410.     file.Write(_T("")
  411. _T("void " + parFuncname + "()\n")
  412. _T("{\n")
  413. _T("\n")
  414. _T("    // Check for memory FS. If not present, load the handler:\n")
  415. _T("    {\n")
  416. _T("        wxMemoryFSHandler::AddFile(\"XRC_resource/dummy_file\", \"dummy one\");\n")
  417. _T("        wxFileSystem fsys;\n")
  418. _T("        wxFSFile *f = fsys.OpenFile(\"memory:XRC_resource/dummy_file\");\n")
  419. _T("        wxMemoryFSHandler::RemoveFile(\"XRC_resource/dummy_file\");\n")
  420. _T("        if (f) delete f;\n")
  421. _T("        else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n")
  422. _T("    }\n")
  423. _T("\n"));
  424.  
  425.     for (i = 0; i < flist.Count(); i++)
  426.     {
  427.         wxString s;
  428.         s.Printf(_T("    wxMemoryFSHandler::AddFile(\"XRC_resource/") + flist[i] +
  429.                  _T("\", xml_res_file_%i, xml_res_size_%i);\n"), i, i);
  430.         file.Write(s);
  431.     }
  432.  
  433.     for (i = 0; i < parFiles.Count(); i++)
  434.     {
  435.         file.Write(_T("    wxXmlResource::Get()->Load(\"memory:XRC_resource/") + 
  436.                    GetInternalFileName(parFiles[i], flist) + _T("\");\n"));
  437.     }
  438.     
  439.     file.Write(_T("}\n"));
  440.  
  441.  
  442. }
  443.  
  444. static wxString FileToPythonArray(wxString filename, int num)
  445. {
  446.     wxString output;
  447.     wxString tmp;
  448.     wxString snum;
  449.     wxFFile file(filename, "rb");
  450.     size_t lng = file.Length();
  451.     
  452.     snum.Printf(_T("%i"), num);
  453.     output = _T("    xml_res_file_") + snum + _T(" = \"\"\"\\\n");
  454.     
  455.     unsigned char *buffer = new unsigned char[lng];
  456.     file.Read(buffer, lng);
  457.     
  458.     for (size_t i = 0, linelng = 0; i < lng; i++)
  459.     {
  460.         unsigned char c = buffer[i];
  461.         if (c == '\n')
  462.         {
  463.             tmp = (wxChar)c;
  464.             linelng = 0;
  465.         }
  466.         else if (c < 32 || c > 127)
  467.             tmp.Printf(_T("\\x%02x"), c);
  468.         else if (c == '\\')
  469.             tmp = _T("\\\\");
  470.         else
  471.             tmp = (wxChar)c;
  472.         if (linelng > 70)
  473.         {
  474.             linelng = 0;
  475.             output << _T("\\\n");
  476.         }
  477.         output << tmp;
  478.         linelng += tmp.Length();
  479.     }
  480.     
  481.     delete[] buffer;
  482.     
  483.     output += _T("\"\"\"\n\n");
  484.     
  485.     return output;
  486. }
  487.  
  488.  
  489. void XmlResApp::MakePackagePython(const wxArrayString& flist)
  490. {
  491.     wxFFile file(parOutput, "wt");
  492.     size_t i;
  493.  
  494.     if (flagVerbose) 
  495.         wxPrintf(_T("creating Python source file ") + parOutput +  _T("...\n"));
  496.     
  497.     file.Write(
  498.        _T("#\n")
  499.        _T("# This file was automatically generated by wxrc, do not edit by hand.\n")
  500.        _T("#\n\n")
  501.        _T("from wxPython.wx import *\n")
  502.        _T("from wxPython.xrc import *\n\n")
  503.     );
  504.  
  505.     
  506.     file.Write(_T("def ") + parFuncname + _T("():\n"));
  507.  
  508.     for (i = 0; i < flist.Count(); i++)
  509.         file.Write(FileToPythonArray(flist[i], i));
  510.  
  511.     for (i = 0; i < flist.Count(); i++)
  512.     {
  513.         wxString s;
  514.         s.Printf(_T("    wxXmlResource_Get().LoadFromString(xml_res_file_%i)\n"), i);
  515.         file.Write(s);
  516.     }
  517. }
  518.  
  519.  
  520.  
  521. void XmlResApp::OutputGettext()
  522. {
  523.     wxArrayString str = FindStrings();
  524.     
  525.     wxFFile fout;
  526.     if (!parOutput) fout.Attach(stdout);
  527.     else fout.Open(parOutput, "wt");
  528.     
  529.     for (size_t i = 0; i < str.GetCount(); i++)
  530.         fout.Write(_T("_(\"") + str[i] + _T("\");\n"));
  531.     
  532.     if (!parOutput) fout.Detach();
  533. }
  534.  
  535.  
  536.  
  537. wxArrayString XmlResApp::FindStrings()
  538. {
  539.     wxArrayString arr, a2;
  540.  
  541.     for (size_t i = 0; i < parFiles.Count(); i++)
  542.     {
  543.         if (flagVerbose) 
  544.             wxPrintf(_T("processing ") + parFiles[i] +  _T("...\n"));
  545.  
  546.         wxXmlDocument doc;        
  547.         if (!doc.Load(parFiles[i]))
  548.         {
  549.             wxLogError(_T("Error parsing file ") + parFiles[i]);
  550.             retCode = 1;
  551.             continue;
  552.         }
  553.         a2 = FindStrings(doc.GetRoot());
  554.         WX_APPEND_ARRAY(arr, a2);
  555.     }
  556.     
  557.     return arr;
  558. }
  559.  
  560.  
  561.  
  562. static wxString ConvertText(const wxString& str)
  563. {
  564.     wxString str2;
  565.     const wxChar *dt;
  566.  
  567.     for (dt = str.c_str(); *dt; dt++)
  568.     {
  569.         if (*dt == wxT('_'))
  570.         {
  571.             if ( *(++dt) == wxT('_') )
  572.                 str2 << wxT('_');
  573.             else
  574.                 str2 << wxT('&') << *dt;
  575.         }
  576.         else 
  577.         {
  578.             switch (*dt)
  579.             {
  580.                 case wxT('\n') : str2 << wxT("\\n"); break;
  581.                 case wxT('\t') : str2 << wxT("\\t"); break;
  582.                 case wxT('\r') : str2 << wxT("\\r"); break;
  583.                 case wxT('\\') : if ((*(dt+1) != 'n') &&
  584.                                      (*(dt+1) != 't') &&
  585.                                      (*(dt+1) != 'r'))
  586.                                      str2 << wxT("\\\\");
  587.                                  else
  588.                                      str2 << wxT("\\");    
  589.                                  break;
  590.                 case wxT('"')  : str2 << wxT("\\\""); break;
  591.                 default        : str2 << *dt; break;
  592.             }
  593.         }
  594.     }
  595.  
  596.     return str2;
  597. }
  598.  
  599.  
  600. wxArrayString XmlResApp::FindStrings(wxXmlNode *node)
  601. {
  602.     wxArrayString arr;
  603.  
  604.     wxXmlNode *n = node;
  605.     if (n == NULL) return arr;
  606.     n = n->GetChildren();
  607.     
  608.     while (n)
  609.     {
  610.         if ((node->GetType() == wxXML_ELEMENT_NODE) &&
  611.             // parent is an element, i.e. has subnodes...
  612.             (n->GetType() == wxXML_TEXT_NODE || 
  613.             n->GetType() == wxXML_CDATA_SECTION_NODE) &&
  614.             // ...it is textnode...
  615.             (
  616.                 node/*not n!*/->GetName() == _T("label") ||
  617.                 (node/*not n!*/->GetName() == _T("value") &&
  618.                                !n->GetContent().IsNumber()) ||
  619.                 node/*not n!*/->GetName() == _T("help") ||
  620.                 node/*not n!*/->GetName() == _T("longhelp") ||
  621.                 node/*not n!*/->GetName() == _T("tooltip") ||
  622.                 node/*not n!*/->GetName() == _T("htmlcode") ||
  623.                 node/*not n!*/->GetName() == _T("title") ||
  624.                 node/*not n!*/->GetName() == _T("item")
  625.             ))
  626.             // ...and known to contain translatable string
  627.         {
  628.             arr.Add(ConvertText(n->GetContent()));
  629.         }
  630.         
  631.         // subnodes:
  632.         if (n->GetType() == wxXML_ELEMENT_NODE)
  633.         {
  634.             wxArrayString a2 = FindStrings(n);
  635.             WX_APPEND_ARRAY(arr, a2);
  636.         }
  637.         
  638.         n = n->GetNext();
  639.     }
  640.     return arr;
  641. }
  642.