From 733c2ca4f002ab63c44a837b018169f1c4a0c76c Mon Sep 17 00:00:00 2001 From: Bruce Date: Sun, 2 Nov 2025 22:31:16 +0800 Subject: [PATCH] Pri Reader has problems. --- pkgread/norstr.h | 118 +- priread/nstring.h | 124 +- priread/prifile.h | 2136 ++++++++++++++++++++++++++----- priread/priread.vcxproj | 1 + priread/priread.vcxproj.filters | 3 + priread/themeinfo.h | 40 + 6 files changed, 1989 insertions(+), 433 deletions(-) create mode 100644 priread/themeinfo.h diff --git a/pkgread/norstr.h b/pkgread/norstr.h index 98e8434..8b6f4b8 100644 --- a/pkgread/norstr.h +++ b/pkgread/norstr.h @@ -100,72 +100,96 @@ template , typename AL = std::all } 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 _local_strlen = [] (const E *p) -> size_t { + size_t cnt = 0; + while (*(p + cnt)) { cnt ++; } + return cnt; }; - 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) + const E *pl = l.c_str (); + const E *pr = r.c_str (); + while (*pl && is_blank (*pl)) ++ pl; + while (*pr && is_blank (*pr)) ++ pr; + const E *el = l.c_str () + _local_strlen (l.c_str ()); + const E *er = r.c_str () + _local_strlen (r.c_str ()); + while (el > pl && is_blank (*(el - 1))) --el; + while (er > pr && is_blank (*(er - 1))) --er; + while (pl < el && pr < er) { - 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)) + if (is_blank (*pl) && is_blank (*pr)) { - skip_blank (it_l, end_l); - skip_blank (it_r, end_r); + while (pl < el && is_blank (*pl)) ++pl; + while (pr < er && is_blank (*pr)) ++pr; + continue; + } + else if (is_blank (*pl)) + { + while (pl < el && is_blank (*pl)) ++pl; + continue; + } + else if (is_blank (*pr)) + { + while (pr < er && is_blank (*pr)) ++pr; + continue; } } + if (l0km::tolower (*pl) != l0km::tolower (*pr)) return false; + ++ pl; + ++ pr; } - skip_blank (it_l, end_l); - skip_blank (it_r, end_r); - return it_l == end_l && it_r == end_r; + while (pl < el && is_blank (*pl)) ++ pl; + while (pr < er && is_blank (*pr)) ++ pr; + return pl == el && pr == er; } 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 _local_strlen = [] (const E *p) -> size_t { + size_t cnt = 0; + while (*(p + cnt)) { cnt ++; } + return cnt; }; - 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) + const E *pl = l.c_str (); + const E *pr = r.c_str (); + while (*pl && is_blank (*pl)) ++ pl; + while (*pr && is_blank (*pr)) ++ pr; + const E *el = l.c_str () + _local_strlen (l.c_str ()); + const E *er = r.c_str () + _local_strlen (r.c_str ()); + while (el > pl && is_blank (*(el - 1))) -- el; + while (er > pr && is_blank (*(er - 1))) -- er; + while (pl < el && pr < er) { - 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)) + if (is_blank (*pl) && is_blank (*pr)) { - 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); - } + while (pl < el && is_blank (*pl)) ++pl; + while (pr < er && is_blank (*pr)) ++pr; + continue; + } + else if (is_blank (*pl)) + { + while (pl < el && is_blank (*pl)) ++pl; + continue; + } + else if (is_blank (*pr)) + { + while (pr < er && is_blank (*pr)) ++pr; + continue; } } + E chl = l0km::tolower (*pl); + E chr = l0km::tolower (*pr); + if (chl != chr) return (int64_t)chl - (int64_t)chr; + ++ pl; + ++ pr; } - 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; + while (pl < el && is_blank (*pl)) ++ pl; + while (pr < er && is_blank (*pr)) ++ pr; + if (pl == el && pr == er) return 0; + if (pl == el) return -1; + if (pr == er) return 1; + return (int64_t)l0km::tolower (*pl) - (int64_t)l0km::tolower (*pr); } template bool IsNormalizeStringEquals (const CharT *l, const CharT *r, bool includemidblank = false) { diff --git a/priread/nstring.h b/priread/nstring.h index b61c94f..ba0e231 100644 --- a/priread/nstring.h +++ b/priread/nstring.h @@ -28,31 +28,37 @@ namespace l0km } inline char toupper (char ch) { + if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).toupper (ch); } inline char tolower (char ch) { + if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).tolower (ch); } inline wchar_t toupper (wchar_t ch) { + if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).toupper (ch); } inline wchar_t tolower (wchar_t ch) { + if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).tolower (ch); } inline int toupper (int ch) { + if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).toupper (ch); } inline int tolower (int ch) { + if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).tolower (ch); } @@ -100,72 +106,96 @@ template , typename AL = std::all } 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 _local_strlen = [] (const E *p) -> size_t { + size_t cnt = 0; + while (*(p + cnt)) { cnt ++; } + return cnt; }; - 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) + const E *pl = l.c_str (); + const E *pr = r.c_str (); + while (*pl && is_blank (*pl)) ++ pl; + while (*pr && is_blank (*pr)) ++ pr; + const E *el = l.c_str () + _local_strlen (l.c_str ()); + const E *er = r.c_str () + _local_strlen (r.c_str ()); + while (el > pl && is_blank (*(el - 1))) --el; + while (er > pr && is_blank (*(er - 1))) --er; + while (pl < el && pr < er) { - 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)) + if (is_blank (*pl) && is_blank (*pr)) { - skip_blank (it_l, end_l); - skip_blank (it_r, end_r); + while (pl < el && is_blank (*pl)) ++pl; + while (pr < er && is_blank (*pr)) ++pr; + continue; + } + else if (is_blank (*pl)) + { + while (pl < el && is_blank (*pl)) ++pl; + continue; + } + else if (is_blank (*pr)) + { + while (pr < er && is_blank (*pr)) ++pr; + continue; } } + if (l0km::tolower (*pl) != l0km::tolower (*pr)) return false; + ++ pl; + ++ pr; } - skip_blank (it_l, end_l); - skip_blank (it_r, end_r); - return it_l == end_l && it_r == end_r; + while (pl < el && is_blank (*pl)) ++ pl; + while (pr < er && is_blank (*pr)) ++ pr; + return pl == el && pr == er; } 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 _local_strlen = [] (const E *p) -> size_t { + size_t cnt = 0; + while (*(p + cnt)) { cnt ++; } + return cnt; }; - 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) + const E *pl = l.c_str (); + const E *pr = r.c_str (); + while (*pl && is_blank (*pl)) ++ pl; + while (*pr && is_blank (*pr)) ++ pr; + const E *el = l.c_str () + _local_strlen (l.c_str ()); + const E *er = r.c_str () + _local_strlen (r.c_str ()); + while (el > pl && is_blank (*(el - 1))) -- el; + while (er > pr && is_blank (*(er - 1))) -- er; + while (pl < el && pr < er) { - 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)) + if (is_blank (*pl) && is_blank (*pr)) { - 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); - } + while (pl < el && is_blank (*pl)) ++pl; + while (pr < er && is_blank (*pr)) ++pr; + continue; + } + else if (is_blank (*pl)) + { + while (pl < el && is_blank (*pl)) ++pl; + continue; + } + else if (is_blank (*pr)) + { + while (pr < er && is_blank (*pr)) ++pr; + continue; } } + E chl = l0km::tolower (*pl); + E chr = l0km::tolower (*pr); + if (chl != chr) return (int64_t)chl - (int64_t)chr; + ++ pl; + ++ pr; } - 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; + while (pl < el && is_blank (*pl)) ++ pl; + while (pr < er && is_blank (*pr)) ++ pr; + if (pl == el && pr == er) return 0; + if (pl == el) return -1; + if (pr == er) return 1; + return (int64_t)l0km::tolower (*pl) - (int64_t)l0km::tolower (*pr); } template bool IsNormalizeStringEquals (const CharT *l, const CharT *r, bool includemidblank = false) { diff --git a/priread/prifile.h b/priread/prifile.h index 493337a..273703c 100644 --- a/priread/prifile.h +++ b/priread/prifile.h @@ -5,9 +5,28 @@ #include #include #include +#include +#include +#include +#include +#ifdef _CONSOLE +#include +#include +#endif #include "nstring.h" #include "localeex.h" +#include "themeinfo.h" +// #define UNALIGN_MEMORY +#ifdef UNALIGN_MEMORY +#pragma pack(push, 1) +#endif +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif struct destruct { std::function endtask = nullptr; @@ -114,6 +133,442 @@ std::wstring ReadStringEndwithNull (IStream *ifile, std::wstring &ret) { return ret = ReadStringEndwithNullW (ifile); } +std::string ReadStringA (IStream *pStream, size_t length) +{ + if (!pStream || length <= 0) return ""; + std::string result; + result.resize (length); + ULONG cbRead = 0; + HRESULT hr = pStream->Read (&result [0], length, &cbRead); + if (FAILED (hr) || cbRead == 0) + { + result.clear (); + return result; + } + if (cbRead < (ULONG)length) result.resize (cbRead); + return result; +} +std::wstring ReadStringW (IStream *pStream, size_t length) +{ + if (!pStream || length <= 0) return L""; + std::wstring result; + result.resize (length); + ULONG cbRead = 0; + HRESULT hr = pStream->Read (&result [0], length * sizeof (WCHAR), &cbRead); + if (FAILED (hr) || cbRead == 0) + { + result.clear (); + return result; + } + if (cbRead < (ULONG)(length * sizeof (WCHAR))) result.resize (cbRead / sizeof (WCHAR)); + return result; +} +enum class seekpos: DWORD +{ + start = STREAM_SEEK_SET, + current = STREAM_SEEK_CUR, + end = STREAM_SEEK_END +}; +class bytesstream +{ + std::vector bytes; + size_t pos = 0; + public: + using seekpos = ::seekpos; + // Îļþ³¤¶È/¾ø¶ÔÆ«ÒÆÎ»Öᣣ¨¶¼ÊÇ 0 Æðʼ£© + using fsize_t = uint64_t; + // ÎļþÖ¸ÕëÏà¶ÔÒÆ¶¯³¤¶È£¬ÕýÊýÏòÓÒ£¬¸ºÊýÏò×ó + using fmove_t = int64_t; + bool read (void *p, size_t size, size_t *ret = nullptr) + { + if (!p || size == 0) return false; + size_t available = 0; + if (pos < bytes.size ()) available = bytes.size () - pos; + size_t readSize = (available >= size) ? size : available; + if (readSize > 0) memcpy_s (p, size, bytes.data () + pos, readSize); + else memset (p, 0, size); + pos += size; + if (ret) *ret = readSize; + return true; + } + template ::value>::type> size_t read (T &var) + { + size_t ret = 0; + read (&var, sizeof (var), &ret); + return ret; + } + template ::value>::type> friend bytesstream &operator >> (bytesstream &s, T &variable) + { + s.read (&variable, sizeof (variable)); + return s; + } + friend bytesstream &operator >> (bytesstream &in, std::string &ret) + { + in.read_string_endwith_null (ret); + return in; + } + friend bytesstream &operator >> (bytesstream &in, std::wstring &ret) + { + in.read_string_endwith_null (ret); + return in; + } + bytesstream (const std::vector &vec): bytes (vec) {} + bytesstream (const BYTE *ptr, size_t len = 0): bytes (len, *ptr) {} + bytesstream () = default; + auto &data () { return bytes; } + void set (const std::vector &bver) + { + bytes = bver; + } + auto position () + { + if (pos > bytes.size ()) pos = bytes.size (); + return pos; + } + auto position (size_t v) { pos = v; if (pos > bytes.size ()) pos = bytes.size (); return pos; } + auto length () const { return bytes.size (); } + auto size () const { return length (); } + std::string read_string_endwith_null_a (); + std::wstring read_string_endwith_null_w (); + size_t read_string_endwith_null (std::string &ret); + size_t read_string_endwith_null (std::wstring &ret); + std::string read_string_a (size_t length); + std::wstring read_string_w (size_t length); + size_t read_string (size_t length, std::wstring &ret); + size_t read_string (size_t length, std::string &ret); + HRESULT seek (fmove_t movelen = 0, seekpos origin = seekpos::current, fsize_t *newpos = nullptr) + { + if (bytes.empty ()) return E_INVALIDARG; + int64_t newPosition = 0; + switch (origin) + { + case seekpos::start: + newPosition = movelen; + break; + case seekpos::current: + newPosition = static_cast (pos) + movelen; + break; + case seekpos::end: + newPosition = static_cast (bytes.size ()) + movelen; + break; + default: return E_INVALIDARG; + } + if (newPosition < 0) newPosition = 0; + pos = static_cast (newPosition); + if (newpos) *newpos = static_cast (pos); + return S_OK; + } + auto &buffer () const { return bytes; } + auto &buffer () { return bytes; } + size_t remain () const + { + if (pos > size ()) return 0; + return size () - pos; + } + void clear () + { + bytes.clear (); + pos = 0; + } + void resize (size_t len) { bytes.resize (len); } + const BYTE *ptr () const { return bytes.data (); } + BYTE *ptr () { return bytes.data (); } + template ::value>::type> + T read_bytes (size_t byteslen = sizeof (T), size_t *returnread = nullptr) + { + std::vector bytesbuf (byteslen); + size_t rl = 0; + read (bytesbuf.data (), byteslen, &rl); + if (returnread) *returnread = rl; + bytesbuf.resize (!rl ? sizeof (T) : rl); + return *(T *)bytesbuf.data (); + } +}; +std::string ReadStringEndwithNullA (bytesstream &stream) +{ + std::string result; + char ch = 0; + size_t cbRead = 0; + while (true) + { + if (!stream.read (&ch, 1, &cbRead) || cbRead == 0) break; + if (ch == '\0') break; + result.push_back (ch); + } + return result; +} +std::wstring ReadStringEndwithNullW (bytesstream &stream) +{ + std::wstring result; + WCHAR ch = 0; + size_t cbRead = 0; + while (true) + { + if (!stream.read (&ch, sizeof (WCHAR), &cbRead) || cbRead < sizeof (WCHAR)) break; + if (ch == L'\0') break; + result.push_back (ch); + } + return result; +} +std::string ReadStringEndwithNull (bytesstream &stream, std::string &ret) +{ + return ret = ReadStringEndwithNullA (stream); +} +std::wstring ReadStringEndwithNull (bytesstream &stream, std::wstring &ret) +{ + return ret = ReadStringEndwithNullW (stream); +} +std::string ReadStringA (bytesstream &stream, size_t length) +{ + if (length == 0) return ""; + std::string result (length, '\0'); + size_t cbRead = 0; + if (!stream.read (&result [0], length, &cbRead) || cbRead == 0) + { + result.clear (); + return result; + } + if (cbRead < length) result.resize (cbRead); + return result; +} +std::wstring ReadStringW (bytesstream &stream, size_t length) +{ + if (length == 0) return L""; + std::wstring result (length, L'\0'); + size_t cbRead = 0; + if (!stream.read (&result [0], length * sizeof (WCHAR), &cbRead) || cbRead == 0) + { + result.clear (); + return result; + } + if (cbRead < length * sizeof (WCHAR)) result.resize (cbRead / sizeof (WCHAR)); + return result; +} +std::string bytesstream::read_string_endwith_null_a () { return ReadStringEndwithNullA (*this); } +std::wstring bytesstream::read_string_endwith_null_w () { return ReadStringEndwithNullW (*this); } +size_t bytesstream::read_string_endwith_null (std::string &ret) +{ + return (ret = read_string_endwith_null_a ()).length (); +} +size_t bytesstream::read_string_endwith_null (std::wstring &ret) +{ + return (ret = read_string_endwith_null_w ()).length (); +} +std::string bytesstream::read_string_a (size_t length) { return ReadStringA (*this, length); } +std::wstring bytesstream::read_string_w (size_t length) { return ReadStringW (*this, length); } +size_t bytesstream::read_string (size_t length, std::wstring &ret) { return (ret = read_string_w (length)).length (); } +size_t bytesstream::read_string (size_t length, std::string &ret) { return (ret = read_string_a (length)).length (); } +// ×¢£ºÏú»Ùʱ²»»áÊÍ·ÅÖ¸Õë¡£½öÊÇΪһÖÖ²Ù×÷Àà +class istreamstream +{ + private: + // COM ½Ó¿Ú£ºÁ÷Ö¸Õë + IStream *comStream = nullptr; + // »º´æ£¬× 210 ×Ö½Ú + bytesstream bsCache; + // ½«»º´æÊÓΪ´°¿Ú£¬ÕâÀï¼Ç¼»º´æÏà¶ÔÓÚÎļþµÄλÖᣠ+ uint64_t ulWndOffset = 0; + static const size_t MAX_CACHE_SIZE = 210; + public: + // Îļþ³¤¶È/¾ø¶ÔÆ«ÒÆÎ»Öᣣ¨¶¼ÊÇ 0 Æðʼ£© + using fsize_t = uint64_t; + // ÎļþÖ¸ÕëÏà¶ÔÒÆ¶¯³¤¶È£¬ÕýÊýÏòÓÒ£¬¸ºÊýÏò×ó + using fmove_t = int64_t; + using seekpos = ::seekpos; + istreamstream (IStream *iptr): comStream (iptr) + { + // bsCache.buffer ().reserve (MAX_CACHE_SIZE); + } + auto &buffer () const { return bsCache; } + auto &buffer () { return bsCache; } + void set_stream (IStream *iptr) { comStream = iptr; } + IStream *get_stream () { return comStream; } + // read ´¦Àí»úÖÆ + // ¹¹½¨»º´æ£º»á¶ÁÈ¡× 210 ×ֽڵĻº´æ + // ¶ÁÈ¡»º´æ£ºÔÚ»º´æÖжÁÈ¡×Ö½Ú£¬Á÷Ö¸ÕëÓë×Ö½ÚÖ¸ÕëÒ»ÆðÒÆ¶¯¡£×Ö½ÚÖ¸Õë¾­¹ý¼ÆËãÒ»¶¨ÓëÁ÷Ö¸ÕëÏàµÈ¡£ + HRESULT read (void *buf, size_t size, size_t *readbytes = nullptr) + { + if (!comStream || !buf) return E_INVALIDARG; + if (position () < ulWndOffset || position () >= ulWndOffset + bsCache.size () || position () != ulWndOffset + position ()) bsCache.buffer ().clear (); + if (size > MAX_CACHE_SIZE) + { + bsCache.clear (); + ULONG cbread = 0; + HRESULT hr = comStream->Read (buf, size, &cbread); + if (readbytes) *readbytes = cbread; + return hr; + } + else if (bsCache.remain () < size) + { + bsCache.clear (); + bsCache.resize (MAX_CACHE_SIZE); + auto nowpos = position (); + ULONG cbread = 0; + HRESULT hr = comStream->Read (bsCache.ptr (), MAX_CACHE_SIZE, &cbread); + comStream->Seek (lint (nowpos), STREAM_SEEK_SET, nullptr); + ulWndOffset = nowpos; + bsCache.resize (cbread); + size_t bufread = 0; + bool res = bsCache.read (buf, size, &bufread); + if (readbytes) *readbytes = bufread; + comStream->Seek (lint (bufread), STREAM_SEEK_CUR, nullptr); + if (res) return S_OK; + else return FAILED (hr) ? hr : E_FAIL; + } + else + { + size_t bufread = 0; + bool res = bsCache.read (buf, size, &bufread); + if (readbytes) *readbytes = bufread; + comStream->Seek (lint (bufread), STREAM_SEEK_CUR, nullptr); + return res ? S_OK : E_FAIL; + } + } + // ʹÓó¡¾°ÓÐÏÞ£¬ÇÒ²»Ö§³Ö´«ÈëÖ¸Õë¡£ + template ::value>::type> + HRESULT read (T &variable, size_t *readbytes = nullptr) + { + return read (&variable, sizeof (variable), readbytes); + } + std::string read_string_endwith_null_a () { return ReadStringEndwithNullA (comStream); } + std::wstring read_string_endwith_null_w () { return ReadStringEndwithNullW (comStream); } + size_t read_string_endwith_null (std::string &ret) + { + return (ret = read_string_endwith_null_a ()).length (); + } + size_t read_string_endwith_null (std::wstring &ret) + { + return (ret = read_string_endwith_null_w ()).length (); + } + std::string read_string_a (size_t length) { return ReadStringA (comStream, length); } + std::wstring read_string_w (size_t length) { return ReadStringW (comStream, length); } + size_t read_string (size_t length, std::wstring &ret) { return (ret = read_string_w (length)).length (); } + size_t read_string (size_t length, std::string &ret) { return (ret = read_string_a (length)).length (); } + HRESULT write (const void *bytes, size_t size, size_t *writebytes = nullptr) + { + if (!comStream) return E_INVALIDARG; + ULONG retsize = 0; + HRESULT hr = comStream->Write (bytes, size, &retsize); + if (writebytes) *writebytes = retsize; + return hr; + } + // ʹÓó¡¾°ÓÐÏÞ£¬ÇÒ²»Ö§³Ö´«ÈëÖ¸Õë¡£ + template ::value>::type> + HRESULT write (const T &variable, size_t *writebytes = nullptr) + { + return write (&variable, sizeof (variable), writebytes); + } + HRESULT seek (fmove_t movelen = 0, seekpos origin = seekpos::current, fsize_t *newpos = nullptr) + { + if (!comStream) return E_INVALIDARG; + ulint ret = 0; + HRESULT hr = comStream->Seek (lint (movelen), (DWORD)origin, ret.ptr_union ()); + if ((movelen != 0 || origin != seekpos::current) && bsCache.size ()) bsCache.clear (); + if (newpos) *newpos = ret; + return hr; + } + fsize_t position () + { + fsize_t pos = 0; + seek (0, seekpos::current, &pos); + return pos; + } + HRESULT stat (STATSTG *data, DWORD statflags) + { + if (!comStream) return E_INVALIDARG; + return comStream->Stat (data, statflags); + } + HRESULT size (fsize_t newsize) + { + if (!comStream) return E_INVALIDARG; + return comStream->SetSize (ulint (newsize)); + } + fsize_t size () + { + STATSTG stg = {0}; + if (SUCCEEDED (stat (&stg, STATFLAG_NONAME))) return stg.cbSize.QuadPart; + else return 0; + } + HRESULT copy_to (istreamstream &pstm, fsize_t cb, fsize_t *pcbRead = nullptr, fsize_t *pcbWritten = nullptr) + { + if (!comStream) return E_INVALIDARG; + ulint r = 0, w = 0; + HRESULT hr = comStream->CopyTo (pstm.comStream, ulint (cb), r.ptr_union (), w.ptr_union ()); + if (pcbRead) *pcbRead = r; + if (pcbWritten) *pcbWritten = w; + return hr; + } + HRESULT commit (DWORD grfCommitFlags) + { + if (!comStream) return E_INVALIDARG; + return comStream->Commit (grfCommitFlags); + } + HRESULT revert () + { + if (!comStream) return E_INVALIDARG; + return comStream->Revert (); + } + HRESULT lock_region (fsize_t libOffset, fsize_t cb, DWORD dwLockType) + { + if (!comStream) return E_INVALIDARG; + return comStream->LockRegion (ulint (libOffset), ulint (cb), dwLockType); + } + HRESULT unlock_region (fsize_t libOffset, fsize_t cb, DWORD dwLockType) + { + if (!comStream) return E_INVALIDARG; + return comStream->UnlockRegion (ulint (libOffset), ulint (cb), dwLockType); + } + HRESULT clone (istreamstream &anotherptr) + { + if (!comStream) return E_INVALIDARG; + return comStream->Clone (&anotherptr.comStream); + } + template ::value>::type> + friend istreamstream &operator >> (istreamstream &in, T &variable) + { + in.read (variable); + return in; + } + template ::value>::type> + friend istreamstream &operator << (istreamstream &out, const T &variable) + { + out.write (variable); + return out; + } + friend istreamstream &operator >> (istreamstream &in, std::string &ret) + { + in.read_string_endwith_null (ret); + return in; + } + friend istreamstream &operator >> (istreamstream &in, std::wstring &ret) + { + in.read_string_endwith_null (ret); + return in; + } + operator IStream * () { return comStream; } + IStream *operator -> () { return comStream; } + template ::value>::type> + // ¶Áȡһ¸öÖµ£¬²¢ÅжÏÊÇ·ñ·ûºÏÔ¤ÆÚ¡£throwerror ÎªÕæÊ±£¬Èç¹ûÖµ²»·ûºÏÔ¤ÆÚÔòͨ¹ýÅ׳öÒì³£À´Åжϡ£·ñÔòֻͨ¹ý·µ»ØÖµÀ´Åжϡ£ + bool expect (const T &expect_value, bool throwerror = true, T *retvalue = nullptr) + { + T value; + this->read (value); + if (retvalue) *retvalue = value; + bool res = value == expect_value; + if (!res && throwerror) throw std::exception ("Unexpected value read."); + return res; + } + template ::value>::type> + T read_bytes (size_t byteslen = sizeof (T), size_t *returnread = nullptr) + { + std::vector bytesbuf (byteslen); + size_t rl = 0; + read (bytesbuf.data (), byteslen, &rl); + if (returnread) *returnread = rl; + bytesbuf.resize (!rl ? sizeof (T) : rl); + return *(T *)bytesbuf.data (); + } +}; // 0 1 // 012345678901234 @@ -139,6 +594,23 @@ enum class SectionType ReverseMap, // ·´ÏòÓ³Éä - Ìṩ´Ó×ÊÔ´Ãûµ½IDµÄÓ³Éä ReferencedFile // ÒýÓÃÎļþ - ¹ÜÀíÒýÓõÄÍⲿÎļþ }; +std::wstring EnumToStringW (SectionType value) +{ + switch (value) + { + case SectionType::PriDescriptor: return L"PriDescriptor"; break; + case SectionType::HierarchicalSchema: return L"HierarchicalSchema"; break; + case SectionType::HierarchicalSchemaEx: return L"HierarchicalSchemaEx"; break; + case SectionType::DecisionInfo: return L"DecisionInfo"; break; + case SectionType::ResourceMap: return L"ResourceMap"; break; + case SectionType::ResourceMap2: return L"ResourceMap2"; break; + case SectionType::DataItem: return L"DataItem"; break; + case SectionType::ReverseMap: return L"ReverseMap"; break; + case SectionType::ReferencedFile: return L"ReferencedFile"; break; + default: + case SectionType::Unknown: return L"Unknown"; break; + } +} struct head { @@ -163,10 +635,10 @@ struct head if (m7) szMagic [7] = m7; }); szMagic [7] = '\0'; - if (!stricmp (szMagic, "mrm_pri")) return false; + if (_stricmp (szMagic, "mrm_pri")) return false; switch (m7) { - case '0': case '1': case 'f': case 'F': break; + case '0': case '1': case '2': case 'f': case 'F': break; default: return false; } if (wPlaceholder1 != 0) return false; @@ -230,13 +702,11 @@ struct substream } 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); + istreamstream iss (ifile); + return iss.seek (offset, istreamstream::seekpos::start); } }; +struct prifile; struct section { section_header head; @@ -244,14 +714,14 @@ struct section substream childst; // Çë´Ó type ·½·¨»ñÈ¡ÀàÐÍ£¬¶ø²»ÊÇÖ±½Óͨ¹ý sect_type À´¶ÁÈ¡£¨ÒòΪδ³õʼ»¯£© SectionType sect_type = SectionType::Unknown; - section (IStream *&ifile): childst (ifile) {} + section (IStream *&ifile, prifile &prif): childst (ifile), pri_file (prif) {} 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; + if (pid.equals (PRI_SECT_ID_PRI_DESCRIPTOR)) sect_type = SectionType::PriDescriptor; 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; @@ -264,9 +734,26 @@ struct section } return sect_type; } + size_t length () const { return head.dwLength; } + prifile &pri_file; +#ifdef _CONSOLE + friend std::wostream &operator << (std::wostream &o, section &s) + { + return o << L"Section " << EnumToStringW (s.type ()) << L" Length " << s.head.dwLength; + } +#endif }; namespace pri { + 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 δ֪ÀàÐÍ - ´¦Àíδʶ±ðµÄ½ÚÇø + // PriDescriptorFlags enum class PRI_SEC_DESP: DWORD @@ -292,6 +779,10 @@ namespace pri DWORD dwCheckSum = 0; DWORD dwScopeCount = 0; // scope ÊýÁ¿ DWORD dwItemCount = 0; // item ÊýÁ¿ + bool empty () + { + return dwUnknown1 != 0; + } } HSCHEMA_VERSION_INFO; // ×ÊÔ´Ãû³Æ£¨scope/item£©°´ÒÔϸñʽ´æ´¢£¨Ê¾Àý×ֶΣ©£ºparent scope index¡¢full path ³¤¶È¡¢ // Ãû×ÖÊ××Öĸ£¨´óд£©¡¢Ãû×Ö³¤¶È¡¢Ãû×ÖÆ«ÒÆ¡¢index property µÈ¡£ @@ -317,6 +808,28 @@ namespace pri bool name_in_ascii () const { return bFlags & 0x20; } DWORD name_offset () const { return (DWORD)wNameOffset | ((DWORD)(bFlags & 0xF) << 16); } DWORD index () const { return wIndexProp; } + //friend istreamstream &operator >> (istreamstream &i, _SCOPE_ITEM_INFO &s) + //{ + // i >> s.wParentScopeIndex >> + // s.wFullPathLength; + // s.wchUpperFirst = i.read_bytes (sizeof (UINT16)); + // s.bNameLength = i.read_bytes (); + // s.bFlags = i.read_bytes (); + // s.wNameOffset = i.read_bytes (); + // s.wIndexProp = i.read_bytes (); + // return i; + //} + //friend bytesstream &operator >> (bytesstream &i, _SCOPE_ITEM_INFO &s) + //{ + // i >> s.wParentScopeIndex >> + // s.wFullPathLength; + // s.wchUpperFirst = i.read_bytes (sizeof (UINT16)); + // s.bNameLength = i.read_bytes (); + // s.bFlags = i.read_bytes (); + // s.wNameOffset = i.read_bytes (); + // s.wIndexProp = i.read_bytes (); + // return i; + //} } SCOPE_ITEM_INFO; typedef struct _SCOPE_EX_INFO { @@ -324,93 +837,69 @@ namespace pri 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 + //friend istreamstream &operator >> (istreamstream &i, _SCOPE_EX_INFO &e) + //{ + // i >> e.wScopeIndex >> + // e.wChildCount >> + // e.wFirstChild; + // i.expect (0, true, &e.wUnknown1); + // return i; + //} 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_SCOPE; 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; - } + RES_MAP_SCOPE *pParent = nullptr; + RES_MAP_ENTRY (ITEM_INDEX index = 0, RES_MAP_SCOPE *parent = {}, const std::wstring &name = L"", RES_MAP_OBJTYPE type = RES_MAP_OBJTYPE::ENTRY, bool setnull = true): + wIndex (index), strName (name), pParent (parent), eType (type), bIsNull (setnull) {} + std::wstring full_name (WCHAR divide = L'\\'); + size_t path (std::vector &output); 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; } + bool bIsNull = false; 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 + class RES_MAP_SCOPE: public RES_MAP_ENTRY { 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; + explicit RES_MAP_SCOPE (ITEM_INDEX index = 0, RES_MAP_SCOPE *parent = nullptr, const std::wstring &name = L"", bool setnull = true): + RES_MAP_ENTRY (index, parent, name, RES_MAP_OBJTYPE::SCOPE, setnull) {} + std::vector vecChild; }; + std::wstring RES_MAP_ENTRY::full_name (WCHAR divide) + { + if (strFullName.empty ()) + { + if (pParent) strFullName = pParent->full_name (divide) + divide + strName; + else strFullName = strName; + } + return strFullName; + } + size_t RES_MAP_ENTRY::path (std::vector &output) + { + output.clear (); + if (pParent) pParent->path (output); + output.push_back (strName); + return output.size (); + } 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); - } + RES_MAP_ITEM (ITEM_INDEX index = 0, RES_MAP_SCOPE *parent = nullptr, const std::wstring &name = L"", bool setnull = true): + RES_MAP_ENTRY (index, parent, name, RES_MAP_OBJTYPE::ITEM, setnull) {} }; // DecisionInfo @@ -447,13 +936,31 @@ namespace pri DEVICEFAMILY = 10, // É豸ϵÁÐ (10) CUSTOM = 11, // ×Ô¶¨Òå (11) }; + std::wstring EnumToStringW (QUALIFIER_TYPE value) + { + switch (value) + { + case QUALIFIER_TYPE::LANGUAGE: return L"Language"; break; + case QUALIFIER_TYPE::CONTRAST: return L"Contrast"; break; + case QUALIFIER_TYPE::SCALE: return L"Scale"; break; + case QUALIFIER_TYPE::HOMEREGION: return L"HomeRegion"; break; + case QUALIFIER_TYPE::TARGETSIZE: return L"TargetSize"; break; + case QUALIFIER_TYPE::LAYOUTDIR: return L"LayoutDir"; break; + case QUALIFIER_TYPE::THEME: return L"Theme"; break; + case QUALIFIER_TYPE::ALTERNATEFORM: return L"AlternateForm"; break; + case QUALIFIER_TYPE::DXFEATURELEVEL: return L"DxFeatureLevel"; break; + case QUALIFIER_TYPE::CONFIG: return L"Configure"; break; + case QUALIFIER_TYPE::DEVICEFAMILY: return L"DeviceFamily"; break; + case QUALIFIER_TYPE::CUSTOM: return L"Custom"; break; + } + } 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 + DWORD wQualiValueOffset = 0; // offset of qualifier value in qualifier value block, in characters } DISTINCE_QUALIFIER_INFO; typedef struct _QUALIFIER { @@ -468,15 +975,15 @@ namespace pri typedef struct _QUALIFIER_SET { WORD wIndex = 0; - std::vector verQuals; - _QUALIFIER_SET (WORD index = 0, std::vector &quals = {}): - wIndex (index), verQuals (quals) {} + std::vector vecQuals; + _QUALIFIER_SET (WORD index = 0, const std::vector &quals = {}): + wIndex (index), vecQuals (quals) {} } QUALIFIER_SET; typedef struct _DECISION { WORD wIndex = 0; std::vector verQualSets; - _DECISION (WORD index, std::vector &qualsets = {}): + _DECISION (WORD index, const std::vector &qualsets = {}): wIndex (index), verQualSets (qualsets) {} } DECISION; @@ -485,11 +992,18 @@ namespace pri 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 + struct + { + 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 + } part2; std::wstring swUniqueId = L""; // unique id + bool empty () + { + return swUniqueId.empty () && part2.wUnknown1 != 0; + } } HSCHEMA_REF_BLOCK; enum class RES_VALUE_TYPE: DWORD { @@ -513,8 +1027,9 @@ namespace pri } 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 + WORD wItemInfoCount; // number of iteminfos in this group + WORD wFirstItemIndex; // index of the first iteminfo in this group + _ITEMINFO_GROUP_TABLE_ENTRY (WORD count = 0, WORD firstIndex = 0): wItemInfoCount (count), wFirstItemIndex (firstIndex) {} } ITEMINFO_GROUP_TABLE_ENTRY; typedef struct _ITEM_ITEMINFO_TABLE_ENTRY { @@ -523,9 +1038,9 @@ namespace pri } 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 + DWORD dwItemAdditEntCount = 0; // number of additional entries of the item to iteminfo group table // ItemToItemInfoGroupCountLarge + DWORD dwItemGroupAdditEntCount = 0; // number of additional entries of the item info group table // itemInfoGroupCountLarge + DWORD dwItemTableAdditEntCount = 0; // number of additional entries of the iteminfo table // itemInfoCountLarge } TABLE_EXT_BLOCK; typedef BYTE CANDIDATE_TYPE; typedef struct _CANDIDATE0_DATA @@ -537,10 +1052,142 @@ namespace pri 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 + WORD wSrcFile = 0; // source file // sourceFileIndex + WORD wDataIndex = 0; // index of the data item storing the data // valueLocation + WORD wSectIndex = 0; // section index of the Data Item Section storing the data // dataItemSection } CANDIDATE1_DATA; + typedef struct _CANDIDATE_INFO + { + BYTE bCandidateType = 0; // 0 »ò 1 + union CANDIDATE + { + CANDIDATE0_DATA _0; + CANDIDATE1_DATA _1; + CANDIDATE (CANDIDATE0_DATA can0): _0 (can0) {} + CANDIDATE (CANDIDATE1_DATA can1): _1 (can1) {} + CANDIDATE () {} + } objCandidate; + _CANDIDATE_INFO (CANDIDATE0_DATA can0): bCandidateType (0), objCandidate (can0) {} + _CANDIDATE_INFO (CANDIDATE1_DATA can1): bCandidateType (1), objCandidate (can1) {} + _CANDIDATE_INFO (): bCandidateType (-1) {} + bool candidate_0 () const { return bCandidateType == 0; } + bool candidate_1 () const { return bCandidateType == 1; } + bool valid () const { return candidate_0 () ^ candidate_1 (); } + } CANDIDATE_INFO; + struct basic_sect; + template struct ref_sect + { + using classtype = 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; } + bool operator == (const classtype &another) const { return index == another.index; } + classtype &operator = (const classtype &another) { index = another.index; return *this; } + classtype &operator = (int newvalue) { index = newvalue; return *this; } + }; + typedef struct _RES_MAP_ITEM_REF + { + ref_sect wSchemaSect; + int iItemIndex; + _RES_MAP_ITEM_REF (const ref_sect &ssect, int itemindex): + wSchemaSect (ssect), iItemIndex (itemindex) {} + _RES_MAP_ITEM_REF () {} + } RES_MAP_ITEM_REF; + struct _CANDIDATE; + typedef struct _CANDIDATE_SET + { + RES_MAP_ITEM_REF refResMapItem; + WORD wDecisionIndex = 0; + std::vector <_CANDIDATE> vecCandidates; + } CANDIDATE_SET; + typedef struct _BASIC_REF + { + INT64 llIndex = -1; + bool valid () const { return llIndex >= 0; } + void reset () { llIndex = -1; } + void set (int index) { llIndex = index; } + void setnull () { llIndex = -1; } + int get () { return llIndex; } + bool isnull () { return !valid (); } + _BASIC_REF (int index = 0, bool isnull = false): + llIndex (isnull ? -1 : index) {} + operator int () { return get (); } + _BASIC_REF &operator = (int index) { set (index); return *this; } + _BASIC_REF &operator = (const _BASIC_REF &rfr) { this->llIndex = rfr.llIndex; return *this; } + bool operator == (const _BASIC_REF &another) const { return this->llIndex == another.llIndex; } + bool operator == (int index) const { return (int)this->llIndex == index; } + } BASIC_REF; + typedef struct _REF_FILE_REF: public BASIC_REF + { + using BASIC_REF::_BASIC_REF; + } REF_FILE_REF; + typedef struct _DATA_ITEM_REF: public BASIC_REF + { + ref_sect iDataSectIndex; + _DATA_ITEM_REF (int itemIndex = 0, int itemDataSectIndex = 0, bool isnull = false): + BASIC_REF (itemIndex, isnull), iDataSectIndex (itemDataSectIndex) {} + operator int () = delete; + _DATA_ITEM_REF &operator = (int) = delete; + _DATA_ITEM_REF &operator = (const _BASIC_REF &) = delete; + _DATA_ITEM_REF &operator = (const _DATA_ITEM_REF &another) + { + this->llIndex = another.llIndex; + this->iDataSectIndex = another.iDataSectIndex; + return *this; + } + bool operator == (int) = delete; + bool operator == (const _BASIC_REF &) = delete; + bool operator == (const _DATA_ITEM_REF &another) const + { return llIndex == another.llIndex && iDataSectIndex == another.iDataSectIndex; } + } DATA_ITEM_REF; + typedef struct _BYTE_SPAN + { + ulint offset = 0; + size_t length = 0; + bool isnull = false; + using classtype = _BYTE_SPAN; + _BYTE_SPAN (ulint p_of = 0, size_t len = 0, bool nullstatus = false): offset (p_of), length (len), isnull (nullstatus) {} + // ¶Áȡʱ»á¸ü¸ÄÎļþÖ¸ÕëλÖà + HRESULT get_bytes (istreamstream istream, std::vector &retbytes, size_t *retbyteslen = nullptr, bool cutbytesnoread = false) + { + retbytes.clear (); + retbytes.resize (length); + size_t bytesread = 0; + if (retbyteslen) *retbyteslen = 0; + HRESULT hr = istream.seek (offset, istreamstream::seekpos::start); + #ifdef _DEBUG + auto allsize = istream.size (); + #endif + if (FAILED (hr)) return hr; + hr = istream.read (retbytes.data (), length, &bytesread); + if (retbyteslen) *retbyteslen = bytesread; + if (cutbytesnoread) retbytes.resize (bytesread); + return hr; + } + } BYTE_SPAN; + typedef struct _CANDIDATE + { + WORD wQualifierSet = 0; + RES_VALUE_TYPE dwResType = RES_VALUE_TYPE::STRING; + REF_FILE_REF iSrcFileIndex = 0; + DATA_ITEM_REF iDataItem = 0; + BYTE_SPAN posData; + _CANDIDATE (WORD qualifierSet, RES_VALUE_TYPE resType, REF_FILE_REF srcFile, DATA_ITEM_REF dataItem): + wQualifierSet (qualifierSet), dwResType (resType), iSrcFileIndex (srcFile), iDataItem (dataItem), posData (0, 0, true) {} + _CANDIDATE (WORD qualifierSet, RES_VALUE_TYPE resType, BYTE_SPAN data): + wQualifierSet (qualifierSet), dwResType (resType), iSrcFileIndex (-1, true), iDataItem (-1, 0, true), posData (data) {} + _CANDIDATE (): iSrcFileIndex (-1, true), iDataItem (-1, 0, true), posData (0, 0, true) {} + // ÎÞЧ»á·µ»Ø nullptr + REF_FILE_REF *source_file_index () { return iSrcFileIndex.valid () ? &iSrcFileIndex : nullptr; } + // ÎÞЧ»á·µ»Ø nullptr + DATA_ITEM_REF *data_item_ref () { return iDataItem.valid () ? &iDataItem : nullptr; } + // ÎÞЧ»á·µ»Ø nullptr + BYTE_SPAN *data_position () { return posData.isnull ? nullptr : &posData; } + } CANDIDATE; // DataItem @@ -568,6 +1215,32 @@ namespace pri 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 + friend istreamstream &operator >> (istreamstream &i, _REF_FOLDER_INFO &reff) + { + return i >> + reff.wUnknown1 >> + reff.wParentIndex >> + reff.wFolderCount >> + reff.wFirstFolderIndex >> + reff.wFileCount >> + reff.wFirstFileIndex >> + reff.wFolderNameLength >> + reff.wFolderFullPathLength >> + reff.dwFolderNameOffset; + } + friend bytesstream &operator >> (bytesstream &i, _REF_FOLDER_INFO &reff) + { + return i >> + reff.wUnknown1 >> + reff.wParentIndex >> + reff.wFolderCount >> + reff.wFirstFolderIndex >> + reff.wFileCount >> + reff.wFirstFileIndex >> + reff.wFolderNameLength >> + reff.wFolderFullPathLength >> + reff.dwFolderNameOffset; + } } REF_FOLDER_INFO; typedef struct _REF_FILE_INFO { @@ -576,7 +1249,94 @@ namespace pri 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 + friend istreamstream &operator >> (istreamstream &i, _REF_FILE_INFO &r) + { + return i >> r.wUnknown1 >> + r.wParentIndex >> + r.wFileFullPathLength >> + r.wFileNameLength >> + r.dwFileNameOffset; + } + friend bytesstream &operator >> (bytesstream &i, _REF_FILE_INFO &r) + { + return i >> r.wUnknown1 >> + r.wParentIndex >> + r.wFileFullPathLength >> + r.wFileNameLength >> + r.dwFileNameOffset; + } } REF_FILE_INFO; + struct _REF_FOLDER; + typedef struct _REF_FILE_ENTRY + { + enum class ENTRYTYPE + { + UNKNOWN = 0, + FOLDER = 1, + FILE = 2 + }; + _REF_FOLDER *rfParent; + std::wstring swName = L""; + std::wstring fullname (); + std::wstring refresh_fullname () { swFullName.clear (); } + size_t path (std::vector &output); + ENTRYTYPE type () const { return eType; } + _REF_FILE_ENTRY (const std::wstring &name = L"", _REF_FOLDER *parent = nullptr, ENTRYTYPE type = ENTRYTYPE::UNKNOWN): + swName (name), eType (type), rfParent (parent) {} + protected: + std::wstring swFullName = L""; + ENTRYTYPE eType = ENTRYTYPE::UNKNOWN; + } REF_FILE_ENTRY; + typedef struct _REF_FOLDER: public _REF_FILE_ENTRY + { + std::vector vecChildrens; + _REF_FOLDER (const std::wstring &name = L"", _REF_FOLDER *parent = nullptr): + REF_FILE_ENTRY (name, parent, REF_FILE_ENTRY::ENTRYTYPE::FOLDER) {} + } REF_FOLDER; + std::wstring _REF_FILE_ENTRY::fullname () + { + if (std::wnstring::empty (swFullName)) + { + if (rfParent) swFullName = rfParent->fullname () + L"\\" + swName; + else swFullName = swName; + } + return swFullName; + } + size_t _REF_FILE_ENTRY::path (std::vector &output) + { + output.clear (); + if (rfParent) rfParent->path (output); + output.push_back (swName); + return output.size (); + } + typedef struct _REF_FILE: public REF_FILE_ENTRY + { + _REF_FILE (const std::wstring &name = L"", _REF_FOLDER *parent = nullptr): + REF_FILE_ENTRY (name, parent, REF_FILE_ENTRY::ENTRYTYPE::FILE) {} + } REF_FILE; + + // ReverseMap + + typedef struct _SCOPE_AND_ITEM_INFO + { + WORD wParent; + WORD wFullPathLength; + DWORD dwHashCode; + // ²»ÄÜÖ±½ÓʹÓ㬶øÊÇʹÓ÷½·¨ name_offset + WORD wNameOffset; + WORD wIndex; + DWORD name_offset () const + { + return (DWORD)wNameOffset | (((dwHashCode >> 24) & 0xF) << 16); + } + bool name_in_ascii () const { return dwHashCode & 0x20000000; } + bool is_scope () const { return dwHashCode & 0x10000000; } + auto Item1 () const { return wParent; } + auto Item2 () const { return wFullPathLength; } + auto Item3 () const { return dwHashCode; } + auto Item4 () const { return name_offset (); } + auto Item5 () const { return wIndex; } + } SCOPE_AND_ITEM_INFO; struct basic_sect { @@ -592,32 +1352,15 @@ namespace pri 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; } - }; +#define counter(_count_, _variable_) for (size_t _variable_ = 0, _counter_##_variable_##_total_ = _count_; _variable_ < _counter_##_variable_##_total_; _variable_ ++) 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."); + parse (); } - struct + struct ContentStruct { WORD wFlags = 0; // ±êÖ¾ / flags WORD wIncFileListIndex = -1; // °üº¬ÎļþÁбí½Ú£¨Included File List£©Ë÷Òý£¬Èô²»´æÔÚÔòΪ 0xFFFF @@ -629,6 +1372,11 @@ namespace pri WORD wRefFileCount = 0; // Referenced File ½ÚÊýÁ¿ WORD wDataItemCount = 0; // Data Item ½ÚÊýÁ¿ WORD wUnknown2 = -1; // δ֪£¬0 + ContentStruct () = default; + ContentStruct (WORD f, WORD inc, WORD unk1, WORD hiera, WORD dec, WORD res, WORD resBeg, WORD ref, WORD data, WORD unk2) + : wFlags (f), wIncFileListIndex (inc), wUnknown1 (unk1), wHieraScheCount (hiera), + wDecInfoCount (dec), wResMapCount (res), wResMapBegIndex (resBeg), wRefFileCount (ref), + wDataItemCount (data), wUnknown2 (unk2) {} } content; std::vector > vec_ref_hs; std::vector > vec_ref_deci; @@ -645,55 +1393,36 @@ namespace pri vec_ref_rf.clear (); vec_ref_dati.clear (); primary_resmap.reset (); - content = {0, -1, -1, 0, 0, 0, -1, 0, 0, -1}; + content = {0, (WORD)-1, (WORD)-1, 0, 0, 0, (WORD)-1, 0, 0, (WORD)-1}; } bool parse () { reset (); - sect.childst.seek (); + HRESULT hr = sect.childst.seek (); + istreamstream fp (sect.childst.ifile); DWORD dwContent = 0; - sect.childst.ifile->Read (&content, sizeof (content), &dwContent); + hr = 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 ++) + counter (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); + vec_ref_hs.push_back (fp.read_bytes ()); } - for (size_t i = 0; i < content.wDecInfoCount; i ++) + counter (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); + vec_ref_deci.push_back (fp.read_bytes ()); } - for (size_t i = 0; i < content.wResMapCount; i ++) + counter (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); + vec_ref_rm.push_back (fp.read_bytes ()); } - for (size_t i = 0; i < content.wRefFileCount; i ++) + counter (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); + vec_ref_rf.push_back (fp.read_bytes ()); } - for (size_t i = 0; i < content.wDataItemCount; i ++) + counter (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); + vec_ref_dati.push_back (fp.read_bytes ()); } return true; } @@ -750,13 +1479,17 @@ namespace pri std::vector vec_scope_and_items; std::vector vec_scope_ex; std::vector vec_item_index; - std::vector vec_scopes; - std::vector vec_items; + 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; } + void throwexpect (const std::string &reason = "Error: unexpected value.") + { + throw std::exception (reason.c_str ()); + } bool valid () { return content.part1.wUnknown1 == 1 && @@ -776,8 +1509,8 @@ namespace pri vec_scope_and_items.clear (); vec_scope_ex.clear (); vec_item_index.clear (); - vec_scopes.clear (); vec_items.clear (); + vec_scopes.clear (); ZeroMemory (&content.part1, sizeof (content.part1)); content.part1.wUnknown2 = -1; ZeroMemory (&content.part2, sizeof (content.part2)); @@ -793,117 +1526,110 @@ namespace pri { reset (); sect.childst.seek (); - sect.childst.ifile->Read (&content.part1, sizeof (content.part1), nullptr); + istreamstream fp (sect.childst.ifile); + if (sect.childst.size == 0) return true; + auto &uniqueNameLength = content.part1.wUniqRMNameLen; + auto &nameLength = content.part1.wResMapNameLen; + fp >> content.part1; + if (content.part1.wUnknown1 != 1 || content.part1.wUnknown2 != 0) throwexpect (); + auto &extendedVersion = ex; if (ex) { - sect.childst.ifile->Read (&content.part2, sizeof (content.part2), nullptr); + fp >> content.part2; 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 ++) + auto &extendedHNames = exHName; + auto &majorVersion = content.part3.verSchema.wMajor; + auto &minorVersion = content.part3.verSchema.wMinor; + auto &checksum = content.part3.verSchema.dwCheckSum; + auto &numScopes = content.part3.verSchema.dwScopeCount; + auto &numItems = content.part3.verSchema.dwItemCount; + fp >> content.part3; + if (content.part3.verSchema.dwUnknown1 != 0) throwexpect (); + auto &Version = content.part3.verSchema; + auto &UniqueName = content.part4.swUniqueRMName; + auto &Name = content.part4.swResMapName; + content.part4.swUniqueRMName = fp.read_string_endwith_null_w (); + content.part4.swResMapName = fp.read_string_endwith_null_w (); + fp.expect (0, true, &content.part4.wUnknown3); + auto &maxFullPathLength = content.part4.wMaxFullPathLength; + fp >> content.part4.wMaxFullPathLength; + fp.expect (0, true, &content.part4.wUnknown3_5); + fp.expect (numScopes + numItems, true, &content.part4.dwResNameCount); + fp.expect (numScopes, true, &content.part4.dwScopeCount); + fp.expect (numItems, true, &content.part4.dwItemsCount); + auto &unicodeDataLength = content.part4.dwUniNameLemgth; + fp >> unicodeDataLength; + fp >> content.part4.dwUnknown4; + if (extendedHNames) fp >> content.part4.dwUnknown5; + auto &scopeAndItemInfos = vec_scope_and_items; + scopeAndItemInfos.resize (content.part4.dwResNameCount); + fp.read (scopeAndItemInfos.data (), (content.part4.dwResNameCount) * sizeof (SCOPE_ITEM_INFO)); + auto &scopeExInfos = vec_scope_ex; + scopeExInfos.resize (numScopes); + fp.read (scopeExInfos.data (), numScopes * sizeof (SCOPE_EX_INFO)); + auto &itemIndexPropertyToIndex = vec_item_index; + itemIndexPropertyToIndex.resize (numItems); + fp.read (itemIndexPropertyToIndex.data (), sizeof (ITEM_INDEX) * numItems); + auto unicodeDataOffset = fp.position (); + auto asciiDataOffset = fp.position () + unicodeDataOffset * 2; + auto &scopes = vec_scopes; + auto &items = vec_items; + scopes.resize (numScopes); + items.resize (numItems); + counter (content.part4.dwResNameCount, i) { - 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) + istreamstream::fsize_t pos = 0; + if (scopeAndItemInfos [i].name_in_ascii ()) + pos = asciiDataOffset + scopeAndItemInfos [i].name_offset (); + else pos = unicodeDataOffset + scopeAndItemInfos [i].name_offset () * 2; + fp.seek (pos, istreamstream::seekpos::start); + std::wstring name; + if (scopeAndItemInfos [i].wFullPathLength != 0) { - if (sai.name_in_ascii ()) name = StringToWString (ReadStringEndwithNullA (sect.childst.ifile)); - else name = ReadStringEndwithNullW (sect.childst.ifile); + if (scopeAndItemInfos [i].name_in_ascii ()) + name = StringToWString (fp.read_string_endwith_null_a ()); + else name = fp.read_string_endwith_null_w (); } - else name = L""; - auto index = sai.index (); - if (sai.is_scope ()) + ITEM_INDEX index = scopeAndItemInfos [i].index (); + if (scopeAndItemInfos [i].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); + if (!scopes [index].bIsNull) throwexpect (); + else scopes.at (index) = RES_MAP_SCOPE (index, nullptr, name, false); } 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); + if (!items [index].bIsNull) throwexpect (); + else items.at (index) = RES_MAP_ITEM (index, nullptr, name, false); } } - for (size_t i = 0; i < silen; i ++) + counter (content.part4.dwResNameCount, 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; + ITEM_INDEX index = scopeAndItemInfos [i].index (); + WORD parent = scopeAndItemInfos [scopeAndItemInfos [i].wParentScopeIndex].index (); if (parent != 0xFFFF) { - if (sai.is_scope ()) + if (scopeAndItemInfos [i].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)); + if (parent != index) scopes.at (index).pParent = &scopes [parent]; } + else items.at (index).pParent = &scopes [parent]; } } - for (size_t i = 0; i < content.part3.verSchema.dwScopeCount; i ++) + counter (numScopes, i) { - auto &s = vec_scope_ex [i]; - auto &sp = vec_scopes [i]; - for (size_t j = 0; j < s.wChildCount; j ++) + auto &scope = scopes [i]; + auto &children = scope.vecChild; + counter (scopeExInfos [i].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)]); + auto &saiInfo = scopeAndItemInfos [scopeExInfos [i].wFirstChild + j]; + if (saiInfo.is_scope ()) children.push_back (&scopes.at (saiInfo.index ())); + else children.push_back (&items.at (saiInfo.index ())); } } - #ifdef readfromistream - #undef readfromistream - #endif return valid (); } }; @@ -948,55 +1674,41 @@ namespace pri bool parse () { reset (); - IStream *&fp = sect.childst.ifile; + istreamstream 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); - } + auto &numDistinctQualifiers = content.wDistQualiCount; + auto &numQualifiers = content.wQualifierCount; + auto &numQualifierSets = content.wQualSetsCount; + auto &numDecisions = content.wDecisionCount; + auto &numIndexTableEntries = content.wEntriesCount; + auto &totalDataLength = content.wQualiValueLength; + fp >> content; + std::vector decisionInfos (numDecisions); + std::vector qualifierSetInfos (numQualifierSets); + std::vector qualifierInfos (numQualifiers); + std::vector distinctQualifierInfos (numDistinctQualifiers); + std::vector indexTable (numIndexTableEntries); + auto &vec_dis_qua_info = distinctQualifierInfos; + auto &vec_qua_info = qualifierInfos; + auto &vec_qua_set_info = qualifierSetInfos; + auto &indexs = indexTable; + auto &vec_dec_info = decisionInfos; + fp.read (decisionInfos.data (), sizeof (DECISION_INFO) * numDecisions); + fp.read (qualifierSetInfos.data (), sizeof (DECISION_INFO) * numQualifierSets); + fp.read (qualifierInfos.data (), sizeof (QUALIFIER_INFO) * numQualifiers); + for (auto &it : qualifierInfos) { if (it.wUnknown1 != 0) throw std::exception ("Error: unexpective value."); } + fp.read (distinctQualifierInfos.data (), sizeof (DISTINCE_QUALIFIER_INFO) * numDistinctQualifiers); + fp.read (indexTable.data (), sizeof (ITEM_INDEX) * numIndexTableEntries); + auto currentpos = fp.position (); + std::vector buf (128); + fp.read (buf.data (), 128 * sizeof (WCHAR)); + fp.seek (currentpos, istreamstream::seekpos::start); 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); + auto &dinfo = vec_dis_qua_info [vec_qua_info [i].wDistQualiIndex]; + auto &qinfo = vec_qua_info [i]; + fp.seek (currentpos + dinfo.wQualiValueOffset * 2, istreamstream::seekpos::start); + std::wstring value = fp.read_string_endwith_null_w (); QUALIFIER qual (i, (QUALIFIER_TYPE)dinfo.wQualiType, qinfo.wPriority, (double)qinfo.wFallbackScore * 0.001, value); vec_qua.push_back (qual); } @@ -1019,18 +1731,15 @@ namespace pri counter (dec.wQualiSetsCount, j) { auto &ind = indexs [dec.wFirstQualiIndex + j]; - auto qset = qsets [ind]; + auto &qset = vec_qua_set.at (ind); qsets.emplace_back (qset); } - vec_dec.push_back (DECISION (i, qsets)); + vec_dec.emplace_back (DECISION (i, qsets)); } - #ifdef counter - #undef counter - #endif return valid (); } }; - struct sect_resmap: public basic_sect + struct sect_resmap: public basic_sect, public basic_sect_func { sect_resmap (section &s): basic_sect (s) { @@ -1040,44 +1749,64 @@ namespace pri } 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 + WORD wEnvRefLength = 0; // length of environment references block // environmentReferencesLength + WORD wRefCount = 0; // number of references in environment references block // numEnvironmentReferences + WORD wHSSectIndex = 0; // section index of Hierarchical Schema Section // SchemaSection + WORD wHSRefLength = 0; // length of hierarchical schema reference block // hierarchicalSchemaReferenceLength + WORD wDecInfSectIndex = 0; // section index of Decision Info Section // DecisionInfoSection + WORD wResTypeEntCount = 0; // number of entries in resource value type table // resourceValueTypeTableSize + WORD wItemEntCount = 0; // number of entries in item to iteminfo group table // ItemToItemInfoGroupCount + WORD wItemGroupEntCount = 0; // number of entries in iteminfo group table // itemInfoGroupCount + DWORD dwItemTableEntCount = 0; // number of entries in iteminfo table // itemInfoCount + DWORD dwCandidateCount = 0; // number of candidates // numCandidates + DWORD dwEmbededDataCount = 0; // length of embedded data bloc // dataLength + DWORD dwTableExtCount = 0; // length of table extension block // largeTableLength } content; BOOL ver2 = FALSE; + std::vector bvecEnvRefData; + std::vector bvecScheRefData; + HSCHEMA_REF_BLOCK hschema_ref; + std::vector vecResTypes; + std::vector vecItemToItemInfoGroup; + std::vector vecItemInfoGroups; + std::vector vecItemInfo; + std::vector vecCandidateInfo; + std::map mapCandidateSet; bool valid () { + if (parseError) return false; 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]; + res = (!ver2) + ? (content.wEnvRefLength != 0 && content.wRefCount != 0) + : (content.wEnvRefLength == 0 && content.wRefCount == 0); + if (!res) return false; + if (content.wHSRefLength != 0) + { + if (hschema_ref.verHschema.dwUnknown1 != 0) return false; + if (hschema_ref.part2.wUnknown1 != 0) return false; + } return res; } void reset () { + parseError = false; + bvecEnvRefData.clear (); + bvecScheRefData.clear (); + vecResTypes.clear (); + vecItemToItemInfoGroup.clear (); + vecItemInfoGroups.clear (); + vecItemInfo.clear (); + vecCandidateInfo.clear (); 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; + hschema_ref = HSCHEMA_REF_BLOCK (); } - bool parse () - { - reset (); - auto &fp = sect.childst.ifile; - sect.childst.seek (); - ulint sectpos = 0; - fp->Seek (lint (0), STREAM_SEEK_SET, sectpos.ptr_union ()); - - } + bool parse (); + private: + BOOL parseError = false; }; struct sect_dataitem: public basic_sect { @@ -1090,8 +1819,49 @@ namespace pri 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 + DWORD dwStoredLength = 0; // total length of stored data } content; + std::vector vecDataItems; + bool valid () + { + return content.dwUnknown1 == 0; + } + void reset () + { + vecDataItems.clear (); + ZeroMemory (&content, sizeof (content)); + content.dwUnknown1 = -1; + } + bool parse () + { + reset (); + sect.childst.seek (); + istreamstream fp (sect.childst.ifile); + auto sectionPosition = fp.position (); + fp >> content; + std::vector &dataItems = vecDataItems; + istreamstream::fsize_t dataStartOffset = + fp.position () + + content.wStrCount * 2 * sizeof (WORD) + + content.wBlobCount * 2 * sizeof (DWORD); + dataItems.reserve (content.wStrCount + content.wBlobCount); + std::vector storedStringInfos (content.wStrCount); + std::vector storedBlobInfo (content.wBlobCount); + fp.read (storedStringInfos.data (), sizeof (STORED_STRING_INFO) * content.wStrCount); + fp.read (storedBlobInfo.data (), sizeof (STORED_BLOB_INFO) * content.wBlobCount); + size_t cnt = 0; + counter (content.wStrCount, i) + { + auto &sstr = storedStringInfos.at (i); + dataItems.push_back (BYTE_SPAN (dataStartOffset + sstr.wStringOffset, sstr.wStringLength)); + } + counter (content.wBlobCount, i) + { + auto &sblo = storedBlobInfo.at (i); + dataItems.push_back (BYTE_SPAN (dataStartOffset + sblo.dwBlobOffset, sblo.dwBlobLength)); + } + return valid (); + } }; struct sect_reffile: public basic_sect { @@ -1107,8 +1877,89 @@ namespace pri WORD wUnknown1 = -1; // unknown, zero DWORD dwNameLength = 0; // length of Unicode name block in characters } content; + std::vector vecFolderInfo; + std::vector vecFileInfo; + std::vector vecRefFolders; + std::vector vecRefFiles; + bool valid () + { + return content.wUnknown1 == 0; + } + void reset () + { + vecFolderInfo.clear (); + vecFileInfo.clear (); + vecRefFiles.clear (); + vecRefFolders.clear (); + ZeroMemory (&content, sizeof (content)); + content.wUnknown1 = -1; + } + bool parse () + { + reset (); + sect.childst.seek (); + istreamstream fp (sect.childst.ifile); + fp >> content; + counter (content.wFolderCount, i) + { + REF_FOLDER_INFO folder; + fp >> folder; + if (folder.wUnknown1 != 0) throw std::exception ("Error: cannot get valid data in ReferencedFile Section."); + vecFolderInfo.push_back (folder); + } + counter (content.wFileCount, i) + { + REF_FILE_INFO file; + fp >> file; + vecFileInfo.push_back (file); + } + auto dataStartPosition = fp.position (); + auto &referencedFolders = vecRefFolders; + using seekpos = istreamstream::seekpos; + counter (content.wFolderCount, i) + { + fp.seek (dataStartPosition + vecFolderInfo [i].dwFolderNameOffset * 2, seekpos::start); + std::wstring name = fp.read_string_w (vecFolderInfo [i].wFolderNameLength); + referencedFolders.push_back (REF_FOLDER (name)); + } + counter (content.wFolderCount, i) + { + if (vecFolderInfo [i].wParentIndex != 0xFFFF) + { + referencedFolders [i].rfParent = &referencedFolders [vecFolderInfo [i].wParentIndex]; + } + } + counter (content.wFileCount, i) + { + REF_FILE file; + auto &fileInfo = vecFileInfo [i]; + fp.seek (dataStartPosition + fileInfo.dwFileNameOffset * 2, seekpos::start); + std::wstring name = fp.read_string_w (fileInfo.wFileNameLength); + file.swName = name; + REF_FOLDER *parent = nullptr; + if (vecFileInfo [i].wParentIndex != 0xFFFF) parent = &referencedFolders [fileInfo.wParentIndex]; + file.rfParent = parent; + vecRefFiles.push_back (file); + } + counter (content.wFolderCount, i) + { + auto &folderInfo = vecFolderInfo [i]; + auto &referencedFolder = referencedFolders [i]; + counter (folderInfo.wFolderCount, j) + { + auto &folder = referencedFolders [folderInfo.wFirstFolderIndex + j]; + referencedFolder.vecChildrens.push_back (&folder); + } + counter (folderInfo.wFileCount, j) + { + auto &file = vecRefFiles [folderInfo.wFirstFileIndex + j]; + referencedFolder.vecChildrens.push_back (&file); + } + } + return valid (); + } }; - struct sect_revmap: public basic_sect + struct sect_revmap: public basic_sect, public basic_sect_func { sect_revmap (section &s): basic_sect (s) { @@ -1116,30 +1967,176 @@ namespace pri } 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; + struct + { + DWORD dwItemsNumber = 0; + DWORD dwCheckCode = 0; + } part1; + struct + { + WORD wFullPathLength = 0; + WORD wUnknown1 = -1; // 0 + DWORD dwEntries = 0; + DWORD dwScopes = 0; + DWORD dwCheckItemsNumber = 0; + DWORD dwUnicodeDataLength = 0; + DWORD dwSkipPadding = 0; + } part2; } content; + std::vector adwMap; + std::vector aobjScopeAndItem; + std::vector aobjScopeExts; + std::vector awItemIndexs; + std::vector aobjScopes; + std::vector aobjItems; + bool valid () + { + bool res = content.part2.wUnknown1 == 0 && + content.part2.dwCheckItemsNumber == content.part1.dwItemsNumber || + 0; + return res; + } + void reset () + { + adwMap.clear (); + aobjScopeAndItem.clear (); + aobjScopeExts.clear (); + awItemIndexs.clear (); + aobjScopes.clear (); + aobjItems.clear (); + ZeroMemory (&content.part1, sizeof (content.part1)); + ZeroMemory (&content.part2, sizeof (content.part2)); + content.part2.wUnknown1 - 1; + } + bool parse () + { + reset (); + sect.childst.seek (); + istreamstream fp (sect.childst.ifile); + fp >> content.part1; + bool chk = content.part1.dwCheckCode == fp.size () - 8; + if (!chk) return false; + adwMap.resize (content.part1.dwItemsNumber); + fp.read (adwMap.data (), sizeof (DWORD) * content.part1.dwItemsNumber); + fp >> content.part2; + chk = content.part2.wUnknown1 == 0 && content.part2.dwCheckItemsNumber == content.part1.dwItemsNumber; + if (!chk) return false; + counter (content.part2.dwScopes + content.part1.dwItemsNumber, i) + { + SCOPE_AND_ITEM_INFO sii; + fp >> sii; + aobjScopeAndItem.push_back (sii); + } + counter (content.part2.dwScopes, i) + { + SCOPE_EX_INFO sei; + fp >> sei; + if (sei.wUnknown1 != 0) throw std::exception ("Error: read invalid data in ReverseMap Section."); + aobjScopeExts.push_back (sei); + } + awItemIndexs.resize (content.part1.dwItemsNumber); + fp.read (awItemIndexs.data (), content.part1.dwItemsNumber * sizeof (ITEM_INDEX)); + auto unicodeDataOffset = fp.position (), + asciiDataOffset = fp.position () + content.part2.dwUnicodeDataLength * 2; + aobjScopes.resize (content.part2.dwScopes); + aobjItems.resize (content.part1.dwItemsNumber); + counter (content.part1.dwItemsNumber + content.part2.dwScopes, i) + { + auto &sii = aobjScopeAndItem [i]; + bool nameInAscii = sii.name_in_ascii (); + UINT64 pos = (nameInAscii ? asciiDataOffset : unicodeDataOffset) + (sii.Item4 () * (nameInAscii ? 1 : 2)); + fp.seek (pos, istreamstream::seekpos::start); + std::wstring name; + if (sii.Item2 ()) + { + if (nameInAscii) name = StringToWString (fp.read_string_endwith_null_a ()); + else name = fp.read_string_endwith_null_w (); + } + auto index = sii.Item5 (); + bool isScope = sii.is_scope (); + if (isScope) + { + auto &it = aobjScopes.at (index); + if (!it.bIsNull) throw std::exception ("Error: invalid scope data in ReverseMap Section."); + else it = RES_MAP_SCOPE (index, nullptr, name); + } + else + { + auto &it = aobjItems.at (index); + if (!it.bIsNull) throw std::exception ("Error: invalid item data in ReverseMap Section."); + else it = RES_MAP_ITEM (index, nullptr, name); + } + } + counter (content.part1.dwItemsNumber + content.part2.dwScopes, i) + { + auto &sii = aobjScopeAndItem [i]; + auto index = sii.Item5 (); + bool isScope = sii.is_scope (); + auto parent = aobjScopeAndItem [sii.Item1 ()].Item5 (); + if (parent != 0xFFFF) + { + if (isScope && parent != index) + { + auto &it = aobjScopes.at (index); + it.pParent = &aobjScopes.at (parent); + } + else + { + auto &it = aobjItems.at (index); + it.pParent = &aobjScopes.at (parent); + } + } + + } + counter (content.part2.dwScopes, i) + { + auto &sei = aobjScopeExts [i]; + auto &scope = aobjScopes [i]; + counter (sei.wChildCount, j) + { + auto &saiInfo = aobjScopeAndItem [sei.wFirstChild + j]; + bool isScope = saiInfo.is_scope (); + if (isScope) + { + auto &prt = aobjScopes [saiInfo.Item5 ()]; + scope.vecChild.push_back (&prt); + } + else + { + auto &prt = aobjItems [saiInfo.Item5 ()]; + scope.vecChild.push_back (&prt); + } + } + } + return true; + } }; struct sect_unknown: public basic_sect { sect_unknown (section &s): basic_sect (s) {} - struct + UINT64 dwLength = 0; + void reset () { - DWORD dwLength = 0; - std::vector abContents; - } content; + dwLength = 0; + } + bool parse () + { + reset (); + sect.childst.seek (); + istreamstream fp (sect.childst.ifile); + dwLength = fp.size () - fp.position (); + return true; + } + size_t bytes (std::vector &bytes) + { + sect.childst.seek (); + istreamstream fp (sect.childst.ifile); + bytes.resize (dwLength); + size_t readlen = 0; + fp.read (bytes.data (), dwLength, &readlen); + bytes.resize (readlen > dwLength ? dwLength : readlen); + return readlen; + } }; } class prifile @@ -1149,15 +2146,41 @@ class prifile head header; foot footer; std::vector toclist; std::vector
sectlist; + enum class searchtype + { + unknown, + string, + file + }; + struct search_key + { + std::wnstring key = L""; + searchtype type = searchtype::unknown; + search_key (const std::wstring &k = L"", searchtype t = searchtype::unknown): + key (k), type (t) {} + bool operator == (const search_key &another) const { return key == another.key && type == another.type; } + bool operator == (const std::wstring &an_key) const { return key.equals (an_key); } + operator searchtype () const { return type; } + operator LPCWSTR () const { return key.c_str (); } + }; + struct search_value + { + std::wstring value = L""; + bool isfind = false; + int begindex = -1; + bool finishsearch = false; + operator LPCWSTR () const { return value.c_str (); } + operator bool () const { return isfind; } + }; + std::map vecTaskSearch; + bool isrunningtask = false; public: - bool close () + void close () { header = head (); footer = foot (); toclist.clear (); sectlist.clear (); - if (pfile) pfile->Release (); - pfile = nullptr; } bool load (IStream *ifile) { @@ -1177,6 +2200,32 @@ class prifile initsect (); return true; } + operator istreamstream () { return istreamstream (pfile); } + pri::sect_pridesp section_pri_descriptor () + { + for (auto &it : sectlist) + { + if (it.type () == SectionType::PriDescriptor) + { + try + { + auto sect = pri::sect_pridesp (it); + sect.parse (); + return sect; + } + catch (const std::exception &e) { continue; } + } + } + throw std::exception ("Error: cannot get the pri descriptor section."); + } + section &get_section_by_ref (int index) + { + return sectlist.at (index); + } + template SectionT get_section_by_ref (pri::ref_sect ref) + { + return SectionT (sectlist.at (ref.index)); + } void inittoc () { toclist.clear (); @@ -1192,22 +2241,431 @@ class prifile void initsect () { sectlist.clear (); + istreamstream iss (pfile); 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 - ); + iss.seek (header.dwSectStartOffset + toclist [i].dwSectOffset, istreamstream::seekpos::start); + section sect (this->pfile, *this); + iss.read (sect.head); + iss.seek (sect.head.dwLength - 16 - 24); + iss.read (sect.foot); + iss.seek (header.dwSectStartOffset + toclist [i].dwSectOffset, istreamstream::seekpos::start); + iss.seek (32); + sect.childst.set (iss.position (), sect.head.dwLength - 16 - 24); sectlist.push_back (sect); } } -}; \ No newline at end of file + // Ó÷¨£º + // auto rmsect = this->get_resmap_sect_by_ref (candidateSet.refResMapItem); + // rmsect.parse (); + // auto item = rmsect.vec_items [candidateSet.refResMapItem.iItemIndex]; + auto get_resmap_sect_by_ref (pri::RES_MAP_ITEM_REF resourceMapItemRef) + { + return get_section_by_ref (resourceMapItemRef.wSchemaSect); + } + // Ó÷¨£º + // auto ds = get_dataitem_sect_by_ref (dataItemRef); + // ds.parse (); + // ds.vecDataItems.at (dataItemRef.get ()); + auto get_dataitem_sect_by_ref (pri::DATA_ITEM_REF dataItemRef) + { + return get_section_by_ref (dataItemRef.iDataSectIndex); + } + bool get_reffile_by_ref (pri::REF_FILE_REF referencedFileRef, std::function callback) + { + try + { + auto sect = get_section_by_ref (section_pri_descriptor ().vec_ref_rf.front ()); + auto &rf = sect.vecRefFiles.at (referencedFileRef); + if (callback) callback (rf); + return true; + } + catch (const std::exception &e) + { + return false; + } + } + void end_taskrunning () { isrunningtask = false; } + static void search_task (prifile &priinst) + { + destruct ([&priinst] () { + priinst.end_taskrunning (); + }); + if (priinst.isrunningtask) return; + else priinst.isrunningtask = true; + auto &tasklist = priinst.vecTaskSearch; + + } + void across_all (std::wostream &out) + { + #ifdef _CONSOLE + struct loadingamine + { + const WCHAR *charcollect = L"-\\|/-\\|/"; + WCHAR nowchar = L' '; + bool isend = false; + bool enablecallback = true; + std::function callback = nullptr; + void exectask () + { + size_t cnt = 0; + size_t charlen = lstrlenW (charcollect); + std::function cb = callback; + while (!isend) + { + nowchar = charcollect [(cnt ++) % charlen]; + if (cb && enablecallback) cb (nowchar); + std::this_thread::sleep_for (std::chrono::milliseconds (300)); + } + } + void run () + { + std::thread th (&loadingamine::exectask, this); + th.detach (); + } + void jump () { isend = true; } + } loadchar; + destruct endt ([&loadchar] () { + loadchar.isend = true; + }); + std::wcout << L" 0 %"; + loadchar.callback = [] (const WCHAR &wch) { + wprintf (L"\r %c 0 %%", wch); + }; + loadchar.run (); + auto DiffSystemTimeMs = [] (const SYSTEMTIME &st1, const SYSTEMTIME &st2) -> LONGLONG + { + FILETIME ft1, ft2; + ULARGE_INTEGER t1, t2; + SystemTimeToFileTime (&st1, &ft1); + SystemTimeToFileTime (&st2, &ft2); + + t1.LowPart = ft1.dwLowDateTime; + t1.HighPart = ft1.dwHighDateTime; + t2.LowPart = ft2.dwLowDateTime; + t2.HighPart = ft2.dwHighDateTime; + + // FILETIME µ¥Î»ÊÇ 100 ÄÉÃ루1Ãë = 10,000,000£© + LONGLONG diff100ns = t2.QuadPart - t1.QuadPart; + + // ת»»ÎªºÁÃë + return diff100ns / 10000; // 1 ºÁÃë = 10,000 * 100ns + }; + out << L"Read Start: "; + WCHAR buf [64]; + SYSTEMTIME st_start; + GetLocalTime (&st_start); + swprintf (buf, 64, L"%4d.%02d.%02d %02d:%02d:%02d", + st_start.wYear, st_start.wMonth, st_start.wDay, + st_start.wHour, st_start.wMinute, st_start.wSecond); + out << buf << std::endl; + out << L"Sections: " << sectlist.size () << std::endl; + for (auto &it : sectlist) + { + out << L" " << it << std::endl; + } + out << std::endl; + auto pri_desp = this->section_pri_descriptor (); + loadchar.callback = nullptr; + loadchar.enablecallback = false; + out << L"Candidates: " << pri_desp.vec_ref_rm.size () << std::endl; + size_t cnt_i = 0; + for (auto &it : pri_desp.vec_ref_rm) + { + auto resmap_sect = this->get_section_by_ref (it); + resmap_sect.parse (); + if (!resmap_sect.hschema_ref.empty ()) continue; + auto decisionInfoSection = get_section_by_ref (resmap_sect.content.wDecInfSectIndex); + decisionInfoSection.parse (); + size_t cnt_j = 0; + for (auto &it_cs : resmap_sect.mapCandidateSet) + { + auto &candidateSet = it_cs.second; + auto rmsect = this->get_resmap_sect_by_ref (candidateSet.refResMapItem); + rmsect.parse (); + auto item = rmsect.vec_items [candidateSet.refResMapItem.iItemIndex]; + out << L" " << item.full_name () << std::endl; + size_t cnt_k = 0; + for (auto &candidate : candidateSet.vecCandidates) + { + std::wstring value; + if (candidate.source_file_index ()) + { + auto temp = get_reffile_by_ref (*candidate.source_file_index (), [&value] (pri::REF_FILE &rf) { + value += L""; + }); + } + else + { + pri::BYTE_SPAN byteSpan; + if (candidate.data_item_ref ()) + { + auto dis = this->get_dataitem_sect_by_ref (*candidate.data_item_ref ()); + dis.parse (); + byteSpan = dis.vecDataItems.at (candidate.data_item_ref ()->get ()); + } + else + { + if (candidate.data_position ()) byteSpan = *candidate.data_position (); + else byteSpan.isnull = true; + } + std::vector bytes (byteSpan.length + 2); + size_t ret; + HRESULT hr = byteSpan.get_bytes (pfile, bytes, &ret); + bytes.resize (bytes.size () + 2); + using restype = pri::RES_VALUE_TYPE; + switch (candidate.dwResType) + { + case restype::ASCIIPATH: + case restype::ASCIISTRING: + value += StringToWString ((CHAR *)bytes.data ()); break; + case restype::UTF8PATH: + case restype::UTF8STRING: + value += StringToWString ((CHAR *)bytes.data (), CP_UTF8); break; + case restype::STRING: + case restype::PATH: + value += (WCHAR *)bytes.data (); break; + case restype::EMBEDDEDDATA: + value += L"<" + std::to_wstring (ret) + L" bytes>"; break; + } + } + auto qualifierSet = decisionInfoSection.vec_qua_set [candidate.wQualifierSet]; + std::wstring qualifiers; + for (auto qual : qualifierSet.vecQuals) + { + std::wstring str = L" "; + str += EnumToStringW (qual.eType) + L" = " + qual.swValue + L"\n"; + qualifiers += str; + } + out << L" Value {" << value << L"}" << std::endl; + out << qualifiers; + double progress = (double)((cnt_i + (cnt_j + (double)cnt_k / candidateSet.vecCandidates.size ()) / resmap_sect.mapCandidateSet.size ()) / pri_desp.vec_ref_rm.size () * 100.0); + std::wcout << L"\r " + << loadchar.nowchar + << L" " + << std::fixed << std::setprecision (2) + << progress + << L" % [(" + << cnt_k + << L" / " + << candidateSet.vecCandidates.size () + << L") of (" + << cnt_j + << L" / " + << resmap_sect.mapCandidateSet.size () + << L") of (" + << cnt_i + << L" / " + << pri_desp.vec_ref_rm.size () + << L")]" + << L" " + ; + cnt_k ++; + } + cnt_j ++; + } + int i = 0; + cnt_i ++; + } + int j = 0; + std::wcout << L"\r 100 % " << std::endl; + out << L"Read Completed: "; + SYSTEMTIME st_end; + GetLocalTime (&st_end); + ZeroMemory (buf, 60 * sizeof (WCHAR)); + swprintf (buf, 64, L"%4d.%02d.%02d %02d:%02d:%02d", + st_end.wYear, st_end.wMonth, st_end.wDay, + st_end.wHour, st_end.wMinute, st_end.wSecond); + out << buf << std::endl; + out << L"Time Spend: " << DiffSystemTimeMs (st_start, st_end) * 0.001 << L"s" << std::endl; + #endif + } +}; +bool pri::sect_resmap::parse () + +{ + reset (); + istreamstream fp (sect.childst.ifile); + sect.childst.seek (); + ulint sectpos = 0; + fp->Seek (lint (0), STREAM_SEEK_CUR, sectpos.ptr_union ()); + fp->Read (&content, sizeof (content), nullptr); + bool res = (!ver2) ? (content.wEnvRefLength != 0 && content.wRefCount != 0) : (content.wEnvRefLength == 0 && content.wRefCount == 0); + if (!res) return false; + { + auto currpos = fp.position (); + try + { + auto dest = sect.pri_file.get_section_by_ref (ref_sect (content.wDecInfSectIndex)); + dest.parse (); + } + catch (const std::exception &e) + { + parseError = true; + return false; + } + fp.seek (currpos, istreamstream::seekpos::start); + } + bvecEnvRefData.resize (content.wEnvRefLength); + bvecScheRefData.resize (content.wHSRefLength); + ZeroMemory (bvecEnvRefData.data (), sizeof (BYTE) * content.wEnvRefLength); + ZeroMemory (bvecScheRefData.data (), sizeof (BYTE) * content.wHSRefLength); + fp->Read (bvecEnvRefData.data (), sizeof (BYTE) * content.wEnvRefLength, nullptr); + fp->Read (bvecScheRefData.data (), sizeof (BYTE) * content.wHSRefLength, nullptr); + if (content.wHSRefLength != 0) + { + bytesstream srdata (bvecScheRefData); + srdata.read (&hschema_ref.verHschema, sizeof (hschema_ref.verHschema)); + if (hschema_ref.verHschema.dwUnknown1 != 0) return false; + srdata.read (&hschema_ref.part2, sizeof (hschema_ref.part2)); + if (hschema_ref.part2.wUnknown1 != 0) return false; + hschema_ref.swUniqueId = ReadStringEndwithNullW (fp); + } + for (size_t i = 0; i < content.wResTypeEntCount; i ++) + { + RES_VALUE_TYPE_TABLE rvtt; + fp->Read (&rvtt, sizeof (rvtt), nullptr); + if (rvtt.dwUnknown1 != 4) return false; + vecResTypes.push_back ((RES_VALUE_TYPE)rvtt.dwResType); + } + for (size_t i = 0; i < content.wItemEntCount; i ++) + { + ITEM_ITEMINFO_GROUP_TABLE_ENTRY iigte; + fp->Read (&iigte, sizeof (iigte), nullptr); + vecItemToItemInfoGroup.push_back (iigte); + } + for (size_t i = 0; i < content.wItemGroupEntCount; i ++) + { + ITEMINFO_GROUP_TABLE_ENTRY iigte; + fp->Read (&iigte, sizeof (iigte), nullptr); + vecItemInfoGroups.push_back (iigte); + } + for (size_t i = 0; i < content.dwItemTableEntCount; i ++) + { + ITEM_ITEMINFO_TABLE_ENTRY iite; + fp->Read (&iite, sizeof (iite), nullptr); + vecItemInfo.push_back (iite); + } + std::vector largeTable (content.dwTableExtCount); + fp->Read (largeTable.data (), sizeof (BYTE) * content.dwTableExtCount, nullptr); + if (largeTable.size () != 0) + { + bytesstream bytes (largeTable); + TABLE_EXT_BLOCK teb; + bytes.read (&teb, sizeof (teb)); + for (size_t i = 0; i < teb.dwItemAdditEntCount; i ++) + { + ITEM_ITEMINFO_GROUP_TABLE_ENTRY iiigte; + bytes.read (&iiigte, sizeof (iiigte)); + vecItemToItemInfoGroup.push_back (iiigte); + } + for (size_t i = 0; i < teb.dwItemGroupAdditEntCount; i ++) + { + ITEMINFO_GROUP_TABLE_ENTRY iigte; + bytes.read (&iigte, sizeof (iigte)); + vecItemInfoGroups.push_back (iigte); + } + for (size_t i = 0; i < teb.dwItemTableAdditEntCount; i ++) + { + ITEM_ITEMINFO_TABLE_ENTRY iiite; + bytes.read (&iiite, sizeof (iiite)); + vecItemInfo.push_back (iiite); + } + if (bytes.position () > bytes.length ()) throw std::exception ("Error: invalid data in ResourceMap or ResourceMap2 Section."); + } + for (size_t i = 0; i < content.dwCandidateCount; i ++) + { + BYTE bType = -1; + fp->Read (&bType, sizeof (bType), nullptr); + switch (bType) + { + case 0x00: { + CANDIDATE_TYPE rvtype = 0; + fp->Read (&rvtype, sizeof (rvtype), nullptr); + CANDIDATE0_DATA cdata; + cdata.bResValueType = (BYTE)vecResTypes.at (rvtype); + auto &length = cdata.wEmbeddedLength; + auto &stringOffset = cdata.dwEmbeddedOffset; + fp >> length >> stringOffset; + vecCandidateInfo.emplace_back (CANDIDATE_INFO (cdata)); + } break; + case 0x01: { + CANDIDATE_TYPE rvtype = 0; + fp->Read (&rvtype, sizeof (rvtype), nullptr); + CANDIDATE1_DATA cdata; + auto &resourceValueType = cdata.bResValueType; + auto &sourceFileIndex = cdata.wSrcFile; + auto &valueLocation = cdata.wDataIndex; + auto &dataItemSection = cdata.wSectIndex; + resourceValueType = (BYTE)vecResTypes.at (rvtype); + fp >> sourceFileIndex >> valueLocation >> dataItemSection; + vecCandidateInfo.emplace_back (CANDIDATE_INFO (cdata)); + } break; + default: { + throw std::domain_error ("Error: invalid data read in ResourceMap or ResourceMap2 section."); + } break; + } + } + ulint strbegpos = 0; + fp->Seek (lint (0), STREAM_SEEK_CUR, strbegpos.ptr_union ()); + for (size_t i = 0; i < vecItemToItemInfoGroup.size (); i ++) + { + auto &itemToItemGroup = vecItemToItemInfoGroup [i]; + ITEMINFO_GROUP_TABLE_ENTRY itemInfoGroup; + if (itemToItemGroup.wItemInfoGroupIndex < vecItemInfoGroups.size ()) + itemInfoGroup = (vecItemInfoGroups [itemToItemGroup.wItemInfoGroupIndex]); + else itemInfoGroup = {1, (WORD)(itemToItemGroup.wItemInfoGroupIndex - vecItemInfoGroups.size ())}; + for (size_t j = itemInfoGroup.wFirstItemIndex; j < itemInfoGroup.wFirstItemIndex + itemInfoGroup.wItemInfoCount; j ++) + { + auto &itemInfo = vecItemInfo [j]; + auto decIndex = itemInfo.wDecisionIndex; + auto &decSect = sect.pri_file.get_section_by_ref (ref_sect (content.wDecInfSectIndex)); + decSect.parse (); + auto dec = decSect.vec_dec [decIndex]; + CANDIDATE_SET candidateSet; + std::vector &candidates = candidateSet.vecCandidates; + for (size_t k = 0; k < dec.verQualSets.size (); k ++) + { + auto can_info = vecCandidateInfo [itemInfo.wFirstCandiIndex + k]; + switch (can_info.bCandidateType) + { + case 0x01: { + REF_FILE_REF sourceFile; + if (!can_info.objCandidate._1.wSrcFile) sourceFile.setnull (); + else sourceFile.set (can_info.objCandidate._1.wSrcFile - 1); + candidates.push_back ( + CANDIDATE ( + dec.verQualSets [k].wIndex, + (RES_VALUE_TYPE)can_info.objCandidate._1.bResValueType, + sourceFile, + DATA_ITEM_REF (can_info.objCandidate._1.wDataIndex, can_info.objCandidate._1.wSectIndex + ) + ) + ); + } break; + case 0x00: { + BYTE_SPAN bspan ( + sectpos + strbegpos + ulint (can_info.objCandidate._0.dwEmbeddedOffset), + can_info.objCandidate._0.wEmbeddedLength + ); + candidates.push_back ( + CANDIDATE ( + dec.verQualSets [k].wIndex, + (RES_VALUE_TYPE)can_info.objCandidate._1.bResValueType, + bspan + ) + ); + } break; + } + } + WORD resourceMapItemIndex = itemToItemGroup.wFirstIndexProperty + (j - itemInfoGroup.wFirstItemIndex); + candidateSet.refResMapItem = RES_MAP_ITEM_REF (content.wHSSectIndex, resourceMapItemIndex); + candidateSet.wDecisionIndex = decIndex; + mapCandidateSet [resourceMapItemIndex] = candidateSet; + } + } + return valid (); +} +#ifdef UNALIGN_MEMORY +#pragma pack(pop) +#endif \ No newline at end of file diff --git a/priread/priread.vcxproj b/priread/priread.vcxproj index dad6f30..268ba63 100644 --- a/priread/priread.vcxproj +++ b/priread/priread.vcxproj @@ -151,6 +151,7 @@ + diff --git a/priread/priread.vcxproj.filters b/priread/priread.vcxproj.filters index e6067f0..7efecd9 100644 --- a/priread/priread.vcxproj.filters +++ b/priread/priread.vcxproj.filters @@ -36,6 +36,9 @@ 头文件 + + 头文件 + diff --git a/priread/themeinfo.h b/priread/themeinfo.h new file mode 100644 index 0000000..8d3c712 --- /dev/null +++ b/priread/themeinfo.h @@ -0,0 +1,40 @@ +#pragma once +#include + +bool IsHighContrastEnabled () +{ + HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)}; + if (SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return (hc.dwFlags & HCF_HIGHCONTRASTON) != 0; + return false; +} +enum class HighContrastTheme +{ + None, + Black, + White, + Other +}; +HighContrastTheme GetHighContrastTheme () +{ + HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)}; + if (!SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return HighContrastTheme::None; + if (!(hc.dwFlags & HCF_HIGHCONTRASTON)) return HighContrastTheme::None; + COLORREF bgColor = GetSysColor (COLOR_WINDOW); + COLORREF textColor = GetSysColor (COLOR_WINDOWTEXT); + int brightnessBg = (GetRValue (bgColor) + GetGValue (bgColor) + GetBValue (bgColor)) / 3; + int brightnessText = (GetRValue (textColor) + GetGValue (textColor) + GetBValue (textColor)) / 3; + if (brightnessBg < brightnessText) return HighContrastTheme::Black; + else if (brightnessBg > brightnessText) return HighContrastTheme::White; + else return HighContrastTheme::Other; +} +int GetDPI () +{ + HDC hDC = GetDC (NULL); + int DPI_A = (int)(((double)GetDeviceCaps (hDC, 118) / (double)GetDeviceCaps (hDC, 8)) * 100); + int DPI_B = (int)(((double)GetDeviceCaps (hDC, 88) / 96) * 100); + ReleaseDC (NULL, hDC); + if (DPI_A == 100) return DPI_B; + else if (DPI_B == 100) return DPI_A; + else if (DPI_A == DPI_B) return DPI_A; + else return 0; +}