00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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;
00064 string fShortName;
00065 string fPath;
00066 MSIDir* fParent;
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;
00100 static const char* fgGuidFileName;
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
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
00171
00172
00173 map<string, string> MSIDir::fgGuids;
00174 map<string, string> MSIDir::fgNewGuids;
00175 const char* MSIDir::fgGuidFileName = 0;
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
00270 if (!fFiles.size() && !fSubdirs.size()) return;
00271
00272 if (GetParent()) {
00273
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
00296 out << indent << "</Directory>" << std::endl;
00297 }
00298 }
00299
00300 void MSIDir::WriteComponentsRecurse(ostream& out, string indent) const {
00301
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
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 }