mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Implemented condition parser for single conditions. The ModFormat and Types source files should be replaced by libespm usage at some point. Committing example masterlist and settings files for reference.
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@
|
||||
cmake_minimum_required (VERSION 2.8.9)
|
||||
project (boss)
|
||||
|
||||
set (BOSS_SRC "${CMAKE_SOURCE_DIR}/src/metadata.cpp" "${CMAKE_SOURCE_DIR}/src/game.cpp" "${CMAKE_SOURCE_DIR}/src/helpers.cpp")
|
||||
set (BOSS_SRC "${CMAKE_SOURCE_DIR}/src/metadata.cpp" "${CMAKE_SOURCE_DIR}/src/game.cpp" "${CMAKE_SOURCE_DIR}/src/helpers.cpp" "${CMAKE_SOURCE_DIR}/src/plugin/ModFormat.cpp" "${CMAKE_SOURCE_DIR}/src/plugin/VersionRegex.cpp")
|
||||
|
||||
# Include source and library directories.
|
||||
include_directories ("${BOSS_LIBS_DIR}/alphanum" "${BOSS_LIBS_DIR}/utf8" "${BOSS_LIBS_DIR}/boost" "${BOSS_LIBS_DIR}/yaml-cpp/include" "${CMAKE_SOURCE_DIR}/src")
|
||||
|
||||
@@ -175,9 +175,8 @@ possible, for example:
|
||||
* Boost: for filesystem interaction, various helpful functions.
|
||||
|
||||
As a reflection of this, LOOT's API will provide functions only for
|
||||
accessing LOOT-specific functionality and data, eg. auto-sorting,
|
||||
masterlist / userlist reading, masterlist download and user
|
||||
edits submission.
|
||||
accessing LOOT-specific functionality and data, eg. masterlist / userlist reading,
|
||||
masterlist download and user edits submission.
|
||||
|
||||
The support for arbitrary data sources will be implemented by having the source
|
||||
LOOT uses specified in a settings file, which will be editable via the GUI.
|
||||
@@ -529,7 +528,6 @@ bUseOnlineCache Boolean Cache = Database
|
||||
bGetMetadataUpdates Boolean Metadata = Masterlist
|
||||
bPromptMetadataSubmit Boolean
|
||||
bAlwaysSubmitMetadata Boolean Only has effect if the above is false.
|
||||
bDoStartupUpdateCheck Boolean Check for program updates.
|
||||
|
||||
sOnlineCacheURL String URL to the base of the database repository.
|
||||
sMetadataURL String
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
# This is the Oblivion masterlist up to the end of the ESMs group, converted by
|
||||
# hand to MF3 (ie. YAML-based format for BOSSv3). Mods without messages attached
|
||||
# have been removed (since they wouldn't be included unless extra data was
|
||||
# required for BOSS to sort them.
|
||||
|
||||
globals:
|
||||
|
||||
- condition: IF VERSION("../BOSS/BOSS.exe", "2.1.1.0", <)
|
||||
type: warn
|
||||
content: An update for BOSS (v2.1.1) has been released. Download it at "http://code.google.com/p/better-oblivion-sorting-software/downloads/list"
|
||||
|
||||
- condition: IFNOT VERSION("../BOSS/BOSS.exe", "2.1.1.0", <)
|
||||
type: say
|
||||
content: You are using the latest version of BOSS.
|
||||
|
||||
plugins:
|
||||
|
||||
- name: Oblivion_1.1.esm
|
||||
msg:
|
||||
- &modESM
|
||||
type: say
|
||||
content: A modding esm - do not use in game, deactivate.
|
||||
|
||||
- name: Oblivion_SI.esm
|
||||
msg:
|
||||
- *modESM
|
||||
|
||||
- name: Oblivion_GOTY non-SI.esm
|
||||
msg:
|
||||
- *modESM
|
||||
|
||||
- name: Hammerfell.esm
|
||||
msg:
|
||||
- condition: if checksum("Hammerfell.esm", 7D22F9DF)
|
||||
type: warn
|
||||
content: 'Contains dirty edits; 0 ITM, 4 UDR records. Needs TES4Edit cleaning: "http://cs.elderscrolls.com/constwiki/index.php/TES4Edit_Cleaning_Guide"'
|
||||
|
||||
- name: GTAesgaard_2.esm
|
||||
msg:
|
||||
- &warnWorldspaces
|
||||
type: warn
|
||||
content: This needs to load directly after Oblivion.esm to avoid landscape issues caused by a failure by the mod author to use TES4Gecko's "Move Worldspaces" function.
|
||||
|
||||
- name: DibellasWatch.esm
|
||||
msg:
|
||||
- *warnWorldspaces
|
||||
|
||||
- name: Belas.esm
|
||||
msg:
|
||||
- type: warn
|
||||
content: Part of Chronicles of Reeb. Do not use. Has serious landscape issues due to editing the Tamriel worldspace. Uninstall and delete.
|
||||
|
||||
- name: Morrowind_ob.esm
|
||||
msg:
|
||||
- *warnWorldspaces
|
||||
|
||||
- name: Silgrad_Tower.esm
|
||||
msg:
|
||||
- condition: if file("Silgrad_Tower_T.esm")
|
||||
type: warn
|
||||
content: Use either Silgrad_Tower.esm or Silgrad_Tower_T.esm but not both together.
|
||||
|
||||
- name: Silgrad_Tower_T.esm
|
||||
msg:
|
||||
- condition: if file("Silgrad_Tower.esm")
|
||||
type: warn
|
||||
content: Use either Silgrad_Tower.esm or Silgrad_Tower_T.esm but not both together.
|
||||
|
||||
- name: Beautiful People 2ch-Ed.esm
|
||||
tag:
|
||||
- Eyes
|
||||
- Graphics
|
||||
- Hair
|
||||
- R.Relations
|
||||
|
||||
- name: xeoex.esm
|
||||
tag:
|
||||
- Body-F
|
||||
- Body-Size-F
|
||||
- Body-M
|
||||
- Body-Size-M
|
||||
- Eyes
|
||||
|
||||
- name: EnhancedWeatherSIOnly.esm
|
||||
msg:
|
||||
- type: warn
|
||||
content: Obsolete. Remove this and install Enhanced Weather.
|
||||
|
||||
- name: Francesco's Leveled Creatures-Items Mod.esm
|
||||
tag:
|
||||
- Actors.ACBS
|
||||
- Actors.AIData
|
||||
- Actors.AIPackages
|
||||
- Actors.CombatStype
|
||||
- Actors.DeathItem
|
||||
- Actors.Stats
|
||||
- Delev
|
||||
- Invent
|
||||
- NpcFaces
|
||||
- Relev
|
||||
- Scripts
|
||||
- Stats
|
||||
msg:
|
||||
- condition: IF CHECKSUM("Francesco's Leveled Creatures-Items Mod.esm", 17F6FD1A)
|
||||
type: warn
|
||||
content: 'Contains dirty edits; 6 ITM, 0 UDR records. Needs TES4Edit cleaning: "http://cs.elderscrolls.com/constwiki/index.php/TES4Edit_Cleaning_Guide"'
|
||||
|
||||
- name: Francesco's Optional New Items Add-On.esm
|
||||
tag:
|
||||
- Delev
|
||||
- Relev
|
||||
msg:
|
||||
- condition: IF CHECKSUM("Francesco's Optional New Items Add-On.esm", DFD4FB97)
|
||||
type: warn
|
||||
content: 'Contains dirty edits; 2 ITM, 0 UDR records. Needs TES4Edit cleaning: "http://cs.elderscrolls.com/constwiki/index.php/TES4Edit_Cleaning_Guide"'
|
||||
|
||||
- name: Francesco's Optional New Creatures Add-On.esm
|
||||
tag:
|
||||
- Actors.AIPackages
|
||||
- Delev
|
||||
- Factions
|
||||
- Invent
|
||||
- Relations
|
||||
- Relev
|
||||
- Scripts
|
||||
msg:
|
||||
- condition: &fcomCond IF FILE("FCOM_Convergence.esm")
|
||||
type: error
|
||||
content: Delete. Not compatible with FCOM. Already integrated into FCOM.
|
||||
|
||||
- name: Crafting Skill Engine.esm
|
||||
msg:
|
||||
- condition: IF FILE("Retros Fletching and Imbueing 1.7.1_rus.esp")
|
||||
type: error
|
||||
content: Delete. Included in Retros Fletching and Imbueing 1.7.1_rus.esp
|
||||
|
||||
- name: Tamrielic Ingredients.esm
|
||||
msg:
|
||||
- type: say
|
||||
content: Do not use Tamrielic Ingredients and COBL at the same time.
|
||||
|
||||
- name: Cobl Main.esm
|
||||
msg:
|
||||
- type: say
|
||||
content: Do not use Tamrielic Ingredients and COBL at the same time.
|
||||
|
||||
- name: Item interchange.esm
|
||||
msg:
|
||||
- type: say
|
||||
content: Outdated. All functions are now handled by Cobl.esm. Update to the latest versions of 'Item Interchange' and Cobl.
|
||||
|
||||
- name: Qarls_Harvest.esm
|
||||
tag:
|
||||
- Scripts
|
||||
|
||||
- name: DEJ Harvest - Flora.esm
|
||||
msg:
|
||||
- type: say
|
||||
content: Obsolete. Update to 'Harvest [Flora]' v3.0.1+.
|
||||
|
||||
- name: Tamriel's Glittering Geology.esm
|
||||
msg:
|
||||
- condition: &oooCond IF FILE("Oscuro's_Oblivion_Overhaul.esm")
|
||||
type: error
|
||||
content: Not compatible with OOO. Already included in OOO.
|
||||
|
||||
- name: Oscuro's_Oblivion_Overhaul.esm
|
||||
tag:
|
||||
- Actors.Spells
|
||||
- Graphics
|
||||
- Invent
|
||||
- Relations
|
||||
- Scripts
|
||||
- Stats
|
||||
- condition: IF FILE("Mart's Monster Mod for OOO.esm") || IF VAR(FCOM)
|
||||
name: -Relations
|
||||
msg:
|
||||
- type: say
|
||||
content: Do not clean. "Dirty" edits are intentional and required for the mod to function.
|
||||
|
||||
- name: Mart's Monster Mod.esm
|
||||
tag:
|
||||
- Actors.AIData
|
||||
- Actors.AIPackages
|
||||
- Actors.Spells
|
||||
- Actors.Stats
|
||||
- Delev
|
||||
- Factions
|
||||
- Graphics
|
||||
- Invent
|
||||
- Names
|
||||
- Relations
|
||||
- Relev
|
||||
- Scripts
|
||||
- Stats
|
||||
|
||||
- name: Mart's Monster Mod for OOO.esm
|
||||
msg:
|
||||
- condition: *fcomCond
|
||||
type: error
|
||||
content: Delete. Not compatible with FCOM.
|
||||
tag:
|
||||
- Delev
|
||||
- Factions
|
||||
- Relations
|
||||
- Relev
|
||||
|
||||
# The message attached to the Waalx plugin below is too vague for the specialised
|
||||
# incompatibility list in MF3, and should probably be removed.
|
||||
- name: Waalx Animals & Creatures.esm
|
||||
msg:
|
||||
- type: say
|
||||
content: Incompatible with other overhaul mods.
|
||||
|
||||
- name: FCOM_Convergence.esm
|
||||
tag:
|
||||
- Delev
|
||||
- Factions
|
||||
- Relations
|
||||
- Relev
|
||||
|
||||
- name: Armamentarium.esm
|
||||
tag:
|
||||
- Relev
|
||||
|
||||
- name: ArmamentariumFran.esm
|
||||
tag:
|
||||
- Relev
|
||||
|
||||
- name: ArmamentariumEnchanted.esm
|
||||
msg:
|
||||
- type: say
|
||||
content: Outdated, included in Armamentarium Complete.
|
||||
|
||||
- name: bookplacing.esm
|
||||
msg:
|
||||
- type: warn
|
||||
content: Check you are using v2+. If not, Update. v1 has a severe bug with the Mystic Emporium disappearing.
|
||||
|
||||
- name: No Lights Flicker.esm
|
||||
msg:
|
||||
- condition: &bpTweakMsg IF FILE("Bashed Patch.*\.esp")
|
||||
type: say
|
||||
content: Use Wrye Bash Bashed Patch tweak instead.
|
||||
|
||||
# If a plugin name was given for Reznod's Mannequins, the incompatibility list
|
||||
# syntax could be used.
|
||||
- name: TLS Modded Mannequins.esm
|
||||
msg:
|
||||
- type: say
|
||||
content: Incompatible with Reznod's Mannequins.
|
||||
|
||||
- name: DKImperials.esm
|
||||
tag:
|
||||
- Hair
|
||||
- Eyes
|
||||
|
||||
- name: Minotaur Race.esm
|
||||
req:
|
||||
- name: &OBSE ../obse_loader.exe
|
||||
condition: if version("../obse_loader.exe", "0.0.18.0", >=)
|
||||
display: OBSE v18+
|
||||
msg:
|
||||
- type: say
|
||||
content: Requires 'Race Repository'
|
||||
- condition: IF CHECKSUM("Minotaur Race.esm", 477340C8)
|
||||
type: warn
|
||||
content: 'Contains dirty edits; 7 ITM, 0 UDR records. Needs TES4Edit cleaning: "http://cs.elderscrolls.com/constwiki/index.php/TES4Edit_Cleaning_Guide"'
|
||||
|
||||
- name: x117race.esm
|
||||
tag:
|
||||
- Hair
|
||||
|
||||
- name: Chocolate Elves.esm
|
||||
tag:
|
||||
- NpcFaces
|
||||
- Hair
|
||||
- Eyes
|
||||
- R.Relations
|
||||
|
||||
- name: Independent High Elf Body (Replace)(v1.1).esm
|
||||
tag:
|
||||
- NpcFaces
|
||||
- Hair
|
||||
- Eyes
|
||||
- R.Relations
|
||||
|
||||
- name: p2p'sAshDraconian.esm
|
||||
tag:
|
||||
- NpcFaces
|
||||
- Hair
|
||||
- Eyes
|
||||
- R.Relations
|
||||
|
||||
- name: SPTDiverseGuards-Resources.esm
|
||||
msg:
|
||||
- condition: *oooCond
|
||||
type: say
|
||||
content: Probably not compatible with OOO. Untested.
|
||||
|
||||
- name: John's Leveled List Overhaul.esm
|
||||
tag:
|
||||
- Graphics
|
||||
|
||||
# I've just made up the OBME DLL name and version here for an example.
|
||||
- name: Diverse Magic Effects Resource.esm
|
||||
req:
|
||||
- name: *OBSE
|
||||
condition: if version("../obse_loader.exe", "0.0.19.0", >=)
|
||||
display: OBSE v19+
|
||||
- name: OBSE/Plugins/obme.dll
|
||||
condition: if version("../obse_loader.exe", "0.1.0.0", >=)
|
||||
display: OBME v1+
|
||||
@@ -0,0 +1,20 @@
|
||||
# BOSS Settings File
|
||||
# This file is written in YAML <http://www.yaml.org/>.
|
||||
# If you don't know YAML, just think of a normal ini file, but replace the
|
||||
# equals signs with colons followed by a space. No tabs allowed.
|
||||
|
||||
bEnableNetworking: true
|
||||
bUseOnlineCache: true
|
||||
bGetMetadataUpdates: true
|
||||
bPromptMetadataSubmit: true
|
||||
bAlwaysSubmitMetadata: true
|
||||
|
||||
sOnlineCacheURL: "http://better-oblivion-sorting-software.googlecode.com/svn/data/boss-nehrim/masterlist.txt"
|
||||
sMetadataURL: "http://better-oblivion-sorting-software.googlecode.com/svn/data/boss-nehrim/masterlist.txt"
|
||||
sVersionCheckerURL: "http://better-oblivion-sorting-software.googlecode.com/svn/data/boss-nehrim/masterlist.txt"
|
||||
|
||||
sGame: auto # auto, oblivion, skyrim, fallout3, falloutnv
|
||||
sLastGame: auto # auto, oblivion, skyrim, fallout3, falloutnv
|
||||
iDebugVerbosity: 0 # 0, 1, 2, 3. Logging takes place if > 0.
|
||||
bDoTrialRun: false
|
||||
sLanguage: eng # An ISO 639-3 language string.
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#if _WIN32 || _WIN64
|
||||
# include <Windows.h>
|
||||
# include <Shlobj.h>
|
||||
@@ -116,6 +118,15 @@ namespace boss {
|
||||
return GamePath() / pluginsFolderName;
|
||||
}
|
||||
|
||||
bool Game::IsActive(const std::string& plugin) const {
|
||||
if (activePlugins.empty()) {
|
||||
//Use libloadorder to fetch the active plugins list. Fill the set
|
||||
//with the lowercased filenames.
|
||||
}
|
||||
|
||||
return activePlugins.find(boost::to_lower_copy(plugin)) != activePlugins.end();
|
||||
}
|
||||
|
||||
void Game::CreateBOSSGameFolder() {
|
||||
//Make sure that the BOSS game path exists.
|
||||
try {
|
||||
|
||||
+12
@@ -24,7 +24,12 @@
|
||||
#ifndef __BOSS_GAME__
|
||||
#define __BOSS_GAME__
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
namespace boss {
|
||||
|
||||
@@ -44,6 +49,12 @@ namespace boss {
|
||||
|
||||
//Creates directory in BOSS folder for BOSS's game-specific files.
|
||||
void CreateBOSSGameFolder();
|
||||
|
||||
bool IsActive(const std::string& plugin) const;
|
||||
|
||||
//Caches for condition results, active plugins and CRCs.
|
||||
boost::unordered_map<std::string, bool> conditionCache; //Holds lowercased strings.
|
||||
boost::unordered_map<std::string, uint32_t> crcCache; //Holds lowercased strings.
|
||||
private:
|
||||
uint32_t id;
|
||||
std::string name;
|
||||
@@ -55,6 +66,7 @@ namespace boss {
|
||||
std::string pluginsFolderName;
|
||||
|
||||
boost::filesystem::path gamePath; //Path to the game's folder.
|
||||
boost::unordered_set<std::string> activePlugins; //Holds lowercased strings.
|
||||
|
||||
//Can be used to get the location of the LOCALAPPDATA folder (and its Windows XP equivalent).
|
||||
boost::filesystem::path GetLocalAppDataPath();
|
||||
|
||||
+48
-38
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include "helpers.h"
|
||||
#include "plugin/ModFormat.h"
|
||||
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@@ -78,15 +79,15 @@ namespace boss {
|
||||
}
|
||||
|
||||
//Converts an integer to a string using BOOST's Spirit.Karma, which is apparently a lot faster than a stringstream conversion...
|
||||
std::string IntToString(const uint32_t n) {
|
||||
std::string IntToString(const int n) {
|
||||
string out;
|
||||
back_insert_iterator<string> sink(out);
|
||||
karma::generate(sink,karma::upper[karma::uint_],n);
|
||||
karma::generate(sink,karma::upper[karma::int_],n);
|
||||
return out;
|
||||
}
|
||||
|
||||
//Converts an integer to a hex string using BOOST's Spirit.Karma, which is apparently a lot faster than a stringstream conversion...
|
||||
std::string IntToHexString(const uint32_t n) {
|
||||
std::string IntToHexString(const int n) {
|
||||
string out;
|
||||
back_insert_iterator<string> sink(out);
|
||||
karma::generate(sink,karma::upper[karma::hex],n);
|
||||
@@ -156,53 +157,58 @@ namespace boss {
|
||||
|
||||
Version::Version(const fs::path file) {
|
||||
// LOG_TRACE("extracting version from '%s'", file.string().c_str());
|
||||
if (file.extension().string() == ".esm" || file.extension().string() == ".esp") {
|
||||
//Use libespm interface.
|
||||
verString = ReadHeader(file).Version;
|
||||
} else {
|
||||
#if _WIN32 || _WIN64
|
||||
DWORD dummy = 0;
|
||||
DWORD size = GetFileVersionInfoSize(file.wstring().c_str(), &dummy);
|
||||
DWORD dummy = 0;
|
||||
DWORD size = GetFileVersionInfoSize(file.wstring().c_str(), &dummy);
|
||||
|
||||
if (size > 0) {
|
||||
LPBYTE point = new BYTE[size];
|
||||
UINT uLen;
|
||||
VS_FIXEDFILEINFO *info;
|
||||
string ver;
|
||||
if (size > 0) {
|
||||
LPBYTE point = new BYTE[size];
|
||||
UINT uLen;
|
||||
VS_FIXEDFILEINFO *info;
|
||||
string ver;
|
||||
|
||||
GetFileVersionInfo(file.wstring().c_str(),0,size,point);
|
||||
GetFileVersionInfo(file.wstring().c_str(),0,size,point);
|
||||
|
||||
VerQueryValue(point,L"\\",(LPVOID *)&info,&uLen);
|
||||
VerQueryValue(point,L"\\",(LPVOID *)&info,&uLen);
|
||||
|
||||
DWORD dwLeftMost = HIWORD(info->dwFileVersionMS);
|
||||
DWORD dwSecondLeft = LOWORD(info->dwFileVersionMS);
|
||||
DWORD dwSecondRight = HIWORD(info->dwFileVersionLS);
|
||||
DWORD dwRightMost = LOWORD(info->dwFileVersionLS);
|
||||
DWORD dwLeftMost = HIWORD(info->dwFileVersionMS);
|
||||
DWORD dwSecondLeft = LOWORD(info->dwFileVersionMS);
|
||||
DWORD dwSecondRight = HIWORD(info->dwFileVersionLS);
|
||||
DWORD dwRightMost = LOWORD(info->dwFileVersionLS);
|
||||
|
||||
delete [] point;
|
||||
delete [] point;
|
||||
|
||||
verString = IntToString(dwLeftMost) + '.' + IntToString(dwSecondLeft) + '.' + IntToString(dwSecondRight) + '.' + IntToString(dwRightMost);
|
||||
}
|
||||
verString = IntToString(dwLeftMost) + '.' + IntToString(dwSecondLeft) + '.' + IntToString(dwSecondRight) + '.' + IntToString(dwRightMost);
|
||||
}
|
||||
#else
|
||||
// ensure filename has no quote characters in it to avoid command injection attacks
|
||||
if (string::npos == file.string().find('"')) {
|
||||
// LOG_WARN("filename has embedded quotes; skipping to avoid command injection: '%s'", file.string().c_str());
|
||||
// } else {
|
||||
// command mostly borrowed from the gnome-exe-thumbnailer.sh script
|
||||
// wrestool is part of the icoutils package
|
||||
string cmd = "wrestool --extract --raw --type=version \"" + file.string() + "\" | tr '\\0, ' '\\t.\\0' | sed 's/\\t\\t/_/g' | tr -c -d '[:print:]' | sed -r 's/.*Version[^0-9]*([0-9]+(\\.[0-9]+)+).*/\\1/'";
|
||||
// ensure filename has no quote characters in it to avoid command injection attacks
|
||||
if (string::npos == file.string().find('"')) {
|
||||
// LOG_WARN("filename has embedded quotes; skipping to avoid command injection: '%s'", file.string().c_str());
|
||||
// } else {
|
||||
// command mostly borrowed from the gnome-exe-thumbnailer.sh script
|
||||
// wrestool is part of the icoutils package
|
||||
string cmd = "wrestool --extract --raw --type=version \"" + file.string() + "\" | tr '\\0, ' '\\t.\\0' | sed 's/\\t\\t/_/g' | tr -c -d '[:print:]' | sed -r 's/.*Version[^0-9]*([0-9]+(\\.[0-9]+)+).*/\\1/'";
|
||||
|
||||
FILE *fp = popen(cmd.c_str(), "r");
|
||||
FILE *fp = popen(cmd.c_str(), "r");
|
||||
|
||||
// read out the version string
|
||||
static const uint32_t BUFSIZE = 32;
|
||||
char buf[BUFSIZE];
|
||||
if (NULL != fgets(buf, BUFSIZE, fp)) {
|
||||
/* LOG_DEBUG("failed to extract version from '%s'", file.string().c_str());
|
||||
// read out the version string
|
||||
static const uint32_t BUFSIZE = 32;
|
||||
char buf[BUFSIZE];
|
||||
if (NULL != fgets(buf, BUFSIZE, fp)) {
|
||||
/* LOG_DEBUG("failed to extract version from '%s'", file.string().c_str());
|
||||
}
|
||||
else {
|
||||
*/ verString = string(buf);
|
||||
// LOG_DEBUG("extracted version from '%s': %s", file.string().c_str(), retVal.c_str());
|
||||
}
|
||||
pclose(fp);
|
||||
}
|
||||
else {
|
||||
*/ verString = string(buf);
|
||||
// LOG_DEBUG("extracted version from '%s': %s", file.string().c_str(), retVal.c_str());
|
||||
}
|
||||
pclose(fp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
string Version::AsString() const {
|
||||
@@ -254,6 +260,10 @@ namespace boss {
|
||||
return (*this == ver || *this > ver);
|
||||
}
|
||||
|
||||
bool Version::operator <= (Version ver) {
|
||||
return (*this == ver || *this < ver);
|
||||
}
|
||||
|
||||
bool Version::operator == (Version ver) {
|
||||
return (verString == ver.AsString());
|
||||
}
|
||||
|
||||
+4
-2
@@ -28,6 +28,7 @@
|
||||
#ifndef __BOSS_HELPERS__
|
||||
#define __BOSS_HELPERS__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
@@ -42,10 +43,10 @@ namespace boss {
|
||||
uint32_t GetCrc32(const fs::path& filename);
|
||||
|
||||
//Converts an integer to a string using BOOST's Spirit.Karma. Faster than a stringstream conversion.
|
||||
std::string IntToString(const uint32_t n);
|
||||
std::string IntToString(const int n);
|
||||
|
||||
//Converts an integer to a hex string using BOOST's Spirit.Karma. Faster than a stringstream conversion.
|
||||
std::string IntToHexString(const uint32_t n);
|
||||
std::string IntToHexString(const int n);
|
||||
|
||||
//Converts a boolean to a string representation (true/false)
|
||||
std::string BoolToString(const bool b);
|
||||
@@ -71,6 +72,7 @@ namespace boss {
|
||||
bool operator > (Version);
|
||||
bool operator < (Version);
|
||||
bool operator >= (Version);
|
||||
bool operator <= (Version);
|
||||
bool operator == (Version);
|
||||
bool operator != (Version);
|
||||
};
|
||||
|
||||
+8
-7
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "metadata.h"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -188,37 +189,37 @@ namespace boss {
|
||||
tags = t;
|
||||
}
|
||||
|
||||
void Plugin::EvalAllConditions(const boost::filesystem::path& gamePath) {
|
||||
void Plugin::EvalAllConditions(boss::Game& game) {
|
||||
for (list<File>::iterator it = loadAfter.begin(); it != loadAfter.end();) {
|
||||
if (!it->EvalCondition(gamePath))
|
||||
if (!it->EvalCondition(game))
|
||||
it = loadAfter.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
for (list<File>::iterator it = requirements.begin(); it != requirements.end();) {
|
||||
if (!it->EvalCondition(gamePath))
|
||||
if (!it->EvalCondition(game))
|
||||
it = requirements.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
for (set<File, file_comp>::iterator it = incompatibilities.begin(); it != incompatibilities.end();) {
|
||||
if (!it->EvalCondition(gamePath))
|
||||
if (!it->EvalCondition(game))
|
||||
incompatibilities.erase(it++);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
for (list<Message>::iterator it = messages.begin(); it != messages.end();) {
|
||||
if (!it->EvalCondition(gamePath))
|
||||
if (!it->EvalCondition(game))
|
||||
it = messages.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
for (list<Tag>::iterator it = tags.begin(); it != tags.end();) {
|
||||
if (!it->EvalCondition(gamePath))
|
||||
if (!it->EvalCondition(game))
|
||||
it = tags.erase(it++);
|
||||
else
|
||||
++it;
|
||||
@@ -230,6 +231,6 @@ namespace boss {
|
||||
}
|
||||
|
||||
bool Plugin::IsRegexPlugin() const {
|
||||
return name.substr(name.length()-5) == "\\.esp" || name.substr(name.length()-5) == "\\.esm";
|
||||
return boost::iends_with(name, "\\.esm") || boost::iends_with(name, "\\.esp");
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -23,6 +23,8 @@
|
||||
#ifndef __BOSS_METADATA__
|
||||
#define __BOSS_METADATA__
|
||||
|
||||
#include "game.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <set>
|
||||
@@ -38,7 +40,7 @@ namespace boss {
|
||||
ConditionalData(const std::string& condition, const std::string& data);
|
||||
|
||||
bool IsConditional() const;
|
||||
bool EvalCondition(const boost::filesystem::path& gamePath) const;
|
||||
bool EvalCondition(boss::Game& game) const;
|
||||
|
||||
std::string Condition() const;
|
||||
std::string Data() const;
|
||||
@@ -124,7 +126,7 @@ namespace boss {
|
||||
void Messages(const std::list<Message>& messages);
|
||||
void Tags(const std::list<Tag>& tags);
|
||||
|
||||
void EvalAllConditions(const boost::filesystem::path& gamePath);
|
||||
void EvalAllConditions(boss::Game& game);
|
||||
bool HasNameOnly() const;
|
||||
bool IsRegexPlugin() const;
|
||||
private:
|
||||
|
||||
+135
-50
@@ -29,10 +29,14 @@
|
||||
#endif
|
||||
|
||||
#include "metadata.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/phoenix_core.hpp>
|
||||
#include <boost/spirit/include/phoenix_operator.hpp>
|
||||
@@ -279,50 +283,16 @@ namespace YAML {
|
||||
|
||||
namespace boss {
|
||||
|
||||
/* Conditional parser
|
||||
///////////////////////////////
|
||||
// Condition parser/evaluator
|
||||
///////////////////////////////
|
||||
|
||||
Expression is of the form:
|
||||
|
||||
condition = keyword type
|
||||
|
||||
expression = -'(' condition (operator condition)* -')' operator
|
||||
|
||||
comp_exp = expression (operator expression)*
|
||||
-'(' keyword type (operator -'(' keyword type -')' )*
|
||||
|
||||
keyword = if | ifnot
|
||||
operator = and | or
|
||||
type = file(...) | checksum(...) | version(...) | active(...)
|
||||
|
||||
'and' takes precedence over 'or', and brackets can also be used to indicate
|
||||
overriding precedences.
|
||||
|
||||
Split string up into sub-strings according to the bracketing if present, then
|
||||
according to operators, until each sub-string only contains one condition.
|
||||
|
||||
{
|
||||
expression =
|
||||
term
|
||||
>> *(string("or") >> term)
|
||||
;
|
||||
|
||||
term =
|
||||
factor
|
||||
>> *(string("and") >> factor)
|
||||
|
||||
factor =
|
||||
condition
|
||||
| '(' >> expression >> ')'
|
||||
|
|
||||
|
||||
condition = keyword >> type
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
/* Still need to add support for bracketing and evaluation of the compound
|
||||
conditions. */
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
namespace unicode = boost::spirit::unicode;
|
||||
namespace phoenix = boost::phoenix;
|
||||
|
||||
template<typename Iterator, typename Skipper>
|
||||
class condition_grammar : public qi::grammar<Iterator, bool(), Skipper> {
|
||||
@@ -330,7 +300,14 @@ namespace boss {
|
||||
condition_grammar() : condition_grammar::base_type(expression, "condition grammar") {
|
||||
|
||||
expression =
|
||||
condition;
|
||||
andStatement
|
||||
>> *(qi::lit("or") >> andStatement)
|
||||
;
|
||||
|
||||
andStatement =
|
||||
condition
|
||||
>> *(qi::lit("and") >> condition)
|
||||
;
|
||||
|
||||
condition =
|
||||
( qi::lit("if") >> type ) [qi::labels::_val = qi::labels::_1]
|
||||
@@ -338,38 +315,144 @@ namespace boss {
|
||||
;
|
||||
|
||||
type =
|
||||
( "file(" > quotedStr > ')' ) [qi::labels::_val = true]
|
||||
| ( "checksum(" > quotedStr > ',' > +unicode::xdigit > ')' ) [qi::labels::_val = true]
|
||||
| ( "version(" > quotedStr > ',' > quotedStr > ',' > unicode::char_ > ')' ) [qi::labels::_val = true]
|
||||
| ( "active(" > quotedStr > ')' ) [qi::labels::_val = true]
|
||||
( "file(" > quotedStr > ')' ) [phoenix::bind(&condition_grammar::CheckFile, this, qi::labels::_val, qi::labels::_1)]
|
||||
| ( "checksum(" > quotedStr > ',' > qi::hex > ')' ) [phoenix::bind(&condition_grammar::CheckSum, this, qi::labels::_val, qi::labels::_1, qi::labels::_2)]
|
||||
| ( "version(" > quotedStr > ',' > quotedStr > ',' > unicode::char_ > ')' ) [phoenix::bind(&condition_grammar::CheckVersion, this, qi::labels::_val, qi::labels::_1, qi::labels::_2, qi::labels::_3)]
|
||||
| ( "active(" > quotedStr > ')' ) [phoenix::bind(&condition_grammar::CheckActive, this, qi::labels::_val, qi::labels::_1)]
|
||||
;
|
||||
|
||||
quotedStr = '"' > +(unicode::char_ - '"') > '"';
|
||||
|
||||
/* Need to add error handlers and actual type evaluation, then start on
|
||||
compound conditional parsing. Need game path support. */
|
||||
expression.name("expression");
|
||||
condition.name("condition");
|
||||
type.name("condition type");
|
||||
quotedStr.name("quoted string");
|
||||
|
||||
qi::on_error<qi::fail>(expression, phoenix::bind(&condition_grammar::SyntaxError, this, qi::labels::_1, qi::labels::_2, qi::labels::_3, qi::labels::_4));
|
||||
qi::on_error<qi::fail>(condition, phoenix::bind(&condition_grammar::SyntaxError, this, qi::labels::_1, qi::labels::_2, qi::labels::_3, qi::labels::_4));
|
||||
qi::on_error<qi::fail>(type, phoenix::bind(&condition_grammar::SyntaxError, this, qi::labels::_1, qi::labels::_2, qi::labels::_3, qi::labels::_4));
|
||||
qi::on_error<qi::fail>(quotedStr, phoenix::bind(&condition_grammar::SyntaxError, this, qi::labels::_1, qi::labels::_2, qi::labels::_3, qi::labels::_4));
|
||||
}
|
||||
|
||||
void SetGame(boss::Game& g) {
|
||||
game = &g;
|
||||
}
|
||||
|
||||
private:
|
||||
qi::rule<Iterator, bool(), Skipper> expression, condition, type;
|
||||
qi::rule<Iterator, std::string()> quotedStr;
|
||||
|
||||
boss::Game * game;
|
||||
|
||||
//Eval's regex and exact paths. Check for files and ghosted plugins.
|
||||
void CheckFile(bool& result, const std::string& file) {
|
||||
if (boost::contains(file, "\\.")) { //Regex. Only supports filenames right now.
|
||||
|
||||
result = false;
|
||||
boost::regex regex;
|
||||
try {
|
||||
regex = boost::regex(file, boost::regex::extended|boost::regex::icase);
|
||||
} catch (boost::regex_error e) {
|
||||
throw std::runtime_error("The regex string \"" + file + "\" is invalid.");
|
||||
// LOG_ERROR("\"%s\" is not a valid regular expression. Item skipped.", reg.c_str());
|
||||
}
|
||||
for (fs::directory_iterator itr(game->DataPath()); itr != fs::directory_iterator(); ++itr) {
|
||||
if (fs::is_regular_file(itr->status())) {
|
||||
if (boost::regex_match(itr->path().filename().string(), regex)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Eval's regex and exact paths.
|
||||
bool FileExists(bool& result, std::string file);
|
||||
} else if (IsPlugin(file))
|
||||
result = boost::filesystem::exists(game->DataPath() / file) || boost::filesystem::exists(game->DataPath() / (file + ".ghost"));
|
||||
else
|
||||
result = boost::filesystem::exists(game->DataPath() / file);
|
||||
}
|
||||
|
||||
void CheckSum(bool& result, const std::string& file, const uint32_t checksum) {
|
||||
uint32_t crc;
|
||||
boost::unordered_map<std::string,uint32_t>::iterator it = game->crcCache.find(boost::to_lower_copy(file));
|
||||
|
||||
if (it != game->crcCache.end())
|
||||
crc = it->second;
|
||||
else {
|
||||
if (boost::filesystem::exists(game->DataPath() / file))
|
||||
crc = GetCrc32(game->DataPath() / file);
|
||||
else if (IsPlugin(file) && boost::filesystem::exists(game->DataPath() / (file + ".ghost")))
|
||||
crc = GetCrc32(game->DataPath() / (file + ".ghost"));
|
||||
else {
|
||||
result = false;
|
||||
return;
|
||||
}
|
||||
|
||||
game->crcCache.emplace(boost::to_lower_copy(file), crc);
|
||||
}
|
||||
|
||||
result = checksum == crc;
|
||||
}
|
||||
|
||||
void CheckVersion(bool& result, const std::string& file, const std::string& version, const char comparator) {
|
||||
|
||||
CheckFile(result, file);
|
||||
if (!result) {
|
||||
if (comparator == '<')
|
||||
result = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Version givenVersion = Version(version);
|
||||
Version trueVersion = Version(game->DataPath() / file);
|
||||
|
||||
switch (comparator) {
|
||||
case '>':
|
||||
if (trueVersion <= givenVersion)
|
||||
result = false;
|
||||
break;
|
||||
case '<':
|
||||
if (trueVersion >= givenVersion)
|
||||
result = false;
|
||||
break;
|
||||
case '=':
|
||||
if (trueVersion != givenVersion)
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckActive(bool& result, const std::string& file) {
|
||||
result = game->IsActive(file);
|
||||
}
|
||||
|
||||
bool IsPlugin(const std::string& file) {
|
||||
return boost::iends_with(file, ".esm") || boost::iends_with(file, ".esp");
|
||||
}
|
||||
|
||||
void SyntaxError(Iterator const& /*first*/, Iterator const& last, Iterator const& errorpos, boost::spirit::info const& what) {
|
||||
|
||||
std::string context(errorpos, min(errorpos +50, last));
|
||||
boost::trim(context);
|
||||
|
||||
throw std::runtime_error("Error parsing condition at \"" + context + "\", expected \"" + what.tag + "\"");
|
||||
}
|
||||
};
|
||||
|
||||
bool ConditionalData::EvalCondition(const boost::filesystem::path& gamePath) const {
|
||||
bool ConditionalData::EvalCondition(boss::Game& game) const {
|
||||
if (condition.empty())
|
||||
return true;
|
||||
|
||||
boost::unordered_map<std::string, bool>::const_iterator it = game.conditionCache.find(boost::to_lower_copy(condition));
|
||||
if (it != game.conditionCache.end())
|
||||
return it->second;
|
||||
|
||||
condition_grammar<std::string::const_iterator, qi::space_type> grammar;
|
||||
qi::space_type skipper;
|
||||
std::string::const_iterator begin, end;
|
||||
bool eval;
|
||||
|
||||
grammar.SetGame(game);
|
||||
begin = condition.begin();
|
||||
end = condition.end();
|
||||
|
||||
@@ -378,6 +461,8 @@ namespace boss {
|
||||
if (!r || begin != end)
|
||||
throw std::runtime_error("Parsing of condition \"" + condition + "\" failed!");
|
||||
|
||||
game.conditionCache.emplace(boost::to_lower_copy(condition), eval);
|
||||
|
||||
return eval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/* BOSS
|
||||
|
||||
A "one-click" program for users that quickly optimises and avoids
|
||||
detrimental conflicts in their TES IV: Oblivion, Nehrim - At Fate's Edge,
|
||||
TES V: Skyrim, Fallout 3 and Fallout: New Vegas mod load orders.
|
||||
|
||||
Copyright (C) 2009-2012 BOSS Development Team.
|
||||
|
||||
This file is part of BOSS.
|
||||
|
||||
BOSS is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
BOSS is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with BOSS. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
$Revision: 2488 $, $Date: 2011-03-27 14:31:33 +0100 (Sun, 27 Mar 2011) $
|
||||
*/
|
||||
|
||||
|
||||
#include "Types.h"
|
||||
#include "ModFormat.h"
|
||||
#include "VersionRegex.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
|
||||
namespace boss {
|
||||
using namespace std;
|
||||
|
||||
using boost::algorithm::trim_copy;
|
||||
using boost::regex;
|
||||
|
||||
//
|
||||
// string ParseVersion(string&):
|
||||
// - Tries to extract the version string value from the given text,
|
||||
// using the above defined regexes to do the dirty work.
|
||||
//
|
||||
string ParseVersion(const string& text){
|
||||
|
||||
string::const_iterator begin, end;
|
||||
|
||||
begin = text.begin();
|
||||
end = text.end();
|
||||
|
||||
for(int i = 0; regex* re = version_checks[i]; i++) {
|
||||
|
||||
smatch what;
|
||||
while (regex_search(begin, end, what, *re)) {
|
||||
|
||||
if (what.empty()){
|
||||
continue;
|
||||
}
|
||||
|
||||
ssub_match match = what[1];
|
||||
|
||||
if (!match.matched) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return trim_copy(string(match.first, match.second));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return string();
|
||||
}
|
||||
|
||||
//
|
||||
// string ReadString(pointer&, maxsize):
|
||||
// - Reads a consecutive array of charactes up to maxsize length and
|
||||
// returns them as a new string.
|
||||
//
|
||||
string ReadString(char*& bufptr, ushort size){
|
||||
string data;
|
||||
|
||||
data.reserve(size + 1);
|
||||
while (char c = *bufptr++) {
|
||||
data.append(1, c);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//
|
||||
// T Peek<T>(pointer&):
|
||||
// - Peeks into the received buffer and returns the value pointed
|
||||
// converting it to the type T.
|
||||
//
|
||||
template <typename T>
|
||||
T Peek(char* buffer) {
|
||||
return *reinterpret_cast<T*>(buffer);
|
||||
}
|
||||
|
||||
//
|
||||
// T Read<T>(pointer&):
|
||||
// - Tries to extract a value of the specified type T from the
|
||||
// received buffer, incrementing the pointer to point past the readen
|
||||
// value.
|
||||
//
|
||||
template <typename T>
|
||||
inline T Read(char*& buffer) {
|
||||
T value = Peek<T>(buffer);
|
||||
buffer += sizeof(T);
|
||||
return value;
|
||||
}
|
||||
|
||||
//-
|
||||
// ModHeader ReadHeader(string):
|
||||
// - Parses the mod file contents and extract the header information
|
||||
// returning the most important data using a ModHeader struct.
|
||||
// --> see:
|
||||
// http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format,
|
||||
//
|
||||
// and in particular this link:
|
||||
// http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format/TES4
|
||||
//
|
||||
|
||||
bool IsPluginMaster(boost::filesystem::path filename) {
|
||||
char buffer[MAXLENGTH];
|
||||
char* bufptr = buffer;
|
||||
ModHeader modHeader;
|
||||
|
||||
if (filename.empty())
|
||||
return false;
|
||||
|
||||
ifstream file(filename.native().c_str(), ios_base::binary | ios_base::in);
|
||||
|
||||
if (file.bad())
|
||||
//throw boss_error(BOSS_ERROR_FILE_READ_FAIL, filename.string());
|
||||
return false;
|
||||
|
||||
// Reads the first MAXLENGTH bytes into the buffer
|
||||
file.read(&buffer[0], sizeof(buffer));
|
||||
|
||||
// Check for the 'magic' marker at start
|
||||
if (Read<uint>(bufptr) != Record::TES4){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next field is the total header size
|
||||
/*uint headerSize =*/ Read<uint>(bufptr);
|
||||
|
||||
// Next comes the header record Flags
|
||||
uint flags = Read<uint>(bufptr);
|
||||
|
||||
// LSb of this record's flags is used to indicate if the
|
||||
// mod is a master or a plugin
|
||||
return ((flags & 0x1) != 0);
|
||||
}
|
||||
|
||||
ModHeader ReadHeader(boost::filesystem::path filename) {
|
||||
char buffer[MAXLENGTH];
|
||||
char* bufptr = buffer;
|
||||
ModHeader modHeader;
|
||||
ifstream file(filename.native().c_str(), ios_base::binary | ios_base::in);
|
||||
|
||||
modHeader.Name = filename.string();
|
||||
|
||||
// Reads the first MAXLENGTH bytes into the buffer
|
||||
file.read(&buffer[0], sizeof(buffer));
|
||||
|
||||
// Check for the 'magic' marker at start
|
||||
if (Read<uint>(bufptr) != Record::TES4){
|
||||
return modHeader;
|
||||
}
|
||||
|
||||
// Next field is the total header size
|
||||
/*uint headerSize =*/ Read<uint>(bufptr);
|
||||
|
||||
// Next comes the header record Flags
|
||||
uint flags = Read<uint>(bufptr);
|
||||
|
||||
// LSb of this record's flags is used to indicate if the
|
||||
// mod is a master or a plugin
|
||||
modHeader.IsMaster = (flags & 0x1) != 0;
|
||||
|
||||
// Next comes the FormID...
|
||||
/*uint formId =*/ Read<uint>(bufptr); // skip formID
|
||||
|
||||
// ...and extra flags
|
||||
/*uint flags2 =*/ Read<uint>(bufptr); // skip flags2
|
||||
|
||||
// Here the Header record starts, check for its signature 'HEDR'
|
||||
if (Read<uint>(bufptr) != Record::HEDR){
|
||||
return modHeader;
|
||||
}
|
||||
|
||||
// HEDR record has fields: DataSize, Version (0.8 o 1.0), Record Count
|
||||
// and Next Object Id
|
||||
/*ushort dataSize =*/ Read<ushort>(bufptr);
|
||||
/*float version =*/ Read<float>(bufptr);
|
||||
/*int numRecords =*/ Read<int>(bufptr);
|
||||
/*uint nextObjId =*/ Read<uint>(bufptr);
|
||||
|
||||
// Then comes the sub-records
|
||||
uint signature = Read<uint>(bufptr);
|
||||
|
||||
// skip optional records
|
||||
bool loop = true;
|
||||
while (loop){
|
||||
switch (signature)
|
||||
{
|
||||
case Record::OFST:
|
||||
case Record::DELE:
|
||||
bufptr += Read<ushort>(bufptr); // skip
|
||||
signature = Read<uint>(bufptr);
|
||||
break;
|
||||
|
||||
// extract author name, if present
|
||||
case Record::CNAM:
|
||||
modHeader.Author = ReadString(bufptr, Read<ushort>(bufptr));
|
||||
signature = Read<uint>(bufptr);
|
||||
break;
|
||||
|
||||
// extract description and version, if present
|
||||
case Record::SNAM:
|
||||
modHeader.Description = ReadString(bufptr, Read<ushort>(bufptr));
|
||||
modHeader.Version = ParseVersion(modHeader.Description);
|
||||
signature = Read<uint>(bufptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
loop = false;
|
||||
}
|
||||
}
|
||||
|
||||
// We should have all the required information.
|
||||
return modHeader;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* BOSS
|
||||
|
||||
A "one-click" program for users that quickly optimises and avoids
|
||||
detrimental conflicts in their TES IV: Oblivion, Nehrim - At Fate's Edge,
|
||||
TES V: Skyrim, Fallout 3 and Fallout: New Vegas mod load orders.
|
||||
|
||||
Copyright (C) 2009-2012 BOSS Development Team.
|
||||
|
||||
This file is part of BOSS.
|
||||
|
||||
BOSS is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
BOSS is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with BOSS. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
$Revision: 2488 $, $Date: 2011-03-27 14:31:33 +0100 (Sun, 27 Mar 2011) $
|
||||
*/
|
||||
|
||||
#ifndef __SUPPORT_MODFORMAT__HPP__
|
||||
#define __SUPPORT_MODFORMAT__HPP__
|
||||
|
||||
#include "Types.h"
|
||||
#include <cstring>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
||||
namespace boss {
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Structure for grouping the information gathered from each mod's header.
|
||||
struct ModHeader {
|
||||
string Name;
|
||||
string Description;
|
||||
string Author;
|
||||
string Version;
|
||||
bool IsMaster;
|
||||
};
|
||||
|
||||
|
||||
struct Record {
|
||||
static const ulong TES4 = '4SET';
|
||||
static const ulong HEDR = 'RDEH';
|
||||
static const ulong OFST = 'TSFO';
|
||||
static const ulong DELE = 'ELED';
|
||||
static const ulong CNAM = 'MANC';
|
||||
static const ulong SNAM = 'MANS';
|
||||
};
|
||||
|
||||
ModHeader ReadHeader(boost::filesystem::path filename);
|
||||
|
||||
bool IsPluginMaster(boost::filesystem::path filename); //Shorter version of the above, to only get master flag.
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/* BOSS
|
||||
|
||||
A "one-click" program for users that quickly optimises and avoids
|
||||
detrimental conflicts in their TES IV: Oblivion, Nehrim - At Fate's Edge,
|
||||
TES V: Skyrim, Fallout 3 and Fallout: New Vegas mod load orders.
|
||||
|
||||
Copyright (C) 2009-2012 BOSS Development Team.
|
||||
|
||||
This file is part of BOSS.
|
||||
|
||||
BOSS is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
BOSS is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with BOSS. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
$Revision: 1679 $, $Date: 2010-10-17 20:41:49 +0100 (Sun, 17 Oct 2010) $
|
||||
*/
|
||||
|
||||
#ifndef __SUPPORT_TYPES__HPP__
|
||||
#define __SUPPORT_TYPES__HPP__
|
||||
|
||||
|
||||
namespace boss {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Common type definitions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned short ushort;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Constants
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// An arbitrary large number. Controls the size of some buffers used to read data from files.
|
||||
const ulong MAXLENGTH = 4096UL;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
/* BOSS
|
||||
|
||||
A "one-click" program for users that quickly optimises and avoids
|
||||
detrimental conflicts in their TES IV: Oblivion, Nehrim - At Fate's Edge,
|
||||
TES V: Skyrim, Fallout 3 and Fallout: New Vegas mod load orders.
|
||||
|
||||
Copyright (C) 2009-2012 BOSS Development Team.
|
||||
|
||||
This file is part of BOSS.
|
||||
|
||||
BOSS is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
BOSS is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with BOSS. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
$Revision: 1681 $, $Date: 2010-10-17 21:01:25 +0100 (Sun, 17 Oct 2010) $
|
||||
*/
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
|
||||
namespace boss {
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
/// REGEX expression definition
|
||||
/// Each expression is composed of three parts:
|
||||
/// 1. The marker string "version", "ver", "rev", "v" or "r"
|
||||
/// 2. The version string itself.
|
||||
|
||||
const char* regex1 =
|
||||
"^(?:\\bversion\\b[ ]*(?:[:.\\-]?)|\\brevision\\b(?:[:.\\-]?))[ ]*"
|
||||
"((?:alpha|beta|test|debug)?\\s*[-0-9a-zA-Z._+]+\\s*(?:alpha|beta|test|debug)?\\s*(?:[0-9]*))$"
|
||||
;
|
||||
|
||||
const char* regex2 =
|
||||
"(?:\\bversion\\b(?:[ :]?)|\\brevision\\b(?:[:.\\-]?))[ ]*"
|
||||
"([0-9][-0-9a-zA-Z._]+\\+?)"
|
||||
;
|
||||
|
||||
const char* regex3 =
|
||||
"(?:\\bver(?:[:.]?)|\\brev(?:[:.]?))\\s*"
|
||||
"([0-9][-0-9a-zA-Z._]*\\+?)"
|
||||
;
|
||||
|
||||
// Matches "Updated: <date>" for the Bashed patch
|
||||
const char* regex4 =
|
||||
"(?:Updated:)\\s*"
|
||||
"([-0-9aAmMpP/ :]+)$"
|
||||
;
|
||||
|
||||
// Matches isolated versions as last resort
|
||||
const char* regex5 =
|
||||
"(?:(?:\\bv|\\br)(?:\\s?)(?:[-.:])?(?:\\s*))"
|
||||
"((?:(?:\\balpha\\b)?|(?:\\bbeta\\b)?)\\s*[0-9][-0-9a-zA-Z._]*\\+?)"
|
||||
;
|
||||
|
||||
// Matches isolated versions as last resort
|
||||
const char* regex6 =
|
||||
"((?:(?:\\balpha\\b)?|(?:\\bbeta\\b)?)\\s*\\b[0-9][-0-9a-zA-Z._]*\\+?)$"
|
||||
;
|
||||
|
||||
const char* regex7 =
|
||||
"(^\\bmark\\b\\s*\\b[IVX0-9][-0-9a-zA-Z._+]*\\s*(?:alpha|beta|test|debug)?\\s*(?:[0-9]*)?)$"
|
||||
;
|
||||
|
||||
/// Array used to try each of the expressions defined above using
|
||||
/// an iteration for each of them.
|
||||
regex* version_checks[] = {
|
||||
new regex(regex1, regex::icase),
|
||||
new regex(regex2, regex::icase),
|
||||
new regex(regex3, regex::icase),
|
||||
new regex(regex4, regex::icase),
|
||||
new regex(regex5, regex::icase), //This incorrectly identifies "OBSE v19" where 19 is any integer.
|
||||
new regex(regex6, regex::icase), //This is responsible for metallicow's false positive.
|
||||
new regex(regex7, regex::icase),
|
||||
0
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* BOSS
|
||||
|
||||
A "one-click" program for users that quickly optimises and avoids
|
||||
detrimental conflicts in their TES IV: Oblivion, Nehrim - At Fate's Edge,
|
||||
TES V: Skyrim, Fallout 3 and Fallout: New Vegas mod load orders.
|
||||
|
||||
Copyright (C) 2009-2012 BOSS Development Team.
|
||||
|
||||
This file is part of BOSS.
|
||||
|
||||
BOSS is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
BOSS is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with BOSS. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
$Revision: 1681 $, $Date: 2010-10-17 21:01:25 +0100 (Sun, 17 Oct 2010) $
|
||||
*/
|
||||
|
||||
#ifndef __SUPPORT_VERSIONREGEX__HPP__
|
||||
#define __SUPPORT_VERSIONREGEX__HPP__
|
||||
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
|
||||
namespace boss {
|
||||
|
||||
using namespace boost;
|
||||
|
||||
/// Array used to try each of the expressions defined above using
|
||||
/// an iteration for each of them.
|
||||
extern regex* version_checks[];
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user