From b1d1a5670b8ff19f3f25b314ea89eb467614106c Mon Sep 17 00:00:00 2001 From: Bruce Date: Tue, 21 Oct 2025 13:49:29 +0800 Subject: [PATCH] PriReader Update --- dlltest/main.cpp | 1 + pkgread/norstr.h | 7 + priread/localeex.h | 163 +++++ priread/nstring.h | 426 ++++++++++++ priread/prifile.h | 1146 ++++++++++++++++++++++++++++++- priread/priread.vcxproj | 2 + priread/priread.vcxproj.filters | 6 + 7 files changed, 1714 insertions(+), 37 deletions(-) create mode 100644 priread/localeex.h create mode 100644 priread/nstring.h diff --git a/dlltest/main.cpp b/dlltest/main.cpp index b24f3d4..1f3ccdf 100644 --- a/dlltest/main.cpp +++ b/dlltest/main.cpp @@ -187,6 +187,7 @@ struct section_header CHAR szIdentifier [16] = {0}; DWORD dwQualifier = 0; WORD wFlags = 0; + WORD wSectFlags = 0; DWORD dwLength = 0; DWORD dwPlaceholder1 = -1; // 0 }; diff --git a/pkgread/norstr.h b/pkgread/norstr.h index 53c1a24..98e8434 100644 --- a/pkgread/norstr.h +++ b/pkgread/norstr.h @@ -325,6 +325,9 @@ namespace std basic_nstring (const ct *pStr): base (pStr), default_upper (false), default_include_blank_in_str (false) {} basic_nstring (const base &str): base (str) {} basic_nstring (base &&str): base (std::move (str)) {} + basic_nstring (const ct *data, size_type count): base (data, count), default_upper (false), default_include_blank_in_str (false) {} + template basic_nstring (InputIt first, InputIt last) : base (first, last), default_upper (false), default_include_blank_in_str (false) {} + template basic_nstring (const ct (&arr) [N]) : base (arr, N) {} bool upper_default () const { return this->default_upper; } bool upper_default (bool value) { return this->default_upper = value; } bool include_blank_in_str_middle () const { return this->default_include_blank_in_str; } @@ -412,6 +415,10 @@ namespace std } template , typename AL = std::allocator > static std::basic_nstring to_nstring (std::basic_string &str) { return std::basic_nstring (str); } + template , typename AL = std::allocator > + static std::basic_nstring toupper (const std::basic_nstring &str) { return l0km::toupper (str); } + template , typename AL = std::allocator > + static std::basic_nstring tolower (const std::basic_nstring &str) { return l0km::tolower (str); } }; typedef basic_nstring nstring; diff --git a/priread/localeex.h b/priread/localeex.h new file mode 100644 index 0000000..b528d56 --- /dev/null +++ b/priread/localeex.h @@ -0,0 +1,163 @@ +#pragma once +#include +#include +static std::wstring StringToWString (const std::string &str, UINT codePage = CP_ACP) +{ + if (str.empty ()) return std::wstring (); + int len = MultiByteToWideChar (codePage, 0, str.c_str (), -1, nullptr, 0); + if (len == 0) return std::wstring (); + std::wstring wstr (len - 1, L'\0'); + MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len); + return wstr; +} + +#undef GetLocaleInfo +std::string GetLocaleInfoA (LCID code, LCTYPE type) +{ + char buf [LOCALE_NAME_MAX_LENGTH] = {0}; + GetLocaleInfoA (code, type, buf, LOCALE_NAME_MAX_LENGTH); + return buf; +} +std::wstring GetLocaleInfoW (LCID code, LCTYPE type) +{ + WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0}; + GetLocaleInfoW (code, type, buf, LOCALE_NAME_MAX_LENGTH); + return buf; +} +void GetLocaleInfo (LCID code, LCTYPE type, std::wstring &output) +{ + output = GetLocaleInfoW (code, type); +} +void GetLocaleInfo (LCID code, LCTYPE type, std::string &output) +{ + output = GetLocaleInfoA (code, type); +} +int GetLocaleInfoEx (std::wstring lpLocaleName, LCTYPE type, std::wstring &output) +{ + WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0}; + int res = GetLocaleInfoEx (lpLocaleName.c_str (), type, buf, LOCALE_NAME_MAX_LENGTH); + if (&output) output = std::wstring (buf); + return res; +} + +#undef SetLocaleInfo +BOOL SetLocaleInfoA (LCID code, LCTYPE type, const std::string &lcData) +{ + return SetLocaleInfoA (code, type, lcData.c_str ()); +} +BOOL SetLocaleInfoW (LCID code, LCTYPE type, const std::wstring &lcData) +{ + return SetLocaleInfoW (code, type, lcData.c_str ()); +} +BOOL SetLocaleInfo (LCID code, LCTYPE type, const std::wstring &lcData) +{ + return SetLocaleInfoW (code, type, lcData); +} +BOOL SetLocaleInfo (LCID code, LCTYPE type, const std::string &lcData) +{ + return SetLocaleInfoA (code, type, lcData); +} + +std::string GetLocaleRestrictedCodeFromLcidA (LCID lcid) +{ + return GetLocaleInfoA (lcid, 89); +} +std::wstring GetLocaleRestrictedCodeFromLcidW (LCID lcid) +{ + return GetLocaleInfoW (lcid, 89); +} +void GetLocaleRestrictedCodeFromLcid (LCID lcid, std::string &ret) +{ + ret = GetLocaleRestrictedCodeFromLcidA (lcid); +} +void GetLocaleRestrictedCodeFromLcid (LCID lcid, std::wstring &ret) +{ + ret = GetLocaleRestrictedCodeFromLcidW (lcid); +} + +std::string GetLocaleElaboratedCodeFromLcidA (LCID lcid) +{ + return GetLocaleInfoA (lcid, 90); +} +std::wstring GetLocaleElaboratedCodeFromLcidW (LCID lcid) +{ + return GetLocaleInfoW (lcid, 90); +} +void GetLocaleElaboratedCodeFromLcid (LCID lcid, std::wstring &ret) +{ + ret = GetLocaleElaboratedCodeFromLcidW (lcid); +} +void GetLocaleElaboratedCodeFromLcid (LCID lcid, std::string &ret) +{ + ret = GetLocaleElaboratedCodeFromLcidA (lcid); +} + +LCID LocaleCodeToLcidW (LPCWSTR localeCode) +{ + BYTE buf [LOCALE_NAME_MAX_LENGTH * sizeof (WCHAR)] = {0}; + int res = GetLocaleInfoEx (localeCode, LOCALE_RETURN_NUMBER | LOCALE_ILANGUAGE, (LPWSTR)buf, LOCALE_NAME_MAX_LENGTH); + LCID lcid = *((LCID *)buf); + return lcid; +} +LCID LocaleCodeToLcidA (LPCSTR localeCode) +{ + std::wstring lcWide = StringToWString (std::string (localeCode)); + return LocaleCodeToLcidW (lcWide.c_str ()); +} +LCID LocaleCodeToLcid (const std::wstring &loccode) +{ + return LocaleCodeToLcidW (loccode.c_str ()); +} +LCID LocaleCodeToLcid (const std::string &loccode) +{ + return LocaleCodeToLcidA (loccode.c_str ()); +} + +std::string GetLocaleRestrictedCodeA (LPCSTR lc) +{ + return GetLocaleInfoA (LocaleCodeToLcidA (lc), 89); +} +std::string GetLocaleRestrictedCodeA (const std::string &lc) +{ + return GetLocaleInfoA (LocaleCodeToLcidA (lc.c_str ()), 89); +} +std::wstring GetLocaleRestrictedCodeW (LPCWSTR lc) +{ + return GetLocaleInfoW (LocaleCodeToLcidW (lc), 89); +} +std::wstring GetLocaleRestrictedCodeW (const std::wstring &lc) +{ + return GetLocaleInfoW (LocaleCodeToLcidW (lc.c_str ()), 89); +} +std::wstring GetLocaleRestrictedCode (const std::wstring &lc) { return GetLocaleRestrictedCodeW (lc); } +std::string GetLocaleRestrictedCode (const std::string &lc) { return GetLocaleRestrictedCodeA (lc); } + +std::string GetLocaleElaboratedCodeA (LPCSTR lc) +{ + return GetLocaleInfoA (LocaleCodeToLcidA (lc), 90); +} +std::string GetLocaleElaboratedCodeA (const std::string &lc) +{ + return GetLocaleInfoA (LocaleCodeToLcidA (lc.c_str ()), 90); +} +std::wstring GetLocaleElaboratedCodeW (LPCWSTR lc) +{ + return GetLocaleInfoW (LocaleCodeToLcidW (lc), 90); +} +std::wstring GetLocaleElaboratedCodeW (const std::wstring &lc) +{ + return GetLocaleInfoW (LocaleCodeToLcidW (lc.c_str ()), 90); +} +std::wstring GetLocaleElaboratedCode (const std::wstring &lc) { return GetLocaleElaboratedCodeW (lc); } +std::string GetLocaleElaboratedCode (const std::string &lc) { return GetLocaleElaboratedCodeA (lc); } + +std::string LcidToLocaleCodeA (LCID lcid, char divide = '-') +{ + return GetLocaleRestrictedCodeFromLcidA (lcid) + divide + GetLocaleElaboratedCodeFromLcidA (lcid); +} +std::wstring LcidToLocaleCodeW (LCID lcid, WCHAR divide = L'-') +{ + return GetLocaleRestrictedCodeFromLcidW (lcid) + divide + GetLocaleElaboratedCodeFromLcidW (lcid); +} +std::wstring LcidToLocaleCode (LCID lcid, WCHAR divide = L'-') { return LcidToLocaleCodeW (lcid, divide); } +std::string LcidToLocaleCode (LCID lcid, char divide = '-') { return LcidToLocaleCodeA (lcid, divide); } \ No newline at end of file diff --git a/priread/nstring.h b/priread/nstring.h new file mode 100644 index 0000000..b61c94f --- /dev/null +++ b/priread/nstring.h @@ -0,0 +1,426 @@ +#pragma once +#include +#include +#include +namespace l0km +{ + template , typename AL = std::allocator > inline std::basic_string toupper (const std::basic_string &src) + { + std::basic_string dst = src; + static const std::locale loc; + const std::ctype &ctype = std::use_facet > (loc); + for (typename std::basic_string ::size_type i = 0; i < src.size (); ++ i) + { + dst [i] = ctype.toupper (src [i]); + } + return dst; + } + template , typename AL = std::allocator > inline std::basic_string tolower (const std::basic_string &src) + { + std::basic_string dst = src; + static const std::locale loc; + const std::ctype &ctype = std::use_facet > (loc); + for (typename std::basic_string ::size_type i = 0; i < src.size (); ++ i) + { + dst [i] = ctype.tolower (src [i]); + } + return dst; + } + inline char toupper (char ch) + { + static const std::locale loc; + return std::use_facet > (loc).toupper (ch); + } + inline char tolower (char ch) + { + static const std::locale loc; + return std::use_facet > (loc).tolower (ch); + } + inline wchar_t toupper (wchar_t ch) + { + static const std::locale loc; + return std::use_facet > (loc).toupper (ch); + } + inline wchar_t tolower (wchar_t ch) + { + static const std::locale loc; + return std::use_facet > (loc).tolower (ch); + } + inline int toupper (int ch) + { + static const std::locale loc; + return std::use_facet > (loc).toupper (ch); + } + inline int tolower (int ch) + { + static const std::locale loc; + return std::use_facet > (loc).tolower (ch); + } +} +template bool is_blank (ct &ch) +{ + return ch == ct (' ') || ch == ct ('\t') || ch == ct ('\n'); +} +template , typename AL = std::allocator > std::basic_string NormalizeString (const std::basic_string &str, bool upper = false, bool includemidblank = false) +{ + typedef std::basic_string string_type; + string_type result; + if (str.empty ()) return result; + auto begin_it = str.begin (); + auto end_it = str.end (); + while (begin_it != end_it && is_blank (*begin_it)) ++begin_it; + while (end_it != begin_it && is_blank (*(end_it - 1))) --end_it; + bool in_space = false; + for (auto it = begin_it; it != end_it; ++ it) + { + if (is_blank (*it)) + { + if (includemidblank) + { + if (!in_space) + { + result.push_back (E (' ')); + in_space = true; + } + } + else + { + result.push_back (*it); + in_space = true; + } + } + else + { + result.push_back (*it); + in_space = false; + } + } + if (upper) return l0km::toupper (result); + else return l0km::tolower (result); +} +template , typename AL = std::allocator > bool IsNormalizeStringEquals (const std::basic_string &l, const std::basic_string &r, bool includemidblank = false) +{ + auto skip_blank = [&] (auto &it, auto &end) + { + while (it != end && is_blank (*it)) ++ it; + }; + auto it_l = l.begin (), it_r = r.begin (); + auto end_l = l.end (), end_r = r.end (); + skip_blank (it_l, end_l); + skip_blank (it_r, end_r); + while (it_l != end_l && it_r != end_r) + { + E ch_l = *it_l; + E ch_r = *it_r; + ch_l = l0km::tolower (ch_l); + ch_r = l0km::tolower (ch_r); + if (ch_l != ch_r) return false; + ++ it_l; + ++ it_r; + if (includemidblank) + { + if (is_blank (ch_l)) + { + skip_blank (it_l, end_l); + skip_blank (it_r, end_r); + } + } + } + skip_blank (it_l, end_l); + skip_blank (it_r, end_r); + return it_l == end_l && it_r == end_r; +} +template , typename AL = std::allocator > int64_t NormalizeStringCompare (const std::basic_string &l, const std::basic_string &r, bool includemidblank = false) +{ + auto skip_blank = [&] (auto &it, auto &end) + { + while (it != end && is_blank (*it)) ++ it; + }; + auto it_l = l.begin (), it_r = r.begin (); + auto end_l = l.end (), end_r = r.end (); + skip_blank (it_l, end_l); + skip_blank (it_r, end_r); + while (it_l != end_l && it_r != end_r) + { + E ch_l = l0km::tolower (*it_l); + E ch_r = l0km::tolower (*it_r); + if (ch_l != ch_r) return ch_l < ch_r ? -1 : 1; + ++ it_l; + ++ it_r; + if (includemidblank) + { + if (is_blank (*it_l) || is_blank (*it_r)) + { + skip_blank (it_l, end_l); + skip_blank (it_r, end_r); + if (it_l != end_l && it_r != end_r) + { + ch_l = l0km::tolower (*it_l); + ch_r = l0km::tolower (*it_r); + } + } + } + } + skip_blank (it_l, end_l); + skip_blank (it_r, end_r); + if (it_l == end_l && it_r == end_r) return 0; + if (it_l == end_l) return -1; + return 1; +} +template bool IsNormalizeStringEquals (const CharT *l, const CharT *r, bool includemidblank = false) +{ + if (!l || !r) return l == r; + auto skip_blank = [] (const CharT *&p) + { + while (*p && is_blank (*p)) ++ p; + }; + const CharT *p1 = l; + const CharT *p2 = r; + skip_blank (p1); + skip_blank (p2); + while (*p1 && *p2) + { + CharT ch1 = l0km::tolower (*p1); + CharT ch2 = l0km::tolower (*p2); + if (ch1 != ch2) return false; + ++ p1; + ++ p2; + if (includemidblank) + { + if (is_blank (*p1) || is_blank (*p2)) + { + skip_blank (p1); + skip_blank (p2); + } + } + } + skip_blank (p1); + skip_blank (p2); + return *p1 == 0 && *p2 == 0; +} +template int64_t NormalizeStringCompare (const CharT *l, const CharT *r, bool includemidblank = false) +{ + if (!l || !r) return l ? 1 : (r ? -1 : 0); + auto skip_blank = [] (const CharT *&p) + { + while (*p && is_blank (*p)) ++ p; + }; + const CharT *p1 = l; + const CharT *p2 = r; + skip_blank (p1); + skip_blank (p2); + while (*p1 && *p2) + { + CharT ch1 = l0km::tolower (*p1); + CharT ch2 = l0km::tolower (*p2); + if (ch1 != ch2) return (ch1 < ch2) ? -1 : 1; + ++ p1; + ++ p2; + if (includemidblank) + { + if (is_blank (*p1) || is_blank (*p2)) + { + skip_blank (p1); + skip_blank (p2); + } + } + } + skip_blank (p1); + skip_blank (p2); + if (*p1 == 0 && *p2 == 0) return 0; + if (*p1 == 0) return -1; + return 1; +} +template , typename AL = std::allocator > bool IsNormalizeStringEmpty (const std::basic_string &str) +{ + return IsNormalizeStringEquals (str, std::basic_string ()); +} +template , typename AL = std::allocator > std::basic_string StringTrim (const std::basic_string &str, bool includemidblank = false) +{ + typedef std::basic_string string_type; + typedef typename string_type::size_type size_type; + if (str.empty ()) return string_type (); + size_type first = 0; + size_type last = str.size (); + while (first < last && is_blank (str [first])) ++first; + while (last > first && is_blank (str [last - 1])) --last; + if (first == last) return string_type (); + string_type result; + result.reserve (last - first); + bool in_space = false; + for (size_type i = first; i < last; ++ i) + { + if (is_blank (str [i])) + { + if (includemidblank) + { + if (!in_space) + { + result.push_back (E (' ')); + in_space = true; + } + } + else + { + result.push_back (str [i]); + in_space = true; + } + } + else + { + result.push_back (str [i]); + in_space = false; + } + } + return result; +} +template , typename AL = std::allocator > size_t GetNormalizeStringLength (const std::basic_string &str, bool includemidblank = false) +{ + typedef typename std::basic_string ::size_type size_type; + if (str.empty ()) return 0; + size_type first = 0, last = str.size (); + while (first < last && is_blank (str [first])) ++first; + while (last > first && is_blank (str [last - 1])) --last; + if (first == last) return 0; + size_t length = 0; + bool in_space = false; + for (size_type i = first; i < last; ++i) + { + if (is_blank (str [i])) + { + if (includemidblank) + { + if (!in_space) + { + ++ length; + in_space = true; + } + } + else + { + ++ length; + in_space = true; + } + } + else + { + ++ length; + in_space = false; + } + } + return length; +} +namespace std +{ + + template , typename al = std::allocator > class basic_nstring: public std::basic_string + { + using base = std::basic_string ; + bool default_upper = false, default_include_blank_in_str = false; + public: + using typename base::size_type; + using typename base::value_type; + using base::base; + basic_nstring (): base (), default_upper (false), default_include_blank_in_str (false) {} + basic_nstring (const ct *pStr): base (pStr), default_upper (false), default_include_blank_in_str (false) {} + basic_nstring (const base &str): base (str) {} + basic_nstring (base &&str): base (std::move (str)) {} + basic_nstring (const ct *data, size_type count): base (data, count), default_upper (false), default_include_blank_in_str (false) {} + template basic_nstring (const ct (&arr) [N]) : base (arr, N) {} + template basic_nstring (InputIt first, InputIt last): base (first, last), default_upper (false), default_include_blank_in_str (false) {} + bool upper_default () const { return this->default_upper; } + bool upper_default (bool value) { return this->default_upper = value; } + bool include_blank_in_str_middle () const { return this->default_include_blank_in_str; } + bool include_blank_in_str_middle (bool value) { return this->default_include_blank_in_str = value; } + base normalize (bool upper, bool includemidblank) const + { + return NormalizeString (*this, upper, includemidblank); + } + base normalize (bool upper) const + { + return this->normalize (upper, default_include_blank_in_str); + } + base normalize () const { return this->normalize (default_upper); } + base upper (bool includemidblank) const + { + return NormalizeString (*this, true, includemidblank); + } + base upper () const { return this->upper (default_include_blank_in_str); } + base lower (bool includemidblank) const + { + return NormalizeString (*this, false, includemidblank); + } + base lower () const { return this->lower (default_include_blank_in_str); } + base trim (bool includemidblank) const + { + return StringTrim (*this, includemidblank); + } + base trim () const { return this->trim (default_include_blank_in_str); } + size_t length (bool includemidblank) const { return GetNormalizeStringLength (*this, includemidblank); } + size_t length () const { return length (default_include_blank_in_str); } + bool empty () const + { + return IsNormalizeStringEmpty (*this); + } + bool equals (const base &another, bool includemidblank) const + { + return IsNormalizeStringEquals (*this, another, includemidblank); + } + bool equals (const base &another) const { return equals (another, default_include_blank_in_str); } + int64_t compare (const base &another, bool includemidblank) const + { + return NormalizeStringCompare (*this, another, includemidblank); + } + int64_t compare (const base &another) const { return compare (another, default_include_blank_in_str); } + base &string () { return *this; } + base to_string (bool upper, bool includemidblank) const { return this->normalize (upper, includemidblank); } + base to_string (bool upper) const { return this->normalize (upper, default_include_blank_in_str); } + base to_string () const { return this->normalize (default_upper); } + bool operator == (const base &other) const { return equals (other, false); } + bool operator != (const base &other) const { return !equals (other, false); } + bool operator < (const base &other) const { return compare (other, false) < 0; } + bool operator > (const base &other) const { return compare (other, false) > 0; } + bool operator <= (const base &other) const { return compare (other, false) <= 0; } + bool operator >= (const base &other) const { return compare (other, false) >= 0; } + int64_t operator - (const base &other) const { return compare (other, false); } + template , typename AL = std::allocator > + static bool equals (const std::basic_string &l, const std::basic_string &r, bool remove_mid_blank = false) + { + return IsNormalizeStringEquals (l, r, remove_mid_blank); + } + template , typename AL = std::allocator > + static int64_t compare (const std::basic_string &l, const std::basic_string &r, bool remove_mid_blank = false) + { + return NormalizeStringCompare (l, r, remove_mid_blank); + } + template , typename AL = std::allocator > + static std::basic_string normalize (const std::basic_string &str, bool to_upper = false, bool remove_mid_blank = false) + { + return NormalizeString (str, to_upper, remove_mid_blank); + } + template , typename AL = std::allocator > + static std::basic_string trim (const std::basic_string &str, bool remove_mid_blank = false) + { + return StringTrim (str, remove_mid_blank); + } + template , typename AL = std::allocator > + static size_t length (const std::basic_string &str, bool remove_mid_blank = false) + { + return GetNormalizeStringLength (str, remove_mid_blank); + } + template , typename AL = std::allocator > + static bool empty (const std::basic_string &str) + { + return IsNormalizeStringEmpty (str); + } + template , typename AL = std::allocator > + static std::basic_nstring to_nstring (std::basic_string &str) { return std::basic_nstring (str); } + template , typename AL = std::allocator > + static std::basic_nstring toupper (const std::basic_nstring &str) { return l0km::toupper (str); } + template , typename AL = std::allocator > + static std::basic_nstring tolower (const std::basic_nstring &str) { return l0km::tolower (str); } + }; + + typedef basic_nstring nstring; + typedef basic_nstring wnstring; +} \ No newline at end of file diff --git a/priread/prifile.h b/priread/prifile.h index 39e1f62..493337a 100644 --- a/priread/prifile.h +++ b/priread/prifile.h @@ -3,6 +3,10 @@ #include #include #include +#include +#include +#include "nstring.h" +#include "localeex.h" struct destruct { @@ -10,24 +14,148 @@ struct destruct destruct (std::function init): endtask (init) {} ~destruct () { if (endtask) endtask (); } }; -typedef struct LargeInt +template struct LargeIntBase { - LARGE_INTEGER val; - LargeInt (LONGLONG v) { val.QuadPart = v; } - operator LARGE_INTEGER() const { return val; } -} lint; + BASE_INT val; + LargeIntBase () { val.QuadPart = 0; } + LargeIntBase (T v) { val.QuadPart = v; } + LargeIntBase (const LargeIntBase &other) { val.QuadPart = other.val.QuadPart; } + LargeIntBase (const BASE_INT &other) { val = other; } + operator BASE_INT () const { return val; } + operator T () const { return val.QuadPart; } + explicit operator bool () const { return val.QuadPart != 0; } + T *ptr_num () { return &val.QuadPart; } + BASE_INT *ptr_union () { return &val; } + size_t sizeof_num () const { return sizeof (val.QuadPart); } + size_t sizeof_union () const { return sizeof (val); } + T num () const { return val.QuadPart; } + BASE_INT win_union () const { return val; } + LargeIntBase operator + (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart + rhs.val.QuadPart); } + LargeIntBase operator - (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart - rhs.val.QuadPart); } + LargeIntBase operator * (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart * rhs.val.QuadPart); } + LargeIntBase operator / (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart / rhs.val.QuadPart); } + LargeIntBase operator % (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart % rhs.val.QuadPart); } + LargeIntBase &operator += (const LargeIntBase &rhs) { val.QuadPart += rhs.val.QuadPart; return *this; } + LargeIntBase &operator -= (const LargeIntBase &rhs) { val.QuadPart -= rhs.val.QuadPart; return *this; } + LargeIntBase &operator *= (const LargeIntBase &rhs) { val.QuadPart *= rhs.val.QuadPart; return *this; } + LargeIntBase &operator /= (const LargeIntBase &rhs) { val.QuadPart /= rhs.val.QuadPart; return *this; } + LargeIntBase &operator %= (const LargeIntBase &rhs) { val.QuadPart %= rhs.val.QuadPart; return *this; } + LargeIntBase operator & (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart & rhs.val.QuadPart); } + LargeIntBase operator | (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart | rhs.val.QuadPart); } + LargeIntBase operator ^ (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart ^ rhs.val.QuadPart); } + LargeIntBase operator << (int n) const { return LargeIntBase (val.QuadPart << n); } + LargeIntBase operator >> (int n) const { return LargeIntBase (val.QuadPart >> n); } + LargeIntBase &operator &= (const LargeIntBase &rhs) { val.QuadPart &= rhs.val.QuadPart; return *this; } + LargeIntBase &operator |= (const LargeIntBase &rhs) { val.QuadPart |= rhs.val.QuadPart; return *this; } + LargeIntBase &operator ^= (const LargeIntBase &rhs) { val.QuadPart ^= rhs.val.QuadPart; return *this; } + LargeIntBase &operator <<= (int n) { val.QuadPart <<= n; return *this; } + LargeIntBase &operator >>= (int n) { val.QuadPart >>= n; return *this; } + LargeIntBase &operator ++ () { ++val.QuadPart; return *this; } + LargeIntBase operator ++ (int) { LargeIntBase tmp (*this); ++val.QuadPart; return tmp; } + LargeIntBase &operator -- () { --val.QuadPart; return *this; } + LargeIntBase operator -- (int) { LargeIntBase tmp (*this); --val.QuadPart; return tmp; } + bool operator < (const LargeIntBase &rhs) const { return val.QuadPart < rhs.val.QuadPart; } + bool operator > (const LargeIntBase &rhs) const { return val.QuadPart > rhs.val.QuadPart; } + bool operator <= (const LargeIntBase &rhs) const { return val.QuadPart <= rhs.val.QuadPart; } + bool operator >= (const LargeIntBase &rhs) const { return val.QuadPart >= rhs.val.QuadPart; } + bool operator == (const LargeIntBase &rhs) const { return val.QuadPart == rhs.val.QuadPart; } + bool operator != (const LargeIntBase &rhs) const { return val.QuadPart != rhs.val.QuadPart; } + bool operator ! () const { return !val.QuadPart; } + LargeIntBase operator ~ () const { return LargeIntBase (~val.QuadPart); } +}; +typedef LargeIntBase LargeInt, lint; +typedef LargeIntBase ULargeInt, ulint; +template , typename al = std::allocator > class basic_priid: public std::basic_nstring +{ + using base = std::basic_nstring ; + public: + using typename base::size_type; + using typename base::value_type; + using base::base; + basic_priid (const ct *buf, size_t sz = 16): base (buf, sz) {} + template basic_priid (const ct (&arr) [N]) : base (arr, N) {} +}; +typedef basic_priid pri_sectid; +std::string ReadStringEndwithNullA (IStream *pStream) +{ + if (!pStream) return ""; + std::string result; + char ch = 0; + ULONG cbRead = 0; + while (true) + { + HRESULT hr = pStream->Read (&ch, 1, &cbRead); + if (FAILED (hr) || cbRead == 0) break; + if (ch == '\0') break; + result.push_back (ch); + } + return result; +} +std::wstring ReadStringEndwithNullW (IStream *pStream) +{ + if (!pStream) return L""; + std::wstring result; + WCHAR ch = 0; + ULONG cbRead = 0; + while (true) + { + HRESULT hr = pStream->Read (&ch, sizeof (WCHAR), &cbRead); + if (FAILED (hr) || cbRead < sizeof (WCHAR)) break; + if (ch == L'\0') break; + result.push_back (ch); + } + return result; +} +std::string ReadStringEndwithNull (IStream *ifile, std::string &ret) +{ + return ret = ReadStringEndwithNullA (ifile); +} +std::wstring ReadStringEndwithNull (IStream *ifile, std::wstring &ret) +{ + return ret = ReadStringEndwithNullW (ifile); +} + +// 0 1 +// 012345678901234 +#define PRI_SECT_ID_PRI_DESCRIPTOR "[mrm_pridescex]" +#define PRI_SECT_ID_HIERARCHICAL_SCHEMA "[mrm_hschema] " +#define PRI_SECT_ID_HIERARCHICAL_SCHEMAEX "[mrm_hschemaex]" +#define PRI_SECT_ID_DECISION_INFO "[mrm_decn_info]" +#define PRI_SECT_ID_RESOURCE_MAP "[mrm_res_map__]" +#define PRI_SECT_ID_RESOURCE_MAP2 "[mrm_res_map2_]" +#define PRI_SECT_ID_DATA_ITEM "[mrm_dataitem] " +#define PRI_SECT_ID_REVERSE_MAP "[mrm_rev_map] " +#define PRI_SECT_ID_REFERENCED_FILE "[def_file_list]" +enum class SectionType +{ + Unknown, // δ֪ÀàÐÍ - ´¦Àíδʶ±ðµÄ½ÚÇø + PriDescriptor, // PRI ÃèÊö·û - °üº¬ÎļþÕûÌå½á¹¹ºÍÒýÓÃÐÅÏ¢ + HierarchicalSchema, // ²ã´Î½á¹¹Ä£Ê½ - ¶¨Òå×ÊÔ´ÃüÃû¿Õ¼äºÍ²ã´Î½á¹¹ + HierarchicalSchemaEx, // ²ã´Î½á¹¹Ä£Ê½ - ¶¨Òå×ÊÔ´ÃüÃû¿Õ¼äºÍ²ã´Î½á¹¹ + DecisionInfo, // ¾ö²ßÐÅÏ¢ - ¹ÜÀí×ÊÔ´ÏÞ¶¨·ûºÍ¾ö²ßÂß¼­ + ResourceMap, // ×ÊÔ´Ó³Éä - ½«×ÊÔ´ÏîÓ³Éäµ½¾ßÌåºòѡֵ + ResourceMap2, // ×ÊÔ´Ó³Éä - ½«×ÊÔ´ÏîÓ³Éäµ½¾ßÌåºòѡֵ + DataItem, // Êý¾ÝÏî - ´æ´¢Êµ¼ÊµÄ×ÊÔ´Êý¾Ý + ReverseMap, // ·´ÏòÓ³Éä - Ìṩ´Ó×ÊÔ´Ãûµ½IDµÄÓ³Éä + ReferencedFile // ÒýÓÃÎļþ - ¹ÜÀíÒýÓõÄÍⲿÎļþ +}; struct head { - CHAR szMagic [8] = {}; - WORD wPlaceholder1 = -1, // 0 - wPlaceholder2 = 0; // 1 - DWORD dwFileSize = 0, - dwToCOffset = 0, - dwSectStartOffset = 0; - WORD wSectCount = 0, - wPlaceholder3 = 0; // 0xFFFF - DWORD dwPlaceholder4 = -1; // 0 + // °æ±¾±êʶ·û / version identifier + // ¡°mrm_pri0¡±£º¿Í»§¶Ë 6.2.1£¨Windows 8£©¡£ + // ¡°mrm_pri1¡±£º¿Í»§¶Ë 6.3.0£¨Windows 8.1£©¡£ + // ¡°mrm_prif¡±£ºWindows Phone 6.3.1¡£ + // ¡°mrm_pri2¡±£ºUniversal 10.0.0£¨Windows 10£©¡£ + CHAR szMagic [8] = {}; + WORD wPlaceholder1 = -1, // δ֪£¬0 / unknown, zero + wPlaceholder2 = 0; // δ֪£¬1 / unknown, one + DWORD dwFileSize = 0, // Îļþ×Ü´óС / total file size + dwToCOffset = 0, // Ŀ¼±íÆ«ÒÆ / offset of table of contents + dwSectStartOffset = 0; // µÚÒ»½ÚµÄÆ«ÒÆ / offset of first section + WORD wSectCount = 0, // ½ÚÊýÁ¿ / number of sections + wPlaceholder3 = 0; // δ֪£¬0xFFFF / unknown, 0xFFFF + DWORD dwPlaceholder4 = -1; // δ֪£¬0 / unknown, zero bool valid () { CHAR m7 = szMagic [7]; @@ -50,9 +178,9 @@ struct head }; struct foot { - DWORD dwChkCode = 0, // 0xDEFFFADE - dwTotalFileSize = 0; - CHAR szMagic [8] = {}; + DWORD dwChkCode = 0; // 0xDEFFFADE + DWORD dwTotalFileSize = 0; // total file size, as in header + CHAR szMagic [8] = {0}; // version identifier, as in header bool valid (const head &fh) { if (dwChkCode != 0xDEFFFADE) return false; @@ -66,53 +194,975 @@ struct foot }; struct tocentry { - CHAR szIdentifier [16] = {0}; - WORD wFlags = 0; - WORD wSectFlags = 0; - DWORD dwSectQualifier = 0; - DWORD dwSectOffset = 0; - DWORD dwSectLength = 0; + CHAR szIdentifier [16] = {0}; // ½Ú±êʶ·û / section identifier + WORD wFlags = 0; // ±êÖ¾ / flags + WORD wSectFlags = 0; // ½Ú±êÖ¾ / section flags + DWORD dwSectQualifier = 0; // ½ÚÏÞ¶¨·û / section qualifier + DWORD dwSectOffset = 0; // ½ÚÆ«ÒÆ£¨Ïà¶ÔÓÚµÚÒ»½ÚÆ«ÒÆ£© / section offset (relative to offset of first section) + DWORD dwSectLength = 0; // ½Ú³¤¶È / section length }; struct section_header { - CHAR szIdentifier [16] = {0}; - DWORD dwQualifier = 0; - WORD wFlags = 0; - DWORD dwLength = 0; - DWORD dwPlaceholder1 = -1; // 0 + CHAR szIdentifier [16] = {0}; // ½Ú±êʶ·û / section identifier + DWORD dwQualifier = 0; // ½ÚÏÞ¶¨·û / section qualifier + WORD wFlags = 0; // ±êÖ¾ / flags + WORD wSectFlags = 0; // ½Ú±êÖ¾ / section flags + DWORD dwLength = 0; // ½Ú³¤¶È / section length + DWORD dwPlaceholder1 = -1; // δ֪£¬0 / unknown, zero bool valid () const { return szIdentifier [0] && !dwPlaceholder1; } }; struct section_check { - DWORD dwChkCode = 0, // 0xDEF5FADE - dwSectLength = 0; + DWORD dwChkCode = 0; // ħÊý 0xF5DEDEFA + DWORD dwSectLength = 0; // ½Ú³¤¶È£¨Óë½ÚÍ·ÖеÄÏàͬ£© / section length, as in section header bool valid (const section_header &h) const { return dwChkCode == 0xDEF5FADE && dwSectLength == h.dwLength; } }; struct substream { IStream *&ifile; - UINT64 offset = 0, - size = 0; - substream (IStream *&ifile, UINT64 ofs = 0, UINT64 siz = 0): ifile (ifile), offset (ofs), size (siz) {} + ULONGLONG offset = 0; + ULONGLONG size = 0; + substream (IStream *&ifile, ulint ofs = 0, ulint siz = 0): ifile (ifile), offset (ofs), size (siz) {} + void set (ulint p_offset, ulint p_size) + { + offset = p_offset; + size = p_size; + } + HRESULT seek () + { + ULARGE_INTEGER pos = {}; + HRESULT hr = ifile->Seek (lint (0), STREAM_SEEK_CUR, &pos); + if (FAILED (hr)) return hr; + if (pos.QuadPart == offset) return S_OK; + return ifile->Seek (lint (offset), STREAM_SEEK_SET, nullptr); + } }; struct section { section_header head; section_check foot; substream childst; + // Çë´Ó type ·½·¨»ñÈ¡ÀàÐÍ£¬¶ø²»ÊÇÖ±½Óͨ¹ý sect_type À´¶ÁÈ¡£¨ÒòΪδ³õʼ»¯£© + SectionType sect_type = SectionType::Unknown; + section (IStream *&ifile): childst (ifile) {} + bool valid () const { return head.valid () && foot.valid (head); } + SectionType type () + { + if (sect_type == SectionType::Unknown) + { + pri_sectid pid (head.szIdentifier, 16); + if (pid.equals (PRI_SECT_ID_PRI_DESCRIPTOR)) sect_type = SectionType::DecisionInfo; + else if (pid.equals (PRI_SECT_ID_HIERARCHICAL_SCHEMA)) sect_type = SectionType::HierarchicalSchema; + else if (pid.equals (PRI_SECT_ID_HIERARCHICAL_SCHEMAEX)) sect_type = SectionType::HierarchicalSchemaEx; + else if (pid.equals (PRI_SECT_ID_DECISION_INFO)) sect_type = SectionType::DecisionInfo; + else if (pid.equals (PRI_SECT_ID_RESOURCE_MAP)) sect_type = SectionType::ResourceMap; + else if (pid.equals (PRI_SECT_ID_RESOURCE_MAP2)) sect_type = SectionType::ResourceMap2; + else if (pid.equals (PRI_SECT_ID_DATA_ITEM)) sect_type = SectionType::DataItem; + else if (pid.equals (PRI_SECT_ID_REVERSE_MAP)) sect_type = SectionType::ReverseMap; + else if (pid.equals (PRI_SECT_ID_REFERENCED_FILE)) sect_type = SectionType::ReferencedFile; + else sect_type = SectionType::Unknown; + } + return sect_type; + } }; +namespace pri +{ + // PriDescriptorFlags + + enum class PRI_SEC_DESP: DWORD + { + INVALID = 0, + AUTOMERGE = 0x1, // AutoMerge + DEPLOY_MERGEABLE = 0x2, // IsDeploymentMergeable + DEPLOY_MERGE_RESULT = 0x4, // IsDeploymentMergeResult + AUTO_MERGE_RESULT = 0x8 // IsAutomergeMergeResult + }; + + // HierarchicalSchema & HierarchicalSchemaEx + + typedef struct _HSCHEMA_VERSION_INFO + { + WORD wMajor = 0; // Ö÷°æ±¾ºÅ / major version + WORD wMinor = 0; // ´Î°æ±¾ºÅ / minor version + DWORD dwUnknown1 = -1; // δ֪£¬0 + // УÑéºÍ£¨checksum£© + // checksum: a CRC32-based checksum computed on the unique name, + // the name, the section indices of the Resource Map Section + // and Data Item Section, and the names of all scopes and items + DWORD dwCheckSum = 0; + DWORD dwScopeCount = 0; // scope ÊýÁ¿ + DWORD dwItemCount = 0; // item ÊýÁ¿ + } HSCHEMA_VERSION_INFO; + // ×ÊÔ´Ãû³Æ£¨scope/item£©°´ÒÔϸñʽ´æ´¢£¨Ê¾Àý×ֶΣ©£ºparent scope index¡¢full path ³¤¶È¡¢ + // Ãû×ÖÊ××Öĸ£¨´óд£©¡¢Ãû×Ö³¤¶È¡¢Ãû×ÖÆ«ÒÆ¡¢index property µÈ¡£ + + typedef struct _SCOPE_ITEM_INFO + { + WORD wParentScopeIndex = -1; // parent scope index + WORD wFullPathLength = 0; // length of full path + WCHAR wchUpperFirst = L'\0'; // uppercase first character of name, '\0' if name is empty + // length of name in characters, null-terminator excluded, 0 if the length is bigger than 255 + // ÔÚÔ­×÷ÕßµÄ C# ´úÂëÖÐÊÇÕâô¶ÁÈ¡µÄ£ºuint nameOffset = binaryReader.ReadUInt16() | (uint)((flags & 0xF) << 16); + // ËùÒÔ²»ÄÜÖ±½ÓʹÓóÉÔ± bNameLength¡£ÇëʹÓýṹÌåÖÐ name_offset () ·½·¨À´»ñȡֵ + BYTE bNameLength = 0; + BYTE bFlags = 0; // flags and upper bits of name offset + WORD wNameOffset = 0; // offset of name in ASCII or Unicode name block in characters + // index property + // bits 0-3: upper bits 16-19 of name offset + // bit 4: set if resource name is a scope, unset if it is an item + // bit 5 : set if name is stored in the ASCII name block, unset if + // it is stored in the Unicode name block + WORD wIndexProp = 0; + bool is_scope () const { return bFlags & 0x10; } + bool name_in_ascii () const { return bFlags & 0x20; } + DWORD name_offset () const { return (DWORD)wNameOffset | ((DWORD)(bFlags & 0xF) << 16); } + DWORD index () const { return wIndexProp; } + } SCOPE_ITEM_INFO; + typedef struct _SCOPE_EX_INFO + { + WORD wScopeIndex = 0; // scope index + WORD wChildCount = 0; // child count + WORD wFirstChild = 0; // scope or item index of first child, all other children follow sequentially + WORD wUnknown1 = 0; // unknown, zero + bool valid () const { return !wUnknown1; } + } SCOPE_EX_INFO; + // For each item, sorted by the index property, follows: 0 uint16 item index + typedef WORD ITEM_INDEX; + class RES_MAP_SCOPE; + // ÈçºÎʹÓã¨Ê¾Àý£©£º + // auto root = std::make_shared (0, nullptr, L"root"); + + enum class RES_MAP_OBJTYPE + { + ENTRY = 0, + SCOPE = 1, + ITEM = 2 + }; + class RES_MAP_ENTRY + { + public: + using ScopePtr = std::weak_ptr ; + ITEM_INDEX wIndex = 0; + std::wstring strName; + RES_MAP_ENTRY (ITEM_INDEX index = 0, ScopePtr parent = {}, const std::wstring &name = L"", RES_MAP_OBJTYPE type = RES_MAP_OBJTYPE::ENTRY): + wIndex (index), strName (name), rmsParent (parent), eType (type) {} + virtual ~RES_MAP_ENTRY () = default; + std::wstring full_name (WCHAR divide = L'\\') + { + if (strFullName.empty ()) + { + if (auto parent = rmsParent.lock ()) strFullName = parent->full_name (divide) + divide + strName; + else strFullName = strName; + } + return strFullName; + } + void refresh_full_name () { strFullName.clear (); } + // °²È«µ÷Óà + void change_parent (ScopePtr parent) + { + rmsParent = parent; + refresh_full_name (); + } + auto get_parent () { return rmsParent; } + static auto make (ITEM_INDEX index = 0, ScopePtr parent = {}, const std::wstring &name = L"") + { + return std::make_shared (index, parent, name, RES_MAP_OBJTYPE::ENTRY); + } + RES_MAP_OBJTYPE type () const { return eType; } + protected: + ScopePtr rmsParent; + std::wstring strFullName; + RES_MAP_OBJTYPE eType; + }; + // ÈçºÎʹÓã¨Ê¾Àý£©£º + // auto folder = root->add_child (1, nullptr, L"folder"); + // auto file = folder->add_child (2, nullptr, L"file.txt"); + class RES_MAP_SCOPE: public RES_MAP_ENTRY, public std::enable_shared_from_this + { + public: + using EntryPtr = std::shared_ptr ; + using ScopePtr = std::shared_ptr ; + explicit RES_MAP_SCOPE (ITEM_INDEX index = 0, ScopePtr parent = nullptr, const std::wstring &name = L""): + RES_MAP_ENTRY (index, parent, name, RES_MAP_OBJTYPE::SCOPE) {} + template std::shared_ptr add_child (Args &&...args) + { + static_assert (std::is_base_of ::value, "T must derive from RES_MAP_ENTRY"); + auto child = std::make_shared (std::forward (args) ...); + child->rmsParent = this->shared_from_this (); + vecChild.push_back (child); + return child; + } + const std::vector &children () const { return vecChild; } + static auto make (ITEM_INDEX index = 0, ScopePtr parent = {}, const std::wstring &name = L"") + { + return std::make_shared (index, parent, name, RES_MAP_OBJTYPE::SCOPE); + } + std::vector vecChild; + }; + class RES_MAP_ITEM: public RES_MAP_ENTRY + { + public: + using EntryPtr = std::shared_ptr ; + using ScopePtr = std::shared_ptr ; + using ItemPtr = std::shared_ptr ; + RES_MAP_ITEM (ITEM_INDEX index = 0, std::shared_ptr parent = nullptr, const std::wstring &name = L""): + RES_MAP_ENTRY (index, parent, name, RES_MAP_OBJTYPE::ITEM) {} + static auto make (ITEM_INDEX index = 0, ScopePtr parent = {}, const std::wstring &name = L"") + { + return std::make_shared (index, parent, name, RES_MAP_OBJTYPE::ITEM); + } + }; + + // DecisionInfo + + typedef struct _DECISION_INFO + { + WORD wFirstQualiIndex = 0; // index of the first qualifier set index in the index table + WORD wQualiSetsCount = 0; // number of qualifiers sets in decision + } DECISION_INFO; + typedef struct _QUALIFIER_SET_INFO + { + WORD wFirstQualiIndex = 0; // index of the first qualifier index in the index table // firstQualifierIndexIndex + WORD wQualiSetsCount = 0; // number of qualifiers in qualifier set // numQualifiersInSet + } QUALIFIER_SET_INFO; + typedef struct _QUALIFIER_INFO + { + WORD wDistQualiIndex = 0; // index of distinct qualifier + WORD wPriority = 0; // priority + WORD wFallbackScore = -1; // fallback score, values range from 0 to 1000 + WORD wUnknown1 = -1; // unknown, zero + } QUALIFIER_INFO; + enum class QUALIFIER_TYPE: WORD + { + LANGUAGE = 0, // ÓïÑÔ (0) + CONTRAST = 1, // ¶Ô±È¶È (1) + SCALE = 2, // ±ÈÀý (2) + HOMEREGION = 3, // Ö÷ÆÁÄ»ÇøÓò (3) + TARGETSIZE = 4, // Ä¿±ê³ß´ç (4) + LAYOUTDIR = 5, // ²¼¾Ö·½Ïò (5) + THEME = 6, // Ö÷Ìâ (6) + ALTERNATEFORM = 7, // Ìæ´ú¸ñʽ (7) + DXFEATURELEVEL = 8, // DX ¹¦Äܵȼ¶ (8) + CONFIG = 9, // ÅäÖà (9) + DEVICEFAMILY = 10, // É豸ϵÁÐ (10) + CUSTOM = 11, // ×Ô¶¨Òå (11) + }; + typedef struct _DISTINCE_QUALIFIER_INFO + { + WORD wUnknown1 = 0; // unknown + WORD wQualiType = 0; // qualifier type + WORD wUnknown2 = 0; // unknown + WORD wUnknown3 = 0; // unknown + WORD wQualiValueOffset = 0; // offset of qualifier value in qualifier value block, in characters + } DISTINCE_QUALIFIER_INFO; + typedef struct _QUALIFIER + { + ITEM_INDEX wIndex = 0; + QUALIFIER_TYPE eType = QUALIFIER_TYPE::CUSTOM; + WORD wPriority = 0; + DOUBLE dFallbackScope = 0; + std::wstring swValue = 0; + _QUALIFIER (ITEM_INDEX index = 0, QUALIFIER_TYPE type = QUALIFIER_TYPE::CUSTOM, WORD priority = 0, DOUBLE fallbackScope = 0, const std::wstring &value = L""): + wIndex (index), eType (type), wPriority (priority), dFallbackScope (fallbackScope), swValue (value) {} + } QUALIFIER; + typedef struct _QUALIFIER_SET + { + WORD wIndex = 0; + std::vector verQuals; + _QUALIFIER_SET (WORD index = 0, std::vector &quals = {}): + wIndex (index), verQuals (quals) {} + } QUALIFIER_SET; + typedef struct _DECISION + { + WORD wIndex = 0; + std::vector verQualSets; + _DECISION (WORD index, std::vector &qualsets = {}): + wIndex (index), verQualSets (qualsets) {} + } DECISION; + + // ResourceMap & ResourceMap2 + + typedef struct _HSCHEMA_REF_BLOCK + { + HSCHEMA_VERSION_INFO verHschema; // hierarchical schema version info + WORD wUniIdLength = 0; // length of unique id in characters, null-terminator included + WORD wUnknown1 = -1; // unknown, zero + DWORD dwUnknown2 = 0; // unknown + DWORD dwUnknown3 = 0; // unknown + std::wstring swUniqueId = L""; // unique id + } HSCHEMA_REF_BLOCK; + enum class RES_VALUE_TYPE: DWORD + { + STRING = 0, // String (0) + PATH = 1, // Path (1) + EMBEDDEDDATA = 2, // EmbeddedData (2) + ASCIISTRING = 3, // AsciiString (3) + UTF8STRING = 4, // Utf8String (4) + ASCIIPATH = 5, // AsciiPath (5) + UTF8PATH = 6 // Utf8Path (6) + }; + typedef struct _RES_VALUE_TYPE_TABLE + { + DWORD dwUnknown1 = 0; // unknown, 4 + DWORD dwResType = -1; // resource value type + } RES_VALUE_TYPE_TABLE; + typedef struct _ITEM_ITEMINFO_GROUP_TABLE_ENTRY + { + WORD wFirstIndexProperty = 0; // index property of first resource item + WORD wItemInfoGroupIndex = 0; // index of iteminfo group + } ITEM_ITEMINFO_GROUP_TABLE_ENTRY; + typedef struct _ITEMINFO_GROUP_TABLE_ENTRY + { + WORD wItemInfoCount = 0; // number of iteminfos in this group + WORD wFirstItemIndex = 0; // index of the first iteminfo in this group + } ITEMINFO_GROUP_TABLE_ENTRY; + typedef struct _ITEM_ITEMINFO_TABLE_ENTRY + { + WORD wDecisionIndex = 0; // index of decision + WORD wFirstCandiIndex = 0; // index of first candidate + } ITEM_ITEMINFO_TABLE_ENTRY; + typedef struct _TABLE_EXT_BLOCK + { + DWORD dwItemAdditEntCount = 0; // number of additional entries of the item to iteminfo group table + DWORD dwItemGroupAdditEntCount = 0; // number of additional entries of the item info group table + DWORD dwItemTableAdditEntCount = 0; // number of additional entries of the iteminfo table + } TABLE_EXT_BLOCK; + typedef BYTE CANDIDATE_TYPE; + typedef struct _CANDIDATE0_DATA + { + BYTE bResValueType = 0; // resource value type, specified as an index into the resource value type table + WORD wEmbeddedLength = 0; // embedded data length + DWORD dwEmbeddedOffset = 0; // offset of the embedded data in the embedded data block + } CANDIDATE0_DATA; + typedef struct _CANDIDATE1_DATA + { + BYTE bResValueType = 0; // resource value type, specified as an index into the resource value type table + WORD wSrcFile = 0; // source file + WORD wDataIndex = 0; // index of the data item storing the data + WORD wSectIndex = 0; // section index of the Data Item Section storing the data + } CANDIDATE1_DATA; + + // DataItem + + typedef struct _STORED_STRING_INFO + { + WORD wStringOffset = 0; // string offset, relative to start of stored data + WORD wStringLength = 0; // string length in bytes + } STORED_STRING_INFO; + typedef struct _STORED_BLOB_INFO + { + DWORD dwBlobOffset = 0; // blob offset, relative to start of stored data + DWORD dwBlobLength = 0; // blob length in bytes + } STORED_BLOB_INFO; + + // ReferencedFile + + typedef struct _REF_FOLDER_INFO + { + WORD wUnknown1 = -1; // unknown, zero + WORD wParentIndex = 0xFFFF; // index of parent folder, 0xFFFF if no parent exists (root) + WORD wFolderCount = 0; // number of folders in this folder + WORD wFirstFolderIndex = 0; // index of first folder in this folder + WORD wFileCount = 0; // number of files in this folder + WORD wFirstFileIndex = 0; // index of first file in this folder + WORD wFolderNameLength = 0; // length of folder name in characters + WORD wFolderFullPathLength = 0; // length of full folder path + DWORD dwFolderNameOffset = 0; // offset of folder name in Unicode name block + } REF_FOLDER_INFO; + typedef struct _REF_FILE_INFO + { + WORD wUnknown1 = 0; // unknown + WORD wParentIndex = 0; // index of parent folder + WORD wFileFullPathLength = 0; // length of full file path + WORD wFileNameLength = 0; // length of file name in characters + DWORD dwFileNameOffset = 0; // offset of file name in Unicode name block + } REF_FILE_INFO; + + struct basic_sect + { + section § + basic_sect (section &s): sect (s) {} + explicit operator section () { return sect; } + SectionType type () const { return sect.type (); } + }; + struct basic_sect_func + { + public: + virtual bool valid () = 0; + virtual void reset () = 0; + virtual bool parse () = 0; + }; + struct sect_pridesp; // PriDescriptor PRI ÃèÊö·û - °üº¬ÎļþÕûÌå½á¹¹ºÍÒýÓÃÐÅÏ¢ + struct sect_hierasche; // HierarchicalSchema & HierarchicalSchemaEx ²ã´Î½á¹¹Ä£Ê½ - ¶¨Òå×ÊÔ´ÃüÃû¿Õ¼äºÍ²ã´Î½á¹¹ + struct sect_decinfo; // DecisionInfo ¾ö²ßÐÅÏ¢ - ¹ÜÀí×ÊÔ´ÏÞ¶¨·ûºÍ¾ö²ßÂß¼­ + struct sect_resmap; // ResourceMap & ResourceMap2 ×ÊÔ´Ó³Éä - ½«×ÊÔ´ÏîÓ³Éäµ½¾ßÌåºòѡֵ + struct sect_dataitem; // DataItem Êý¾ÝÏî - ´æ´¢Êµ¼ÊµÄ×ÊÔ´Êý¾Ý + struct sect_revmap; // ReverseMap ·´ÏòÓ³Éä - Ìṩ´Ó×ÊÔ´Ãûµ½IDµÄÓ³Éä + struct sect_reffile; // ReferencedFile ÒýÓÃÎļþ - ¹ÜÀíÒýÓõÄÍⲿÎļþ + struct sect_unknown; // Unknown δ֪ÀàÐÍ - ´¦Àíδʶ±ðµÄ½ÚÇø + + template struct ref_sect + { + static_assert (std::is_base_of ::value, "SectionType must derive from basic_sect"); + int index; + ref_sect (int sect_index = -1): index (sect_index) {} + using sect_type = SectionType; + explicit operator int () { return index; } + bool valid () const { return index != -1; } + void reset () { index = -1; } + }; + struct sect_pridesp: public basic_sect, public basic_sect_func + { + sect_pridesp (section &s): basic_sect (s) + { + if (s.type () != SectionType::PriDescriptor) throw std::exception ("Error: Section type error."); + } + struct + { + WORD wFlags = 0; // ±êÖ¾ / flags + WORD wIncFileListIndex = -1; // °üº¬ÎļþÁбí½Ú£¨Included File List£©Ë÷Òý£¬Èô²»´æÔÚÔòΪ 0xFFFF + WORD wUnknown1 = -1; // δ֪£¬0 + WORD wHieraScheCount = 0; // Hierarchical Schema ½ÚÊýÁ¿ + WORD wDecInfoCount = 0; // Decision Info ½ÚÊýÁ¿ + WORD wResMapCount = 0; // Resource Map ½ÚÊýÁ¿ + WORD wResMapBegIndex = -1; // Ö÷×ÊÔ´Ó³É䣨primary resource map£©µÄ½ÚË÷Òý£¬ÈôÎÞÔò 0xFFFF + WORD wRefFileCount = 0; // Referenced File ½ÚÊýÁ¿ + WORD wDataItemCount = 0; // Data Item ½ÚÊýÁ¿ + WORD wUnknown2 = -1; // δ֪£¬0 + } content; + std::vector > vec_ref_hs; + std::vector > vec_ref_deci; + std::vector > vec_ref_rm; + std::vector > vec_ref_rf; + std::vector > vec_ref_dati; + ref_sect primary_resmap; + bool valid () { return content.wUnknown1 == 0 && content.wUnknown2 == 0; } + void reset () + { + vec_ref_hs.clear (); + vec_ref_deci.clear (); + vec_ref_rm.clear (); + vec_ref_rf.clear (); + vec_ref_dati.clear (); + primary_resmap.reset (); + content = {0, -1, -1, 0, 0, 0, -1, 0, 0, -1}; + } + bool parse () + { + reset (); + sect.childst.seek (); + DWORD dwContent = 0; + sect.childst.ifile->Read (&content, sizeof (content), &dwContent); + if (!valid ()) return false; + if (content.wResMapBegIndex != 0xFFFF) primary_resmap.index = content.wResMapBegIndex; + for (size_t i = 0; i < content.wHieraScheCount; i ++) + { + ref_sect ref_sect_hs; + UINT16 u16 = 0; + sect.childst.ifile->Read (&u16, sizeof (u16), nullptr); + ref_sect_hs.index = u16; + vec_ref_hs.push_back (ref_sect_hs); + } + for (size_t i = 0; i < content.wDecInfoCount; i ++) + { + ref_sect ref_sect_di; + UINT16 u16 = 0; + sect.childst.ifile->Read (&u16, sizeof (u16), nullptr); + ref_sect_di.index = u16; + vec_ref_deci.push_back (ref_sect_di); + } + for (size_t i = 0; i < content.wResMapCount; i ++) + { + ref_sect ref_sect_rm; + UINT16 u16 = 0; + sect.childst.ifile->Read (&u16, sizeof (u16), nullptr); + ref_sect_rm.index = u16; + vec_ref_rm.push_back (ref_sect_rm); + } + for (size_t i = 0; i < content.wRefFileCount; i ++) + { + ref_sect ref_sect_rf; + UINT16 u16 = 0; + sect.childst.ifile->Read (&u16, sizeof (u16), nullptr); + ref_sect_rf.index = u16; + vec_ref_rf.push_back (ref_sect_rf); + } + for (size_t i = 0; i < content.wDataItemCount; i ++) + { + ref_sect ref_sect_di; + UINT16 u16 = 0; + sect.childst.ifile->Read (&u16, sizeof (u16), nullptr); + ref_sect_di.index = u16; + vec_ref_dati.push_back (ref_sect_di); + } + return true; + } + }; + struct sect_hierasche: public basic_sect, public basic_sect_func + { + struct + { + struct + { + WORD wUnknown1 = 0; // δ֪£¬1 + WORD wUniqRMNameLen = 0; // ×ÊÔ´Ó³ÉäΨһÃû³¤¶È£¨×Ö·ûÊý£¬º¬ÖÕÖ¹·û£© + WORD wResMapNameLen = 0; // ×ÊÔ´Ó³ÉäÃû³Æ³¤¶È£¨×Ö·ûÊý£¬º¬ÖÕÖ¹·û£© + WORD wUnknown2 = -1; // unknown, zero + } part1; + struct + { + // hname ±êʶ·û£¨½ö extended ´æÔÚ£© + // hname identifier: only present in the extended Hierarchical Schema Section. + // Observed values are "[def_hnames] \0" and "[def_hnamesx] \0". + CHAR szHNameExt [16] = {0}; + } part2; + struct + { + HSCHEMA_VERSION_INFO verSchema; // ²ã´Î»¯ schema °æ±¾ÐÅÏ¢ + } part3; + struct + { + std::wstring swUniqueRMName = L""; // ×ÊÔ´Ó³ÉäµÄΨһÃû£¨unique name£© + std::wstring swResMapName = L""; // name of resource map + WORD wUnknown3 = -1; // unknown, zero + WORD wMaxFullPathLength = 0; // length of longest full path of all resource names + WORD wUnknown3_5 = -1; // unknown, zero + DWORD dwResNameCount = 0; // number of resource names, usually number of scopes + items + DWORD dwScopeCount = 0; // number of scopes + DWORD dwItemsCount = 0; // number of items + DWORD dwUniNameLemgth = 0; // length of Unicode name block + DWORD dwUnknown4 = 0; // unknown + // unknown at 70 + ?: only present in the extended Hierarchical + // Schema Section and if hname identifier is "[def_hnamesx] \0". + DWORD dwUnknown5 = 0; + void *get_buf_first_dir () { return &wUnknown3; } + size_t get_buf_size_of () + { + return sizeof (wUnknown3) + sizeof (wMaxFullPathLength) + sizeof (wUnknown3_5) + + sizeof (dwScopeCount) + sizeof (dwItemsCount) + sizeof (dwResNameCount) + + sizeof (dwUniNameLemgth) + sizeof (dwUnknown4) + + sizeof (dwUnknown5); + } + } part4; + } content; + BOOL ex = FALSE; + BOOL exHName = FALSE; + std::vector vec_scope_and_items; + std::vector vec_scope_ex; + std::vector vec_item_index; + std::vector vec_scopes; + std::vector vec_items; + sect_hierasche (section &s): basic_sect (s) + { + if (s.type () != SectionType::HierarchicalSchema && s.type () != SectionType::HierarchicalSchemaEx) throw std::exception ("Error: Section type error."); + if (s.type () == SectionType::HierarchicalSchemaEx) ex = TRUE; + } + bool valid () + { + return content.part1.wUnknown1 == 1 && + content.part1.wUnknown2 == 0 && + content.part3.verSchema.dwUnknown1 == 0 && + content.part4.wUnknown3 == 0 && + content.part4.wUnknown3_5 == 0 && + content.part4.dwResNameCount == content.part3.verSchema.dwScopeCount + content.part3.verSchema.dwItemCount && + content.part4.dwScopeCount == content.part3.verSchema.dwScopeCount && + content.part4.dwItemsCount == content.part3.verSchema.dwItemCount && + content.part4.dwUniNameLemgth == content.part3.verSchema.dwItemCount && + content.part4.swUniqueRMName.length () == content.part1.wUniqRMNameLen && + content.part4.swResMapName.length () == content.part1.wResMapNameLen - 1; + } + void reset () + { + vec_scope_and_items.clear (); + vec_scope_ex.clear (); + vec_item_index.clear (); + vec_scopes.clear (); + vec_items.clear (); + ZeroMemory (&content.part1, sizeof (content.part1)); + content.part1.wUnknown2 = -1; + ZeroMemory (&content.part2, sizeof (content.part2)); + ZeroMemory (&content.part3, sizeof (content.part3)); + content.part3.verSchema.dwUnknown1 = -1; + content.part4.swUniqueRMName = L""; + content.part4.swResMapName = L""; + ZeroMemory (content.part4.get_buf_first_dir (), content.part4.get_buf_size_of ()); + content.part4.wUnknown3 = -1; + content.part4.wUnknown3_5 = -1; + } + bool parse () + { + reset (); + sect.childst.seek (); + sect.childst.ifile->Read (&content.part1, sizeof (content.part1), nullptr); + if (ex) + { + sect.childst.ifile->Read (&content.part2, sizeof (content.part2), nullptr); + if (pri_sectid (content.part2.szHNameExt, 16).equals ("[def_hnamesx]")) exHName = true; + else if (pri_sectid (content.part2.szHNameExt, 16).equals ("[def_hnames]")) exHName = false; + else return false; + } + else exHName = false; + #define readfromistream(_variable_) sect.childst.ifile->Read (&(_variable_), sizeof (_variable_), nullptr) + sect.childst.ifile->Read (&content.part3, sizeof (content.part3), nullptr); + ReadStringEndwithNull (sect.childst.ifile, content.part4.swUniqueRMName); + ReadStringEndwithNull (sect.childst.ifile, content.part4.swResMapName); + readfromistream (content.part4.wUnknown3); + readfromistream (content.part4.wMaxFullPathLength); + readfromistream (content.part4.wUnknown3_5); + readfromistream (content.part4.dwResNameCount); + readfromistream (content.part4.dwScopeCount); + readfromistream (content.part4.dwItemsCount); + readfromistream (content.part4.dwUniNameLemgth); + readfromistream (content.part4.dwUnknown4); + if (exHName) readfromistream (content.part4.dwUnknown5); + size_t silen = content.part3.verSchema.dwScopeCount + content.part3.verSchema.dwItemCount; + for (size_t cnt = 0; cnt < silen; cnt ++) + { + SCOPE_ITEM_INFO siinfo; + readfromistream (siinfo); + vec_scope_and_items.push_back (siinfo); + } + for (size_t cnt = 0; cnt < content.part3.verSchema.dwScopeCount; cnt ++) + { + SCOPE_EX_INFO sxinfo; + readfromistream (sxinfo); + vec_scope_ex.push_back (sxinfo); + } + for (size_t cnt = 0; cnt < content.part3.verSchema.dwItemCount; cnt ++) + { + ITEM_INDEX iindex = 0; + readfromistream (iindex); + vec_item_index.push_back (iindex); + } + ULARGE_INTEGER pos = {}; + sect.childst.ifile->Seek (lint (0), STREAM_SEEK_CUR, &pos); + ulint posw = pos; // unicodeDataOffset + ulint posa = ulint (pos) + ulint (content.part4.dwUniNameLemgth); // asciiDataOffset + vec_scopes.resize (content.part3.verSchema.dwScopeCount); + vec_items.resize (content.part3.verSchema.dwItemCount); + for (size_t i = 0; i < silen; i ++) + { + lint pos; + auto &sai = vec_scope_and_items [i]; + if (sai.name_in_ascii ()) pos = posa + lint (sai.name_offset ()); + else pos = posw + lint ((LONGLONG)sai.name_offset () * 2); + sect.childst.ifile->Seek (pos, STREAM_SEEK_SET, nullptr); + std::wstring name = L""; + if (sai.wFullPathLength != 0) + { + if (sai.name_in_ascii ()) name = StringToWString (ReadStringEndwithNullA (sect.childst.ifile)); + else name = ReadStringEndwithNullW (sect.childst.ifile); + } + else name = L""; + auto index = sai.index (); + if (sai.is_scope ()) + { + auto it = vec_scopes.begin () + index; + if (*it != nullptr) throw std::exception ("Error: invalid scope data in HierarchicalSchema(-ex) Section"); + else *it = RES_MAP_SCOPE::make (index, nullptr, name); + } + else + { + auto it = vec_items.begin () + index; + if (*it != nullptr) throw std::exception ("Error: invalid item data in HierarchicalSchema(-ex) Section"); + else *it = RES_MAP_ITEM::make (index, nullptr, name); + } + } + for (size_t i = 0; i < silen; i ++) + { + auto &sai = vec_scope_and_items [i]; + ITEM_INDEX index = sai.index () & 0xFFFF; + ITEM_INDEX parent = vec_scope_and_items [vec_scope_and_items [i].wParentScopeIndex].index () & 0xFFFF; + if (parent != 0xFFFF) + { + if (sai.is_scope ()) + { + if (parent != index) + { + auto it = vec_scopes.begin () + index; + (*it)->change_parent (*(vec_scopes.begin () + parent)); + } + } + else + { + auto it = vec_items.begin () + index; + (*it)->change_parent (*(vec_scopes.begin () + parent)); + } + } + } + for (size_t i = 0; i < content.part3.verSchema.dwScopeCount; i ++) + { + auto &s = vec_scope_ex [i]; + auto &sp = vec_scopes [i]; + for (size_t j = 0; j < s.wChildCount; j ++) + { + auto sai = vec_scope_and_items [s.wFirstChild + j]; + if (sai.is_scope ()) sp->vecChild.push_back (vec_scopes [(UINT16)(sai.index () & 0xFFFF)]); + else sp->vecChild.push_back (vec_items [(UINT16)(sai.index () & 0xFFFF)]); + } + } + #ifdef readfromistream + #undef readfromistream + #endif + return valid (); + } + }; + struct sect_decinfo: public basic_sect, public basic_sect_func + { + sect_decinfo (section &s): basic_sect (s) + { + if (s.type () != SectionType::DecisionInfo) throw std::exception ("Error: Section type error."); + } + struct + { + WORD wDistQualiCount = 0; // ²»Í¬µÄ distinct qualifiers ÊýÁ¿ / number of distinct qualifiers + WORD wQualifierCount = 0; // qualifiers ÊýÁ¿ + WORD wQualSetsCount = 0; // qualifier sets ÊýÁ¿ + WORD wDecisionCount = 0; // decisions ÊýÁ¿ / number of decisions + WORD wEntriesCount = 0; // index table ÌõÄ¿Êý / number of entries in the index table + WORD wQualiValueLength = 0; // qualifier value block ³¤¶È£¨×Ö·ûÊý£© / length of qualifier value block in characters + } content; + std::vector vec_qua_set; + std::vector vec_qua; + std::vector vec_dec; + bool valid () + { + return content.wDecisionCount || + content.wQualifierCount || + content.wDistQualiCount || + content.wQualSetsCount || + content.wEntriesCount || + content.wQualiValueLength || + vec_qua.size () || + vec_qua_set.size () || + vec_dec.size () || + 0; + } + void reset () + { + vec_qua.clear (); + vec_qua_set.clear (); + vec_dec.clear (); + ZeroMemory (&content, sizeof (content)); + } + bool parse () + { + reset (); + IStream *&fp = sect.childst.ifile; + sect.childst.seek (); + fp->Read (&content, sizeof (content), nullptr); + std::vector vec_dec_info; + std::vector vec_qua_set_info; + std::vector vec_qua_info; + std::vector vec_dis_qua_info; + #define counter(_count_, _variable_) for (size_t _variable_ = 0, _counter_##_variable_##_total_ = _count_; _variable_ < _counter_##_variable_##_total_; _variable_ ++) + counter (content.wDecisionCount, i) + { + DECISION_INFO dec; + fp->Read (&dec, sizeof (dec), nullptr); + vec_dec_info.push_back (dec); + } + counter (content.wQualSetsCount, i) + { + QUALIFIER_SET_INFO qua_set; + fp->Read (&qua_set, sizeof (qua_set), nullptr); + vec_qua_set_info.push_back (qua_set); + } + counter (content.wQualifierCount, i) + { + QUALIFIER_INFO qua; + fp->Read (&qua, sizeof (qua), nullptr); + if (qua.wUnknown1 != 0) throw std::exception ("Error: invalid data in DecisionInfo Section"); + vec_qua_info.push_back (qua); + } + counter (content.wDistQualiCount, i) + { + DISTINCE_QUALIFIER_INFO dist; + fp->Read (&dist, sizeof (dist), nullptr); + vec_dis_qua_info.push_back (dist); + } + std::vector indexs; + counter (content.wEntriesCount, i) + { + ITEM_INDEX index; + fp->Read (&index, sizeof (index), nullptr); + indexs.push_back (index); + } + ULARGE_INTEGER ul; + fp->Seek (lint (0), STREAM_SEEK_CUR, &ul); + ulint dspos = ul; + counter (content.wQualifierCount, i) + { + auto dinfo = vec_dis_qua_info [vec_qua_info [i].wDistQualiIndex]; + auto qinfo = vec_qua_info [i]; + fp->Seek (lint (dspos + ulint (dinfo.wQualiValueOffset * 2)), STREAM_SEEK_SET, nullptr); + std::wstring value = ReadStringEndwithNullW (fp); + QUALIFIER qual (i, (QUALIFIER_TYPE)dinfo.wQualiType, qinfo.wPriority, (double)qinfo.wFallbackScore * 0.001, value); + vec_qua.push_back (qual); + } + counter (content.wQualSetsCount, i) + { + std::vector quals; + auto qset = vec_qua_set_info [i]; + counter (qset.wQualiSetsCount, j) + { + auto &ind = indexs [qset.wFirstQualiIndex + j]; + auto &qual = vec_qua [ind]; + quals.push_back (qual); + } + vec_qua_set.emplace_back (QUALIFIER_SET (i, quals)); + } + counter (content.wDecisionCount, i) + { + auto &dec = vec_dec_info [i]; + std::vector qsets; + counter (dec.wQualiSetsCount, j) + { + auto &ind = indexs [dec.wFirstQualiIndex + j]; + auto qset = qsets [ind]; + qsets.emplace_back (qset); + } + vec_dec.push_back (DECISION (i, qsets)); + } + #ifdef counter + #undef counter + #endif + return valid (); + } + }; + struct sect_resmap: public basic_sect + { + sect_resmap (section &s): basic_sect (s) + { + if (s.type () != SectionType::ResourceMap && s.type () != SectionType::ResourceMap2) throw std::exception ("Error: Section type error."); + if (s.type () == SectionType::ResourceMap2) ver2 = true; + else ver2 = false; + } + struct + { + WORD wEnvRefLength = 0; // length of environment references block + WORD wRefCount = 0; // number of references in environment references block + WORD wHSSectIndex = 0; // section index of Hierarchical Schema Section + WORD wHSRefLength = 0; // length of hierarchical schema reference block + WORD wDecInfSectIndex = 0; // section index of Decision Info Section + WORD wResTypeEntCount = 0; // number of entries in resource value type table + WORD wItemEntCount = 0; // number of entries in item to iteminfo group table + WORD wItemGroupEntCount = 0; // number of entries in iteminfo group table + DWORD dwItemTableEntCount = 0; // number of entries in iteminfo table + DWORD dwCandidateCount = 0; // number of candidates + DWORD dwEmbededDataCount = 0; // length of embedded data bloc + DWORD dwTableExtCount = 0; // length of table extension block + } content; + BOOL ver2 = FALSE; + bool valid () + { + UINT64 *p = (UINT64 *)&content; + bool res = false; + size_t len = sizeof (content) / sizeof (UINT64); + for (size_t i = 0; i < len; i ++) res = res || p [i]; + return res; + } + void reset () + { + UINT64 *p = (UINT64 *)&content; + bool res = false; + size_t len = sizeof (content) / sizeof (UINT64); + for (size_t i = 0; i < len; i ++) p [i] = 0; + } + bool parse () + { + reset (); + auto &fp = sect.childst.ifile; + sect.childst.seek (); + ulint sectpos = 0; + fp->Seek (lint (0), STREAM_SEEK_SET, sectpos.ptr_union ()); + + } + }; + struct sect_dataitem: public basic_sect + { + sect_dataitem (section &s): basic_sect (s) + { + if (s.type () != SectionType::DataItem) throw std::exception ("Error: Section type error."); + } + struct + { + DWORD dwUnknown1 = -1; // unknown, zero + WORD wStrCount = 0; // number of stored strings + WORD wBlobCount = 0; // number of stored blobs + WORD wStoredLength = 0; // total length of stored data + } content; + }; + struct sect_reffile: public basic_sect + { + sect_reffile (section &s): basic_sect (s) + { + if (s.type () != SectionType::ReferencedFile) throw std::exception ("Error: Section type error."); + } + struct + { + WORD wRootCount = 0; // number of roots + WORD wFolderCount = 0; // number of folders + WORD wFileCount = 0; // number of folders + WORD wUnknown1 = -1; // unknown, zero + DWORD dwNameLength = 0; // length of Unicode name block in characters + } content; + }; + struct sect_revmap: public basic_sect + { + sect_revmap (section &s): basic_sect (s) + { + if (s.type () != SectionType::ReverseMap) throw std::exception ("Error: Section type error."); + } + struct + { + DWORD dwItemsNumber = 0; + DWORD dwCheckCode = 0; + std::vector adwMap; + WORD wFullPathLength = 0; + DWORD dwEntries = 0; + DWORD dwScopes = 0; + DWORD dwCheckItemsNumber = 0; + DWORD dwUnicodeDataLength = 0; + DWORD dwSkipPadding = 0; + std::vector aobjScopes; + std::vector aobjScopeExts; + std::vector awItemIndexs; + LONG lDataOffsetW = 0; + LONG lDataOffsetA = 0; + } content; + }; + struct sect_unknown: public basic_sect + { + sect_unknown (section &s): basic_sect (s) {} + struct + { + DWORD dwLength = 0; + std::vector abContents; + } content; + }; +} class prifile { private: IStream *pfile = nullptr; head header; foot footer; std::vector toclist; + std::vector
sectlist; public: - bool load (IStream *ifile) + bool close () { - if (!ifile) return false; header = head (); footer = foot (); + toclist.clear (); + sectlist.clear (); + if (pfile) pfile->Release (); + pfile = nullptr; + } + bool load (IStream *ifile) + { + close (); + if (!ifile) return false; ifile->Seek (lint (0), STREAM_SEEK_SET, nullptr); DWORD dwhead = 0, dwfoot = 0; ifile->Read (&header, sizeof (header), &dwhead); @@ -123,10 +1173,11 @@ class prifile if (!dwfoot) return false; if (!footer.valid (header)) return false; pfile = ifile; - bool res = inittoc (); + inittoc (); + initsect (); return true; } - bool inittoc () + void inittoc () { toclist.clear (); pfile->Seek (lint (header.dwToCOffset), STREAM_SEEK_SET, nullptr); @@ -138,4 +1189,25 @@ class prifile toclist.push_back (toc); } } + void initsect () + { + sectlist.clear (); + for (size_t i = 0; i < header.wSectCount; i ++) + { + pfile->Seek (lint (header.dwSectStartOffset + toclist [i].dwSectOffset), STREAM_SEEK_SET, nullptr); + section sect (pfile); + DWORD dwHead = 0, dwFoot = 0; + pfile->Read (§.head, sizeof (sect.head), &dwHead); + pfile->Seek (lint (sect.head.dwLength - 16 - 24), STREAM_SEEK_CUR, nullptr); + pfile->Read (§.foot, sizeof (sect.foot), &dwFoot); + pfile->Seek (lint (32 - sect.head.dwLength), STREAM_SEEK_CUR, nullptr); + ULARGE_INTEGER pos = {}; + pfile->Seek (lint (0), STREAM_SEEK_CUR, &pos); + sect.childst.set ( + pos.QuadPart, + sect.head.dwLength - 16 - 24 + ); + sectlist.push_back (sect); + } + } }; \ No newline at end of file diff --git a/priread/priread.vcxproj b/priread/priread.vcxproj index 227b2b3..dad6f30 100644 --- a/priread/priread.vcxproj +++ b/priread/priread.vcxproj @@ -145,6 +145,8 @@ + + diff --git a/priread/priread.vcxproj.filters b/priread/priread.vcxproj.filters index 9b04e58..e6067f0 100644 --- a/priread/priread.vcxproj.filters +++ b/priread/priread.vcxproj.filters @@ -30,6 +30,12 @@ 头文件 + + 头文件 + + + 头文件 +