00001 #ifndef VERSION_INI_IMPLEMENTATION_FILE
00002 #define VERSION_INI_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "byte_filer.h"
00019 #include "filename.h"
00020 #include "ini_config.h"
00021 #include "version_ini.h"
00022
00023 #include <basis/function.h>
00024 #include <basis/portable.h>
00025 #include <basis/string_array.h>
00026 #include <basis/version_record.h>
00027 #include <opsystem/directory.h>
00028
00029 #include <sys/stat.h>
00030 #ifdef __WIN32__
00031 #include <io.h>
00032 #endif
00033
00034
00035 const char *version_ini::VERSION_SECTION = "version";
00036
00037 const char *version_ini::COMPANY_KEY="company";
00038 const char *version_ini::COPYRIGHT_KEY="copyright";
00039 const char *version_ini::LEGAL_INFO_KEY="legal_info";
00040 const char *version_ini::PRODUCT_KEY="product_name";
00041 const char *version_ini::WEB_SITE_KEY="web_site";
00042
00043
00044
00045
00046
00047
00048 const char *version_ini::MAJOR = "major";
00049 const char *version_ini::MINOR = "minor";
00050 const char *version_ini::REVISION = "revision";
00051 const char *version_ini::BUILD = "build";
00052 const char *version_ini::DESCRIPTION = "description";
00053 const char *version_ini::ROOT = "root";
00054 const char *version_ini::NAME = "name";
00055 const char *version_ini::EXTENSION = "extension";
00056 const char *version_ini::OLE_AUTO = "ole_auto";
00057
00058
00059 const char *VERSION_INI_FILE = "/version.ini";
00060
00061 #undef LOG
00062 #define LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger(), t)
00063
00064 version_ini::version_ini(const istring &path_name)
00065 : _loaded(false),
00066 _path_name(new filename(path_name)),
00067 _ini(new ini_configurator("", ini_configurator::RETURN_ONLY)),
00068 _held_record(new version_record)
00069 {
00070 check_name(*_path_name);
00071 _ini->name(*_path_name);
00072 }
00073
00074 version_ini::~version_ini()
00075 {
00076 WHACK(_ini);
00077 WHACK(_path_name);
00078 WHACK(_held_record);
00079 }
00080
00081 bool version_ini::ole_auto_registering()
00082 {
00083 istring extension = _ini->load(VERSION_SECTION, OLE_AUTO, "");
00084 return (extension.lower() != "");
00085 }
00086
00087 bool version_ini::executable()
00088 {
00089 istring extension = _ini->load(VERSION_SECTION, EXTENSION, "");
00090 if (extension.lower() == istring("exe")) return true;
00091 return false;
00092 }
00093
00094 bool version_ini::library() { return !executable(); }
00095
00096 bool version_ini::writable() { return _path_name->is_writable(); }
00097
00098 void version_ini::check_name(filename &to_examine)
00099 {
00100
00101 if (to_examine.is_directory()) {
00102 to_examine = istring(to_examine) + VERSION_INI_FILE;
00103 to_examine.canonicalize();
00104 }
00105
00106
00107
00108 if ( (to_examine.raw()[0] != '.') && (to_examine.dirname().raw() == ".") ) {
00109 to_examine = istring("./") + to_examine;
00110 to_examine.canonicalize();
00111 }
00112 }
00113
00114 bool version_ini::executable(const istring &path_name_in)
00115 {
00116 filename path_name(path_name_in);
00117 check_name(path_name);
00118 ini_configurator temp_ini(path_name, ini_configurator::RETURN_ONLY);
00119 istring extension = temp_ini.load(VERSION_SECTION, EXTENSION, "");
00120 extension.to_lower();
00121 if (extension == istring("exe")) return true;
00122 return false;
00123 }
00124
00125 bool version_ini::library(const istring &path_name)
00126 { return !executable(path_name); }
00127
00128 version version_ini::get_version()
00129 {
00130 if (_loaded) return _held_record->file_version;
00131 get_record();
00132 return _held_record->file_version;
00133 }
00134
00135 void version_ini::set_version(const version &to_write, bool write_ini)
00136 {
00137 _held_record->file_version = to_write;
00138
00139
00140 _held_record->product_version = to_write;
00141 _held_record->product_version.set_component(version::REVISION, "0");
00142 _held_record->product_version.set_component(version::BUILD, "0");
00143
00144 if (!write_ini) return;
00145 _ini->store(VERSION_SECTION, MAJOR, to_write.get_component(version::MAJOR));
00146 _ini->store(VERSION_SECTION, MINOR, to_write.get_component(version::MINOR));
00147 _ini->store(VERSION_SECTION, REVISION, to_write.get_component(version::REVISION));
00148 _ini->store(VERSION_SECTION, BUILD, to_write.get_component(version::BUILD));
00149 }
00150
00151 version version_ini::read_version_from_ini()
00152 {
00153 string_array parts;
00154 parts += _ini->load(VERSION_SECTION, MAJOR, "0");
00155 parts += _ini->load(VERSION_SECTION, MINOR, "0");
00156 parts += _ini->load(VERSION_SECTION, REVISION, "0");
00157 parts += _ini->load(VERSION_SECTION, BUILD, "0");
00158 return version(parts);
00159 }
00160
00161 version_record &version_ini::access_record() { return *_held_record; }
00162
00163 version_record version_ini::get_record()
00164 {
00165 FUNCDEF("get_record");
00166 if (_loaded) return *_held_record;
00167 version_record to_return;
00168 to_return.description = _ini->load(VERSION_SECTION, DESCRIPTION, "");
00169 to_return.file_version = read_version_from_ini();
00170 to_return.internal_name = _ini->load(VERSION_SECTION, NAME, "");
00171 to_return.original_name = _ini->load(VERSION_SECTION, ROOT, "");
00172 to_return.original_name += ".";
00173
00174
00175
00176 istring extension = _ini->load(VERSION_SECTION, EXTENSION, "");
00177 extension.to_lower();
00178 if (extension == "dll") {}
00179 else if (extension == "exe") {}
00180 else extension = "dll";
00181 to_return.original_name += extension;
00182
00183 to_return.product_version = to_return.file_version;
00184 to_return.product_version.set_component(version::REVISION, "0");
00185 to_return.product_version.set_component(version::BUILD, "0");
00186
00187 to_return.product_name = _ini->load(VERSION_SECTION, PRODUCT_KEY, "");
00188 to_return.company_name = _ini->load(VERSION_SECTION, COMPANY_KEY, "");
00189 to_return.copyright = _ini->load(VERSION_SECTION, COPYRIGHT_KEY, "");
00190 to_return.trademarks = _ini->load(VERSION_SECTION, LEGAL_INFO_KEY, "");
00191 to_return.web_address = _ini->load(VERSION_SECTION, WEB_SITE_KEY, "");
00192
00193
00194
00195
00199
00200 *_held_record = to_return;
00201 _loaded = true;
00202 return to_return;
00203 }
00204
00205 void version_ini::set_record(const version_record &to_write, bool write_ini)
00206 {
00207 *_held_record = to_write;
00208 if (write_ini) {
00209 _ini->store(VERSION_SECTION, DESCRIPTION, to_write.description);
00210 set_version(to_write.file_version, write_ini);
00211 _ini->store(VERSION_SECTION, ROOT, to_write.original_name);
00212 _ini->store(VERSION_SECTION, NAME, to_write.internal_name);
00213 }
00214 _loaded = true;
00215 }
00216
00218
00219 const istring version_rc_template = "\
00220 #ifndef NO_VERSION\n\
00221 #include <winver.h>\n\
00222 #include <__build_version.h>\n\
00223 #include <__build_configuration.h>\n\
00224 #define BI_PLAT_WIN32\n\
00225 // force 32 bit compile.\n\
00226 1 VERSIONINFO LOADONCALL MOVEABLE\n\
00227 FILEVERSION __build_FILE_VERSION_COMMAS\n\
00228 PRODUCTVERSION __build_PRODUCT_VERSION_COMMAS\n\
00229 FILEFLAGSMASK 0\n\
00230 FILEFLAGS VS_FFI_FILEFLAGSMASK\n\
00231 #if defined(BI_PLAT_WIN32)\n\
00232 FILEOS VOS__WINDOWS32\n\
00233 #else\n\
00234 FILEOS VOS__WINDOWS16\n\
00235 #endif\n\
00236 FILETYPE VFT_APP\n\
00237 BEGIN\n\
00238 BLOCK \"StringFileInfo\"\n\
00239 BEGIN\n\
00240 // Language type = U.S. English(0x0409) and Character Set = Windows, Multilingual(0x04b0)\n\
00241 BLOCK \"040904b0\" // Matches VarFileInfo Translation hex value.\n\
00242 BEGIN\n\
00243 VALUE \"CompanyName\", __build_company \"\\000\"\n\
00244 #ifndef _DEBUG\n\
00245 VALUE \"FileDescription\", \"$file_desc\\000\"\n\
00246 #else\n\
00247 VALUE \"FileDescription\", \"$file_desc\\000\"\n\
00248 #endif\n\
00249 VALUE \"FileVersion\", __build_FILE_VERSION \"\\000\" \n\
00250 VALUE \"ProductVersion\", __build_PRODUCT_VERSION \"\\000\" \n\
00251 VALUE \"InternalName\", \"$internal\\000\"\n\
00252 VALUE \"LegalCopyright\", __build_copyright \"\\000\"\n\
00253 VALUE \"LegalTrademarks\", __build_legal_info \"\\000\"\n\
00254 VALUE \"OriginalFilename\", \"$original_name\\000\"\n\
00255 VALUE \"ProductName\", __build_product_name \"\\000\"\n\
00256 $special_ole_flag\n\
00257 END\n\
00258 END\n\
00259 \n\
00260 BLOCK \"VarFileInfo\"\n\
00261 BEGIN\n\
00262 VALUE \"Translation\", 0x0409, 0x04b0 // US English (0x0409) and win32 multilingual (0x04b0)\n\
00263 END\n\
00264 END\n\
00265 #endif\n";
00266
00268
00269
00270 #define REPLACE(tag, replacement) \
00271 new_version_entry.replace_all(tag, replacement); \
00272
00273 bool version_ini::write_rc(const version_record &to_write)
00274 {
00275 istring new_version_entry(version_rc_template);
00276
00277
00278 REPLACE("$file_ver", to_write.file_version.flex_text_form(version::COMMAS));
00279
00280
00281 REPLACE("$prod_ver", to_write.product_version.flex_text_form
00282 (version::COMMAS));
00283
00284
00285 REPLACE("$company", to_write.company_name);
00286
00287
00288 istring description_release = to_write.description;
00289 REPLACE("$file_desc", description_release);
00290 istring description_debug = to_write.description
00291 + istring(" -- Debug Version");
00292 REPLACE("$file_desc", description_debug);
00293
00294
00295 REPLACE("$file_txt_ver", to_write.file_version.flex_text_form(version::DOTS));
00296
00297
00298 REPLACE("$internal", to_write.internal_name);
00299
00300
00301 REPLACE("$copyright", to_write.copyright);
00302
00303
00304 REPLACE("$legal_tm", to_write.trademarks);
00305
00306
00307 REPLACE("$original_name", to_write.original_name);
00308
00309
00310 REPLACE("$prod_name", to_write.product_name);
00311
00312
00313 REPLACE("$prod_txt_ver", to_write.product_version
00314 .flex_text_form(version::DOTS, version::MINOR));
00315
00316 istring special_filler;
00317 if (ole_auto_registering())
00318 special_filler = "VALUE \"OLESelfRegister\", \"\\0\"";
00319 REPLACE("$special_ole_flag", special_filler);
00320
00321 istring root_part = "/";
00322 root_part += _ini->load(VERSION_SECTION, ROOT, "");
00323
00324 istring rc_filename(istring(_path_name->dirname()) + root_part
00325 + "_version.rc");
00326
00327 filename(rc_filename).chmod(filename::ALLOW_BOTH, filename::USER_RIGHTS);
00328
00329
00330 byte_filer rc_file(rc_filename, "w");
00331 if (!rc_file.good()) return false;
00332 rc_file.write((byte *)new_version_entry.s(), new_version_entry.length());
00333 rc_file.close();
00334 return true;
00335 }
00336
00338
00339 const istring version_header_template = "\
00340 #ifndef $lib_prefix_VERSION_HEADER\n\
00341 #define $lib_prefix_VERSION_HEADER\n\
00342 \n\
00343 /*****************************************************************************\\\n\
00344 * *\n\
00345 * Name : Version header for $lib_name\n\
00346 * Author : Automatically generated by version_stamper *\n\
00347 * *\n\
00348 \\*****************************************************************************/\n\
00349 \n\
00350 #include <__build_version.h>\n\
00351 #include <__build_configuration.h>\n\
00352 #include <basis/version_checker.h>\n\
00353 #include <basis/version_record.h>\n\
00354 \n\
00355 #ifdef __WIN32__\n\
00356 \n\
00357 // this macro can be used to check that the current version of the\n\
00358 // $lib_name library is the same version as expected. to use it, check\n\
00359 // whether it returns true or false. if false, the version is incorrect.\n\
00360 #define CHECK_$lib_prefix() (version_checker(istring(\"$lib_prefix\")\\\n\
00361 + istring(\".dll\"), version(__build_SYSTEM_VERSION),\\\n\
00362 istring(\"Please contact $company_name for the latest DLL and \"\\\n\
00363 \"Executable files ($web_address).\")).good_version())\n\
00364 \n\
00365 #else\n\
00366 \n\
00367 // null checking for embedded or other platforms without versions.\n\
00368 \n\
00369 #define CHECK_$lib_prefix() 1\n\
00370 \n\
00371 #endif //__WIN32__\n\
00372 \n\
00373 #endif\n\
00374 \n";
00375
00377
00378 bool version_ini::write_code(const version_record &to_write)
00379 {
00380 istring root_part = _ini->load(VERSION_SECTION, ROOT, "");
00381 istring root = root_part.upper();
00382 istring name = _ini->load(VERSION_SECTION, NAME, "");
00383
00384 name.replace_all("$product_name", to_write.product_name);
00385
00386 istring new_version_entry(version_header_template);
00387
00388
00389
00390
00391 REPLACE("$lib_prefix", root);
00392 REPLACE("$lib_prefix", root);
00393 REPLACE("$lib_prefix", root);
00394 REPLACE("$lib_prefix", root);
00395 REPLACE("$lib_prefix", root);
00396 REPLACE("$lib_prefix", root);
00397 REPLACE("$lib_prefix", root);
00398
00399
00400 REPLACE("$lib_name", name);
00401 REPLACE("$lib_name", name);
00402 REPLACE("$lib_name", name);
00403
00404
00405 REPLACE("$lib_version", to_write.file_version.flex_text_form(version::COMMAS));
00406
00407
00408 REPLACE("$company_name", to_write.company_name);
00409
00410
00411 REPLACE("$web_address", to_write.web_address);
00412
00413 istring header_filename(_path_name->dirname().raw() + "/" + root_part
00414 + istring("_version.h"));
00415
00416 filename(header_filename).chmod(filename::ALLOW_BOTH, filename::USER_RIGHTS);
00417
00418
00419 byte_filer header(header_filename, "w");
00420 if (!header.good()) return false;
00421 header.write((byte *)new_version_entry.s(), new_version_entry.length());
00422 header.close();
00423 return true;
00424 }
00425
00426 bool version_ini::write_assembly(const version_record &to_write,
00427 bool do_logging)
00428 {
00429 FUNCDEF("write_assembly");
00430 filename just_dir = _path_name->dirname();
00431
00432 directory dir(just_dir);
00433 filename to_patch;
00434
00435 if (non_negative(dir.files().find("AssemblyInfo.cpp")))
00436 to_patch = just_dir.raw() + "/AssemblyInfo.cpp";
00437 else if (non_negative(dir.files().find("AssemblyInfo.cs")))
00438 to_patch = just_dir.raw() + "/AssemblyInfo.cs";
00439 if (to_patch.raw().t()) {
00440
00441 filename(to_patch).chmod(filename::ALLOW_BOTH, filename::USER_RIGHTS);
00442
00443 byte_filer modfile(to_patch, "r+b");
00444 istring contents;
00445 modfile.read(contents, 1000000);
00446 while (contents[contents.end()] == '\032') {
00447
00448 contents.zap(contents.end(), contents.end());
00449 }
00450
00451 int ver_posn = contents.find("AssemblyVersionAttribute", 0);
00452
00453 if (ver_posn < 0)
00454 ver_posn = contents.find("AssemblyVersion", 0);
00455 if (ver_posn < 0) return true;
00456
00457 int quote_posn = contents.find("\"", ver_posn);
00458 if (quote_posn < 0) return true;
00459
00460 int second_quote_posn = contents.find("\"", quote_posn + 1);
00461 if (second_quote_posn < 0) return true;
00462
00463 istring ver_string = to_write.file_version.flex_text_form(version::DOTS);
00464 contents.zap(quote_posn + 1, second_quote_posn - 1);
00465 contents.insert(quote_posn + 1, ver_string);
00466
00467 modfile.seek(0);
00468 modfile.write(contents);
00469 modfile.truncate();
00470 if (do_logging) {
00471
00472 filename dirbase = filename(modfile.filename()).dirname().basename();
00473 filename just_base = filename(modfile.filename()).basename();
00474 program_wide_logger().log(istring(" patching: ") + dirbase
00475 + "/" + just_base);
00476 }
00477 }
00478
00479 return true;
00480 }
00481
00482 bool version_ini::one_stop_version_stamp(const istring &path,
00483 const istring &source_version, bool do_logging)
00484 {
00485 istring path_name = path;
00487 if (path_name == ".")
00488 path_name = portable::current_directory();
00489
00490
00491 version_ini source(path_name);
00492 source.get_record();
00493
00494 if (source_version.t()) {
00495
00496 version_ini main_version(source_version);
00497 version version_to_use = main_version.get_version();
00498
00499
00500 source.set_version(version_to_use, false);
00501
00502
00503 version_record main = main_version.get_record();
00504 source.access_record().company_name = main.company_name;
00505 source.access_record().web_address = main.web_address;
00506 source.access_record().copyright = main.copyright;
00507 source.access_record().trademarks = main.trademarks;
00508 source.access_record().product_name = main.product_name;
00509
00510 source.access_record().internal_name.replace("$product_name",
00511 source.get_record().product_name);
00512 }
00513
00514 if (do_logging) {
00515
00516 program_wide_logger().log((source.get_record().internal_name + " version "
00517 + source.get_version().text_form() + ".").s());
00518 }
00519
00520 version_ini verini(path_name);
00521 verini.set_record(source.get_record(), false);
00522
00523
00524
00525
00526
00527 if (!verini.write_rc(verini.get_record())) {
00528 guards::alert_message(isprintf("Could not write the RC file in \"%s\".",
00529 filename(path_name).basename().raw().s()));
00530 return false;
00531 }
00532
00533 if (verini.library() && !verini.write_code(verini.get_record())) {
00534 guards::alert_message(istring("Could not write the C++ header file for "
00535 "the directory \"")
00536 + filename(path_name).basename() + istring("\".\n"));
00537 return false;
00538 }
00539
00540 if (!verini.write_assembly(verini.get_record(), do_logging)) {
00541 guards::alert_message(istring("Could not write the Assembly info file for "
00542 "the directory \"")
00543 + filename(path_name).basename() + istring("\".\n"));
00544 return false;
00545 }
00546
00547 return true;
00548 }
00549
00550 #endif //VERSION_INI_IMPLEMENTATION_FILE
00551