makemsi.cxx

Go to the documentation of this file.
00001 // @(#)root/winnt:$Id: makemsi.cxx 20882 2007-11-19 11:31:26Z rdm $
00002 // Author: Axel Naumann 2006-05-09
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 // WiX MSI Installer Package Utility
00013 // Creates a WiX source file
00014 
00015 // USAGE: makemsi outputfile.msi -T filelist.txt
00016 // will create a MSI file for files in filelist.txt
00017 
00018 #if !defined(VERSION) || !defined(PRODUCT)
00019 #  error "Define the CPP macros PRODUCT and VERSION!"
00020 #endif
00021 
00022 #include <rpc.h>
00023 #include <stdio.h>
00024 #include <list>
00025 #include <map>
00026 #include <iostream>
00027 #include <fstream>
00028 #include <sstream>
00029 #include <string>
00030 #include <algorithm>
00031 
00032 using std::string;
00033 using std::list;
00034 using std::map;
00035 using std::cerr;
00036 using std::endl;
00037 using std::ostream;
00038 
00039 ////////////////////////////////////////////////////////////////////////////////
00040 // CLASS DECLARATIONS
00041 ////////////////////////////////////////////////////////////////////////////////
00042 
00043 class MSIDir;
00044 
00045 class MSIDirEntry {
00046 public:
00047    MSIDirEntry(const char* name, MSIDir* parent, bool dir);
00048    virtual ~MSIDirEntry() {}
00049 
00050    string GetLongName() const {return fLongName;}
00051    string GetShortName() const {return fShortName;}
00052    string GetPath() const {return fPath;}
00053    string GetId() const;
00054    MSIDir* GetParent() const {return fParent;}
00055 
00056    virtual void WriteRecurse(ostream& out, string indent) const = 0;
00057    ostream& WriteLongShort(ostream& out) const;
00058 
00059 private:
00060    void SetShortName(bool dir);
00061    string GetMyId() const;
00062 
00063    string fLongName; // regular name
00064    string fShortName; // 8.3 name
00065    string fPath; // path incl parents
00066    MSIDir* fParent; // parent dir
00067 };
00068 
00069 ////////////////////////////////////////////////////////////////////////////////
00070 
00071 class MSIFile;
00072 
00073 class MSIDir: public MSIDirEntry {
00074 public:
00075    MSIDir(const char* name, MSIDir* parent=0): MSIDirEntry(name, parent, true) {}
00076    ~MSIDir() {if (!GetParent()) UpdateGuids();}
00077 
00078    void AddFile(const char* file);
00079 
00080    void Write(ostream& out) const;
00081 
00082 private:
00083    void WriteRecurse(ostream& out, string indent) const;
00084    void WriteComponentsRecurse(ostream& out, string indent) const;
00085    const char* GetGuid() const {
00086       if (!fgGuids.size() && !fgNewGuids.size()) SetupGuids();
00087       map<string, string>::const_iterator iGuid = fgGuids.find(GetId());
00088       if (iGuid == fgGuids.end()) return CreateGuid();
00089       return iGuid->second.c_str();
00090    }
00091    const char* CreateGuid() const;
00092    static void SetupGuids();
00093    static void UpdateGuids();
00094 
00095    map<string, MSIDir*> fSubdirs;
00096    list<MSIFile*> fFiles;
00097 
00098    static map<string, string> fgGuids;
00099    static map<string, string> fgNewGuids; // guids created during this process
00100    static const char* fgGuidFileName; // location of the GUID file
00101 };
00102 
00103 ////////////////////////////////////////////////////////////////////////////////
00104 
00105 class MSIFile: public MSIDirEntry {
00106 public:
00107    MSIFile(const char* name, MSIDir* parent): MSIDirEntry(name, parent, false) {}
00108 
00109    void WriteRecurse(ostream& out, string indent) const {
00110       out << indent << "<File Id=\"" << GetId() << "\" ";
00111       WriteLongShort(out) << "DiskId=\"1\"></File>" << std::endl;
00112    };
00113 };
00114 
00115 
00116 
00117 ////////////////////////////////////////////////////////////////////////////////
00118 // MSIDirEntry DEFINITIONS
00119 ////////////////////////////////////////////////////////////////////////////////
00120 
00121 MSIDirEntry::MSIDirEntry(const char* name, MSIDir* parent, bool dir): fLongName(name), fParent(parent) 
00122 { 
00123    if (fParent) fPath = fParent->GetPath() + '/' + name;
00124    else fPath = ".";
00125    SetShortName(dir); 
00126 }
00127 
00128 void MSIDirEntry::SetShortName(bool dir) {
00129    WIN32_FIND_DATA findData;
00130    string filename(GetPath());
00131    HANDLE hFind = ::FindFirstFile(filename.c_str(), &findData);
00132    if (hFind == INVALID_HANDLE_VALUE) {
00133       cerr << "Cannot find " << filename << endl;
00134    } else {
00135       bool foundDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0;
00136       if (foundDir == !dir)
00137          cerr << filename << " is not what I expected it to be!" << endl;
00138       else
00139          fShortName = findData.cAlternateFileName;
00140    } 
00141    FindClose(hFind);
00142 }
00143 
00144 string MSIDirEntry::GetId() const { 
00145    string ret;
00146    if (fParent) ret = fParent->GetId() + "_";
00147    return ret + GetMyId();
00148 }
00149 
00150 string MSIDirEntry::GetMyId() const { 
00151    string ret(fLongName);
00152    std::replace(ret.begin(), ret.end(), '/', '_');
00153    std::replace(ret.begin(), ret.end(), '-', '_');
00154    std::replace(ret.begin(), ret.end(), '#', '_');
00155    std::replace(ret.begin(), ret.end(), '~', '_');
00156    std::replace(ret.begin(), ret.end(), '@', '_');
00157    return ret;
00158 }
00159 
00160 ostream& MSIDirEntry::WriteLongShort(ostream& out) const {
00161    if (!fShortName.empty()) 
00162       out << "LongName=\"" << fLongName <<"\" Name=\"" << fShortName << "\" ";
00163    else out << "Name=\"" << fLongName << "\" ";
00164    return out;
00165 }
00166 
00167 
00168 
00169 ////////////////////////////////////////////////////////////////////////////////
00170 // MSIDir DEFINITIONS
00171 ////////////////////////////////////////////////////////////////////////////////
00172 
00173 map<string, string> MSIDir::fgGuids;
00174 map<string, string> MSIDir::fgNewGuids;
00175 const char* MSIDir::fgGuidFileName = 0; // set to e.g. "guids.txt" make GUIDs persistent
00176 
00177 void MSIDir::AddFile(const char* file) {
00178    string subdir(file);
00179    string filename(file);
00180 
00181    string::size_type posSlash = subdir.find('/');
00182    if (posSlash != string::npos) {
00183       subdir.erase(posSlash, subdir.length());
00184       filename.erase(0, posSlash+1);
00185    } else subdir.erase();
00186 
00187    if (filename.empty()) {
00188       cerr << "Cannot add empty filename!" << endl;
00189       return;
00190    }
00191    if (subdir.empty()) fFiles.push_back(new MSIFile(filename.c_str(), this));
00192    else {
00193       if (!fSubdirs[subdir]) fSubdirs[subdir] = new MSIDir(subdir.c_str(), this);
00194       fSubdirs[subdir]->AddFile(filename.c_str());
00195    }
00196 }
00197 
00198 void MSIDir::Write(ostream& out) const {
00199    const DWORD bufsize = MAX_PATH;
00200    char pwd[bufsize];
00201    ::GetCurrentDirectory(bufsize, pwd);
00202 
00203    out << "<?xml version=\"1.0\" encoding=\"windows-1252\" ?>" << std::endl;
00204    out << "<Wix xmlns=\"http://schemas.microsoft.com/wix/2003/01/wi\">" << std::endl;
00205    out << "<Product Name=\"" << PRODUCT << "\" Id=\"{f570a3d8-bc0d-408e-bbe3-57e6deee5aaa}\" Language=\"1033\" Codepage=\"1252\"" << std::endl;
00206    out << "   Version=\"" << VERSION << "\" Manufacturer=\"ROOT Team\">" << std::endl;
00207    out << "   <Package Id=\"???????\?-???\?-???\?-???\?-????????????\" Keywords=\"Installer\" Description=\"ROOT Installer\"" << std::endl;
00208    out << "        Comments=\"ROOT Windows Installer, see http://root.cern.ch\" Manufacturer=\"CERN\" InstallerVersion=\"100\"" << std::endl;
00209    out << "        Languages=\"1033\" Compressed=\"yes\" SummaryCodepage=\"1252\" />" << std::endl;
00210    out << "   <Media Id=\"1\" Cabinet=\"ROOT.cab\" EmbedCab=\"yes\" />" << std::endl;
00211    out << "   <Directory Id=\"TARGETDIR\" Name=\"SourceDir\">" << std::endl;
00212    out << "      <Component Id=\"EnvVars\" Guid=\"{0E85B756-F20C-4213-A292-4AD80A5FE21A}\">" << std::endl;
00213    out << "         <Environment Id=\"ROOTSYS\" Name=\"ROOTSYS\" Action=\"set\" Part=\"all\" Value=\"[INSTALLLOCATION]\" />" << std::endl;
00214    out << "         <Environment Id=\"PATHROOT\" Name=\"PATH\" Action=\"set\" Part=\"first\" Value=\"[INSTALLLOCATION]bin\" />" << std::endl;
00215    out << "         <Environment Id=\"PATHPY\" Name=\"PYTHONPATH\" Action=\"set\" Part=\"first\" Value=\"[INSTALLLOCATION]bin\" />" << std::endl;
00216    out << "      </Component>" << std::endl;
00217    out << "      <Directory Id=\"DesktopFolder\">" << std::endl;
00218    out << "         <Component Id=\"DesktopIcon\" Guid=\"{BF68C3D3-D9AC-488d-A73F-1C732466DBF7}\">" << std::endl;
00219    out << "            <Shortcut Id=\"DesktopIcon\" Directory=\"DesktopFolder\"" << std::endl;
00220    out << "               Name=\"" << PRODUCT << "\" LongName=\"" << PRODUCT << " " << VERSION << "\" Target=\"[!ROOTSYS_bin_root.exe]\" " << std::endl;
00221    out << "               WorkingDirectory=\"INSTALLLOCATION\" Icon=\"root.exe\" IconIndex=\"0\" />" << std::endl;
00222    out << "         </Component>" << std::endl;
00223    out << "      </Directory>" << std::endl;
00224    out << "      <Directory Id=\"ProgramMenuFolder\">" << std::endl;
00225    out << "         <Directory Id=\"PM_ROOT\" Name=\"ROOT\">" << std::endl;
00226    out << "            <Component Id=\"StartMenuIcon\" Guid=\"{801AF243-0D4F-4f26-AF98-60DFB704969E}\">" << std::endl;
00227    out << "               <Shortcut Id=\"StartMenuIcon\" Directory=\"PM_ROOT\"" << std::endl;
00228    out << "                 Name=\"" << PRODUCT << "\" LongName=\"" << PRODUCT << " " << VERSION << "\" Target=\"[!ROOTSYS_bin_root.exe]\" " << std::endl;
00229    out << "                 WorkingDirectory=\"INSTALLLOCATION\" Icon=\"root.exe\" IconIndex=\"0\" />" << std::endl;
00230    out << "            </Component>" << std::endl;
00231    out << "         </Directory>" << std::endl;
00232    out << "      </Directory>" << std::endl;
00233    out << "      <Directory Id=\"WindowsVolume\" Name=\"WinVol\">" << std::endl;
00234    out << "         <Directory Id=\"INSTALLLOCATION\" Name=\"root\" FileSource=\"" << pwd << "\">" << std::endl;
00235 
00236    WriteRecurse(out, std::string("             "));
00237 
00238    out << "         </Directory>" << std::endl;
00239    out << "      </Directory>" << std::endl;
00240    out << "   </Directory>" << std::endl;
00241    out << "   <Feature Id=\"Base\" Title=\"Core modules\" Level=\"1\" Description=\"Core ROOT files\" Absent=\"disallow\" "<< std::endl;
00242    out << "      AllowAdvertise =\"no\" ConfigurableDirectory=\"INSTALLLOCATION\" TypicalDefault=\"install\">" << std::endl;
00243 
00244    WriteComponentsRecurse(out, std::string("         "));
00245 
00246    out << "      <Feature Id=\"EnvVars\" Title=\"Environment variables\" Level=\"1\" Description=\"ROOT environment variables\" AllowAdvertise =\"no\">" << std::endl;
00247    out << "         <ComponentRef Id=\"EnvVars\" />" << std::endl;
00248    out << "      </Feature>" << std::endl;
00249    out << "   </Feature>" << std::endl;
00250    out << "   <Feature Id=\"Shortcuts\" Title=\"Shortcuts\" Level=\"1\" Description=\"ROOT shortcuts\" AllowAdvertise =\"no\">" << std::endl;
00251    out << "      <Feature Id=\"DesktopIcon\" Title=\"Desktop Icon\" Level=\"1\" Description=\"ROOT desktop icon\">" << std::endl;
00252    out << "         <ComponentRef Id=\"DesktopIcon\" />" << std::endl;
00253    out << "      </Feature>" << std::endl;
00254    out << "      <Feature Id=\"StartMenuIcon\" Title=\"Startmenu Icon\" Level=\"1\" Description=\"ROOT start menu entry\">" << std::endl;
00255    out << "         <ComponentRef Id=\"StartMenuIcon\" />" << std::endl;
00256    out << "      </Feature>" << std::endl;
00257    out << "   </Feature>" << std::endl;
00258    out << "   <Property Id=\"INSTALLLOCATION\">" << std::endl;
00259    out << "      <RegistrySearch Id=\"RegInstallLocation\" Type=\"raw\" " << std::endl;
00260    out << "         Root=\"HKLM\" Key=\"Software\\CERN\\ROOT\" Name=\"InstallDir\" />" << std::endl;
00261    out << "   </Property>" << std::endl;
00262    out << "   <Icon Id=\"root.exe\" SourceFile=\"" << pwd << "/bin/root.exe\" />" << std::endl;
00263    out << "   <UIRef Id=\"WixUI\" />" << std::endl;
00264    out << "</Product>" << std::endl;
00265    out << "</Wix>" << std::endl;
00266 }
00267 
00268 void MSIDir::WriteRecurse(ostream& out, string indent) const {
00269    // write to out recursively
00270    if (!fFiles.size() && !fSubdirs.size()) return;
00271 
00272    if (GetParent()) {
00273       // assume that Write takes care of the root dir.
00274       out << indent << "<Directory Id=\"" << GetId() << "\" ";
00275       WriteLongShort(out) << ">" << std::endl;
00276       indent+="   ";
00277    }
00278 
00279    if (fFiles.size()) {
00280       out << indent << "<Component Id=\"Component_" << GetId() << "\" Guid=\"" 
00281          << GetGuid() << "\">" << std::endl;
00282       indent+="   ";
00283 
00284       for (list<MSIFile*>::const_iterator iFile = fFiles.begin(); iFile != fFiles.end(); ++iFile) {
00285          (*iFile)->WriteRecurse(out, indent);
00286       }
00287       indent.erase(indent.length()-3, 3);
00288       out << indent << "</Component>" << std::endl;
00289    }
00290    for (map<string, MSIDir*>::const_iterator iSubdir = fSubdirs.begin(); iSubdir != fSubdirs.end(); ++iSubdir)
00291       iSubdir->second->WriteRecurse(out, indent);
00292 
00293    indent.erase(indent.length()-3, 3);
00294    if (GetParent()) {
00295       // assume that Write takes care of the root dir.
00296       out << indent << "</Directory>" << std::endl;
00297    }
00298 }
00299 
00300 void MSIDir::WriteComponentsRecurse(ostream& out, string indent) const {
00301    // write all components to out
00302    if (!fFiles.empty()) 
00303       out << indent << "<ComponentRef Id=\"Component_" << GetId() << "\" />" << std::endl;
00304    for (map<string, MSIDir*>::const_iterator iSubdir = fSubdirs.begin(); iSubdir != fSubdirs.end(); ++iSubdir)
00305       iSubdir->second->WriteComponentsRecurse(out, indent);
00306 }
00307 
00308 
00309 const char* MSIDir::CreateGuid() const {
00310    UUID uuid;
00311    ::UuidCreate(&uuid);
00312    unsigned char* str = 0;
00313    ::UuidToString(&uuid, &str);
00314    std::string id = GetId();
00315    const std::string& ret = fgGuids[id] = (char*)str;
00316    fgNewGuids[id] = ret;
00317    RpcStringFree(&str);
00318    return ret.c_str();
00319 }
00320 
00321 void MSIDir::SetupGuids() {
00322    if (!fgGuidFileName) return;
00323 
00324    std::ifstream in(fgGuidFileName);
00325    std::string line;
00326    while (std::getline(in, line)) {
00327       std::istringstream sin(line);
00328       std::string id, guid;
00329       sin >> id >> guid;
00330       fgGuids[id] = guid;
00331    }
00332 }
00333 
00334 void MSIDir::UpdateGuids() {
00335    if (!fgNewGuids.size() || !fgGuidFileName) return;
00336 
00337    std::ofstream out(fgGuidFileName, std::ios_base::app);
00338    if (!out) {
00339       cerr << "ERROR: cannot write to GUID file " 
00340          << fgGuidFileName << "!" << endl;
00341       cerr << "ERROR: You should NOT use this MSI file, but re-generate with with accessible GUID file!"
00342          << endl;
00343       return;
00344    }
00345    for (map<string, string>::const_iterator iGuid = fgNewGuids.begin(); iGuid != fgNewGuids.end(); ++iGuid)
00346       out << iGuid->first << " " << iGuid->second << endl;
00347    std::cout << "WARNING: new GUIDs created; please cvs checkin " << fgGuidFileName << "!" << endl;
00348 }
00349 
00350 
00351 
00352 ////////////////////////////////////////////////////////////////////////////////
00353 // main()
00354 ////////////////////////////////////////////////////////////////////////////////
00355 
00356 int main(int argc, char *argv[]) {
00357    if (argc<4 || string(argv[2]) != "-T") {
00358       cerr << "USAGE: " << argv[0] << " <msifile> -T <inputlistfile>" << endl;
00359       return 1;
00360    }
00361 
00362    string outfile = argv[1];
00363    std::ofstream out(outfile.c_str());
00364    if (!out) {
00365       cerr << "Cannot open output file " << outfile << "!" << endl;
00366       return 2;
00367    }
00368 
00369    string infile = argv[3];
00370    std::ifstream in(infile.c_str());
00371    if (!in) {
00372       cerr << "Cannot open input file " << infile << "!" << endl;
00373       return 2;
00374    }
00375 
00376    MSIDir fileroot("ROOTSYS");
00377    string line;
00378    while (std::getline(in, line))
00379       fileroot.AddFile(line.c_str());
00380 
00381    fileroot.Write(out);
00382 }

Generated on Tue Jul 5 14:10:17 2011 for ROOT_528-00b_version by  doxygen 1.5.1