mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
1467 lines
45 KiB
C++
1467 lines
45 KiB
C++
// priformatcli.cpp : 定义 DLL 应用程序的导出函数。
|
||
//
|
||
|
||
#include "stdafx.h"
|
||
#include "priformatcli.h"
|
||
#include "prifile.h"
|
||
#include "typestrans.h"
|
||
#include "mpstr.h"
|
||
#include "nstring.h"
|
||
#include "themeinfo.h"
|
||
#include "localeex.h"
|
||
#include "syncutil.h"
|
||
#include "strcmp.h"
|
||
|
||
#include <string>
|
||
#include <vector>
|
||
#include <map>
|
||
#include <cwchar>
|
||
#include <functional>
|
||
#include <algorithm>
|
||
#include <set>
|
||
|
||
const std::wstring g_swMsResUriProtocolName = L"ms-resource:";
|
||
const size_t g_cbMsResPNameLength = lstrlenW (g_swMsResUriProtocolName.c_str ());
|
||
std::wstring g_swExcept = L"";
|
||
CriticalSection g_csLastErr;
|
||
CriticalSection g_threadlock;
|
||
CriticalSection g_iterlock;
|
||
struct destruct
|
||
{
|
||
std::function <void ()> endtask = nullptr;
|
||
destruct (std::function <void ()> init): endtask (init) {}
|
||
~destruct () { if (endtask) endtask (); }
|
||
};
|
||
void SetPriLastError (const std::wstring &lpMsg)
|
||
{
|
||
CreateScopedLock (g_csLastErr);
|
||
g_swExcept = lpMsg;
|
||
}
|
||
enum class OpenType
|
||
{
|
||
Unknown,
|
||
IStream,
|
||
Stream
|
||
};
|
||
ref class PriFileInst
|
||
{
|
||
public:
|
||
PriFile ^inst = nullptr;
|
||
OpenType opentype = OpenType::Unknown;
|
||
IStream *isptr = nullptr;
|
||
System::IO::Stream ^fsptr = nullptr;
|
||
operator PriFile ^ () { return inst; }
|
||
operator IStream * () { return isptr; }
|
||
operator System::IO::Stream ^ () { return fsptr; }
|
||
explicit operator bool () { return inst && (int)opentype && ((bool)isptr ^ (fsptr != nullptr)); }
|
||
size_t Seek (int64_t offset, System::IO::SeekOrigin origin)
|
||
{
|
||
if (isptr)
|
||
{
|
||
ULARGE_INTEGER ul;
|
||
ul.QuadPart = 0;
|
||
LARGE_INTEGER lo;
|
||
lo.QuadPart = offset;
|
||
DWORD dwOrigin = 0;
|
||
switch (origin)
|
||
{
|
||
case System::IO::SeekOrigin::Begin: dwOrigin = STREAM_SEEK_SET;
|
||
break;
|
||
case System::IO::SeekOrigin::Current: dwOrigin = STREAM_SEEK_CUR;
|
||
break;
|
||
case System::IO::SeekOrigin::End: dwOrigin = STREAM_SEEK_END;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
HRESULT hr = isptr->Seek (lo, dwOrigin, &ul);
|
||
return ul.QuadPart;
|
||
}
|
||
else if (fsptr)
|
||
{
|
||
return fsptr->Seek (offset, origin);
|
||
}
|
||
throw gcnew NullReferenceException ("Error: cannot get the stream.");
|
||
return 0;
|
||
}
|
||
!PriFileInst ()
|
||
{
|
||
if (fsptr)
|
||
{
|
||
fsptr->Close ();
|
||
delete fsptr;
|
||
fsptr = nullptr;
|
||
}
|
||
if (inst)
|
||
{
|
||
delete inst;
|
||
inst = nullptr;
|
||
}
|
||
}
|
||
~PriFileInst ()
|
||
{
|
||
if (fsptr)
|
||
{
|
||
fsptr->Close ();
|
||
delete fsptr;
|
||
fsptr = nullptr;
|
||
}
|
||
if (inst)
|
||
{
|
||
delete inst;
|
||
inst = nullptr;
|
||
}
|
||
}
|
||
};
|
||
size_t KeyToPath (const std::wstring &key, std::vector <std::wnstring> &output);
|
||
typedef struct _TASKITEM_SEARCH
|
||
{
|
||
std::wstring swKey;
|
||
int iTaskType; // 0: 字符串,1: 文件路径
|
||
operator std::wstring () { return swKey; }
|
||
operator LPCWSTR () { return swKey.c_str (); }
|
||
operator std::wnstring () { return swKey; }
|
||
void set_key (const std::wstring &value)
|
||
{
|
||
iTaskType = std::wnstring (GetStringLeft (std::wnstring::trim (value), g_cbMsResPNameLength)) != g_swMsResUriProtocolName;
|
||
swKey = value;
|
||
}
|
||
bool isuri () const
|
||
{
|
||
return std::wnstring (GetStringLeft (std::wnstring::trim (swKey), g_cbMsResPNameLength)) == g_swMsResUriProtocolName;
|
||
}
|
||
bool isfulluri () const
|
||
{
|
||
const std::wstring root = L"//";
|
||
return std::wnstring (GetStringLeft (std::wnstring::trim (swKey), g_cbMsResPNameLength + root.length ())) == g_swMsResUriProtocolName + root;
|
||
}
|
||
bool isfilepath () const { return !isuri (); }
|
||
bool isrelativeuri () const { return !isfulluri () && isuri (); }
|
||
size_t get_path (std::vector <std::wnstring> &output) const
|
||
{
|
||
output.clear ();
|
||
auto &path = output;
|
||
KeyToPath (swKey, path);
|
||
if (isrelativeuri ())
|
||
{
|
||
std::wstring nopre = GetStringRight (swKey, swKey.length () - g_cbMsResPNameLength);
|
||
std::wstring firstch = GetStringLeft (nopre, 1);
|
||
if (firstch [0] != L'/') path.insert (path.begin (), L"resources");
|
||
}
|
||
else if (isfilepath ()) path.insert (path.begin (), L"Files");
|
||
return output.size ();
|
||
}
|
||
_TASKITEM_SEARCH &operator = (const std::wstring &v)
|
||
{
|
||
set_key (v);
|
||
return *this;
|
||
}
|
||
explicit _TASKITEM_SEARCH (const std::wstring &v, int type = -1)
|
||
{
|
||
if (type < 0 || type > 1) set_key (v);
|
||
else
|
||
{
|
||
swKey = v;
|
||
iTaskType = type;
|
||
}
|
||
}
|
||
_TASKITEM_SEARCH (int type, const std::wstring &v = L"")
|
||
{
|
||
if (type < 0 || type > 1) set_key (v);
|
||
else
|
||
{
|
||
swKey = v;
|
||
iTaskType = type;
|
||
}
|
||
}
|
||
_TASKITEM_SEARCH () = default;
|
||
bool operator == (const _TASKITEM_SEARCH &another) const
|
||
{
|
||
return std::wnstring (swKey).equals (another.swKey);
|
||
}
|
||
bool operator < (const _TASKITEM_SEARCH &another) const
|
||
{
|
||
return std::wnstring (swKey).compare (another.swKey) < 0;
|
||
}
|
||
} TASKITEM_SEARCH;
|
||
typedef struct _TASKRESULT_FIND
|
||
{
|
||
std::wstring swValue = L"";
|
||
int iFindResult = -1; // -1 未进行查找,0:查找但未找到,1:查找且已找到
|
||
operator std::wstring () { return swValue; }
|
||
operator LPCWSTR () { return swValue.c_str (); }
|
||
operator std::wnstring () { return swValue; }
|
||
_TASKRESULT_FIND (const std::wstring &v, int findres = -1):
|
||
swValue (v), iFindResult (findres) {}
|
||
_TASKRESULT_FIND (int findres, const std::wstring &v = L""):
|
||
swValue (v), iFindResult (findres) {}
|
||
_TASKRESULT_FIND () = default;
|
||
// 是否查找到
|
||
bool is_find () const { return iFindResult > 0; }
|
||
// 是否进行过查找
|
||
bool has_search () const { return iFindResult >= 0; }
|
||
} TASKRESULT_FIND;
|
||
typedef struct _TASKINFO_SEARCH
|
||
{
|
||
bool bIsRunning = false;
|
||
std::map <TASKITEM_SEARCH, TASKRESULT_FIND> mapTasks;
|
||
operator std::map <TASKITEM_SEARCH, TASKRESULT_FIND> () { return mapTasks; }
|
||
} TASKINFO_SEARCH;
|
||
|
||
size_t UriToPath (System::Uri ^uri, std::vector <std::wnstring> &output)
|
||
{
|
||
output.clear ();
|
||
try
|
||
{
|
||
auto path = uri->AbsolutePath;
|
||
auto arr = path->Split ('/');
|
||
for (size_t i = 0; i < arr->Length; i ++)
|
||
{
|
||
auto str = arr [i];
|
||
std::wnstring cppstr = MPStringToStdW (str);
|
||
if (cppstr.empty ()) continue;
|
||
output.push_back (cppstr);
|
||
}
|
||
}
|
||
catch (Exception ^e)
|
||
{
|
||
SetPriLastError (MPStringToStdW (e->Message));
|
||
}
|
||
return output.size ();
|
||
}
|
||
std::vector <std::wstring> split_wcstok (const std::wstring &str, const std::wstring &delim)
|
||
{
|
||
std::vector <std::wstring> result;
|
||
std::wstring cpy = L"" + str;
|
||
LPWSTR context = nullptr;
|
||
LPWSTR token = wcstok ((LPWSTR)cpy.c_str (), delim.c_str (), &context);
|
||
while (token)
|
||
{
|
||
result.push_back (token);
|
||
token = wcstok (nullptr, delim.c_str (), &context);
|
||
}
|
||
return result;
|
||
}
|
||
std::vector <std::wnstring> VecWStringToWNString (const std::vector <std::wstring> &vec)
|
||
{
|
||
std::vector <std::wnstring> wns;
|
||
wns.reserve (vec.size ());
|
||
for (auto &it : vec) wns.push_back (it);
|
||
return wns;
|
||
}
|
||
size_t KeyToPath (const std::wstring &key, std::vector <std::wnstring> &output)
|
||
{
|
||
output.clear ();
|
||
try
|
||
{
|
||
// 1: 字符串,0: 文件路径
|
||
int iTaskType = std::wnstring (GetStringLeft (key, g_cbMsResPNameLength)) == g_swMsResUriProtocolName;
|
||
if (iTaskType)
|
||
{
|
||
Uri ^uri = gcnew Uri (CStringToMPString (key.c_str ()));
|
||
size_t ret = UriToPath (uri, output);
|
||
delete uri;
|
||
uri = nullptr;
|
||
return ret;
|
||
}
|
||
else
|
||
{
|
||
auto arr = split_wcstok (key, L"\\");
|
||
for (auto &it : arr)
|
||
{
|
||
if (std::wnstring (it).empty ()) continue;
|
||
else output.push_back (it);
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ^e)
|
||
{
|
||
auto arr = split_wcstok (key, L"\\");
|
||
for (auto &it : arr)
|
||
{
|
||
if (std::wnstring (it).empty ()) continue;
|
||
else output.push_back (it);
|
||
}
|
||
}
|
||
return output.size ();
|
||
}
|
||
size_t KeyToPath (const TASKITEM_SEARCH &key, std::vector <std::wnstring> &output)
|
||
{
|
||
return KeyToPath (key.swKey, output);
|
||
}
|
||
bool PathEquals (const std::vector <std::wnstring> &left, const std::vector <std::wnstring> &right)
|
||
{
|
||
if (left.size () != right.size ()) return false;
|
||
try
|
||
{
|
||
for (size_t i = 0; i < left.size () && i < right.size (); i ++)
|
||
{
|
||
if (left.at (i) != right.at (i)) return false;
|
||
}
|
||
return true;
|
||
}
|
||
catch (const std::exception &e) {}
|
||
return false;
|
||
}
|
||
|
||
std::map <PCSPRIFILE, TASKINFO_SEARCH> g_tasklist;
|
||
|
||
PCSPRIFILE CreatePriFileInstanceFromStream (PCOISTREAM pStream)
|
||
{
|
||
if (!pStream) return nullptr;
|
||
try
|
||
{
|
||
HRESULT hr = S_OK;
|
||
if (pStream) hr = ((IStream *)pStream)->Seek (LARGE_INTEGER {}, STREAM_SEEK_SET, nullptr);
|
||
System::IO::Stream ^stream = nullptr;
|
||
auto pri = PriFile::Parse (ComIStreamToCliIStream (reinterpret_cast <IStream *> (pStream)), stream);
|
||
PriFileInst ^inst = gcnew PriFileInst ();
|
||
inst->inst = pri;
|
||
inst->opentype = OpenType::IStream;
|
||
inst->isptr = reinterpret_cast <IStream *> (pStream);
|
||
inst->fsptr = stream;
|
||
auto handle = System::Runtime::InteropServices::GCHandle::Alloc (inst);
|
||
IntPtr token = System::Runtime::InteropServices::GCHandle::ToIntPtr (handle);
|
||
return reinterpret_cast <PCSPRIFILE> (token.ToPointer ());
|
||
}
|
||
catch (System::Exception ^e)
|
||
{
|
||
SetPriLastError (MPStringToStdW (e->Message));
|
||
}
|
||
return nullptr;
|
||
}
|
||
PCSPRIFILE CreatePriFileInstanceFromPath (LPCWSTR lpswFilePath)
|
||
{
|
||
if (!lpswFilePath) return nullptr;
|
||
if (!*lpswFilePath) return nullptr;
|
||
try
|
||
{
|
||
auto fstream = System::IO::File::OpenRead (CStringToMPString (lpswFilePath ? lpswFilePath : L""));
|
||
auto pri = PriFile::Parse (fstream);
|
||
PriFileInst ^inst = gcnew PriFileInst ();
|
||
inst->inst = pri;
|
||
inst->opentype = OpenType::Stream;
|
||
inst->fsptr = fstream;
|
||
auto handle = System::Runtime::InteropServices::GCHandle::Alloc (inst);
|
||
IntPtr token = System::Runtime::InteropServices::GCHandle::ToIntPtr (handle);
|
||
return reinterpret_cast <PCSPRIFILE> (token.ToPointer ());
|
||
}
|
||
catch (System::Exception ^e)
|
||
{
|
||
SetPriLastError (MPStringToStdW (e->Message));
|
||
}
|
||
return nullptr;
|
||
}
|
||
//void DestroyPriFileInstance (PCSPRIFILE pFilePri)
|
||
//{
|
||
// if (!pFilePri) return;
|
||
// try
|
||
// {
|
||
// if (g_tasklist.find (pFilePri) != g_tasklist.end ())
|
||
// {
|
||
// g_tasklist [pFilePri].bIsRunning = false;
|
||
// g_tasklist.erase (pFilePri);
|
||
// }
|
||
// IntPtr handlePtr = IntPtr (pFilePri);
|
||
// System::Runtime::InteropServices::GCHandle handle = System::Runtime::InteropServices::GCHandle::FromIntPtr (handlePtr);
|
||
// PriFileInst ^inst = safe_cast <PriFileInst ^> (handle.Target);
|
||
// delete inst;
|
||
// handle.Free ();
|
||
// System::GC::Collect ();
|
||
// System::GC::WaitForPendingFinalizers ();
|
||
// System::GC::Collect ();
|
||
// }
|
||
// catch (System::Exception ^e)
|
||
// {
|
||
// SetPriLastError (MPStringToStdW (e->Message));
|
||
// }
|
||
//}
|
||
void DestroyPriFileInstance (PCSPRIFILE pFilePri)
|
||
{
|
||
if (!pFilePri) return;
|
||
try
|
||
{
|
||
CreateScopedLock (g_threadlock);
|
||
auto it = g_tasklist.find (pFilePri);
|
||
if (it != g_tasklist.end ())
|
||
{
|
||
it->second.bIsRunning = false;
|
||
g_tasklist.erase (it);
|
||
}
|
||
IntPtr handlePtr = IntPtr (pFilePri);
|
||
System::Runtime::InteropServices::GCHandle handle = System::Runtime::InteropServices::GCHandle::FromIntPtr (handlePtr);
|
||
PriFileInst ^inst = safe_cast <PriFileInst ^> (handle.Target);
|
||
delete inst;
|
||
handle.Free ();
|
||
}
|
||
catch (System::Exception ^e)
|
||
{
|
||
SetPriLastError (MPStringToStdW (e->Message));
|
||
}
|
||
System::GC::Collect ();
|
||
System::GC::WaitForPendingFinalizers ();
|
||
System::GC::Collect ();
|
||
}
|
||
LPCWSTR PriFileGetLastError ()
|
||
{
|
||
CreateScopedLock (g_csLastErr);
|
||
return g_swExcept.c_str ();
|
||
}
|
||
enum class Contrast
|
||
{
|
||
None = 0,
|
||
White = 1,
|
||
Black = 2,
|
||
High = 3,
|
||
Low = 4
|
||
};
|
||
struct candidate_value
|
||
{
|
||
int type; // 1:语言;2:缩放和对比度;0:未知
|
||
std::wstring value;
|
||
union restitem
|
||
{
|
||
struct // type==1
|
||
{
|
||
std::wstring languages;
|
||
};
|
||
struct // type==2
|
||
{
|
||
uint32_t scale;
|
||
Contrast contrast;
|
||
};
|
||
struct // type==0
|
||
{
|
||
std::wstring not_support_restrict;
|
||
};
|
||
restitem () {} // 不做初始化,由外层控制构造
|
||
~restitem () {} // 不自动析构,由外层控制析构
|
||
} restitems;
|
||
candidate_value (const std::wstring &val, const std::wstring &lang): type (1), value (val)
|
||
{
|
||
new(&restitems.languages) std::wstring (lang);
|
||
}
|
||
candidate_value (const std::wstring &val, uint32_t scale, Contrast contrast = Contrast::None): type (2), value (val)
|
||
{
|
||
restitems.scale = scale;
|
||
restitems.contrast = contrast;
|
||
}
|
||
candidate_value (const std::wstring &val): type (0), value (val)
|
||
{
|
||
new (&restitems.not_support_restrict) std::wstring (L"");
|
||
}
|
||
candidate_value (const candidate_value &other): type (other.type), value (other.value)
|
||
{
|
||
if (type == 1) new(&restitems.languages) std::wstring (other.restitems.languages);
|
||
else if (type == 2)
|
||
{
|
||
restitems.scale = other.restitems.scale;
|
||
restitems.contrast = other.restitems.contrast;
|
||
}
|
||
else new (&restitems.not_support_restrict) std::wstring (other.restitems.not_support_restrict);
|
||
}
|
||
candidate_value &operator = (const candidate_value &other)
|
||
{
|
||
if (this != &other)
|
||
{
|
||
this->~candidate_value (); // 先析构旧内容
|
||
new (this) candidate_value (other); // 再调用拷贝构造
|
||
}
|
||
return *this;
|
||
}
|
||
~candidate_value ()
|
||
{
|
||
if (type == 1) restitems.languages.~basic_string ();
|
||
else if (type == 0) restitems.not_support_restrict.~basic_string ();
|
||
}
|
||
std::wstring get_language () const { return type == 1 ? restitems.languages : L""; }
|
||
uint32_t get_scale () const { return type == 2 ? restitems.scale : 0; }
|
||
Contrast get_contrast () const { return type == 2 ? restitems.contrast : Contrast::None; }
|
||
};
|
||
std::wstring GetStringValueByLocale (std::vector <candidate_value> &stringcand, const std::wstring &llc)
|
||
{
|
||
for (auto &it : stringcand)
|
||
{
|
||
if (LocaleNameCompare (it.get_language (), llc)) return it.value;
|
||
}
|
||
std::vector <std::wstring> scrc;
|
||
for (auto &it : stringcand)
|
||
{
|
||
std::wstring rc;
|
||
scrc.push_back (rc = GetLocaleRestrictedCodeFromLcidW (LocaleCodeToLcidW (it.get_language ())));
|
||
if (LocaleNameCompare (rc, llc)) return it.value;
|
||
}
|
||
std::wstring lrc = GetLocaleRestrictedCodeFromLcidW (LocaleCodeToLcidW (llc));
|
||
for (size_t i = 0; i < stringcand.size (); i ++)
|
||
{
|
||
auto &rc = scrc.at (i);
|
||
auto &it = stringcand.at (i);
|
||
if (LocaleNameCompare (rc, llc)) return it.value;
|
||
}
|
||
return L"";
|
||
}
|
||
std::wstring GetSuitableStringValue (std::vector <candidate_value> &stringcand)
|
||
{
|
||
std::wstring ret = GetStringValueByLocale (stringcand, GetComputerLocaleCodeW ());
|
||
if (ret.empty () || std::wnstring::trim (ret).length () == 0) ret = GetStringValueByLocale (stringcand, L"en-US");
|
||
if (ret.empty () || std::wnstring::trim (ret).length () == 0)
|
||
{
|
||
for (auto &it : stringcand) return it.value;
|
||
}
|
||
return ret;
|
||
}
|
||
std::wstring GetSuitablePathValueByDPI (std::vector<candidate_value> &pathcand)
|
||
{
|
||
std::sort (pathcand.begin (), pathcand.end (),
|
||
[] (const candidate_value &v1, const candidate_value &v2) {
|
||
return v1.get_scale () < v2.get_scale ();
|
||
});
|
||
if (pathcand.empty ()) return L"";
|
||
uint32_t nowdpi = GetDPI ();
|
||
for (auto &cv : pathcand) if (cv.get_scale () >= nowdpi && !StrInclude (cv.value, L"layoutdir-RTL", true)) return cv.value;
|
||
return pathcand.back ().value;
|
||
}
|
||
std::wstring GetSuitablePathValue (std::vector <candidate_value> &pathcand)
|
||
{
|
||
std::vector <candidate_value> contrasted;
|
||
for (auto &it : pathcand) if (it.get_contrast () == Contrast::None) contrasted.emplace_back (it);
|
||
std::wstring ret = GetSuitablePathValueByDPI (contrasted);
|
||
if (std::wnstring (ret).empty ())
|
||
{
|
||
contrasted.clear ();
|
||
for (auto &it: pathcand) if (it.get_contrast () == Contrast::White) contrasted.emplace_back (it);
|
||
ret = GetSuitablePathValueByDPI (contrasted);
|
||
}
|
||
if (std::wnstring (ret).empty ())
|
||
{
|
||
contrasted.clear ();
|
||
for (auto &it : pathcand) if (it.get_contrast () == Contrast::Black) contrasted.emplace_back (it);
|
||
ret = GetSuitablePathValueByDPI (contrasted);
|
||
}
|
||
if (std::wnstring (ret).empty ())
|
||
{
|
||
contrasted.clear ();
|
||
for (auto &it : pathcand) contrasted.emplace_back (it);
|
||
ret = GetSuitablePathValueByDPI (contrasted);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
void PriFileIterateTask (PCSPRIFILE pFilePri)
|
||
{
|
||
CreateScopedLock (g_threadlock);
|
||
if (g_tasklist.find (pFilePri) == g_tasklist.end ()) g_tasklist [pFilePri] = TASKINFO_SEARCH ();
|
||
try { g_tasklist.at (pFilePri); } catch (const std::exception &e) { return; }
|
||
auto &task = g_tasklist.at (pFilePri);
|
||
if (task.bIsRunning == false) task.bIsRunning = true;
|
||
else return;
|
||
destruct endt ([&task] () {
|
||
task.bIsRunning = false;
|
||
});
|
||
auto &taskitems = task.mapTasks;
|
||
IntPtr handlePtr = IntPtr (pFilePri);
|
||
System::Runtime::InteropServices::GCHandle handle = System::Runtime::InteropServices::GCHandle::FromIntPtr (handlePtr);
|
||
auto pri = safe_cast <PriFileInst ^> (handle.Target);
|
||
auto &priFile = pri;
|
||
if (!priFile) return;
|
||
auto resmapsect = pri->inst->PriDescriptorSection->ResourceMapSections;
|
||
bool isallsearched = true;
|
||
size_t allitemslen = 0;
|
||
std::map <std::wnstring, size_t> mapitemscnt;
|
||
auto begtime = System::DateTime::Now;
|
||
SearchLoop:
|
||
allitemslen = 0;
|
||
for (size_t i = 0; i < resmapsect->Count; i ++)
|
||
{
|
||
CreateScopedLock (g_iterlock);
|
||
auto resourceMapSectionRef = resmapsect [i];
|
||
auto resourceMapSection = pri->inst->GetSectionByRef (resourceMapSectionRef);
|
||
if (resourceMapSection->HierarchicalSchemaReference != nullptr) continue;
|
||
auto decisionInfoSection = pri->inst->GetSectionByRef (resourceMapSection->DecisionInfoSection);
|
||
for each (auto candidateSet in resourceMapSection->CandidateSets->Values)
|
||
{
|
||
// 超时强制退出(也就没有遍及的必要了)
|
||
if ((System::DateTime::Now - begtime).TotalSeconds > 60) return;
|
||
allitemslen ++;
|
||
auto item = pri->inst->GetResourceMapItemByRef (candidateSet->ResourceMapItem);
|
||
std::wstring itemfullname = MPStringToStdW (item->FullName);
|
||
std::vector <std::wnstring> itempath;
|
||
{
|
||
auto ips = split_wcstok (itemfullname, L"\\");
|
||
for (auto &it : ips)
|
||
{
|
||
if (std::wnstring::empty (it)) continue;
|
||
itempath.push_back (it);
|
||
}
|
||
}
|
||
bool willcont = true;
|
||
TASKITEM_SEARCH *taskkey = nullptr;
|
||
for (auto &it : taskitems)
|
||
{
|
||
auto &key = it.first;
|
||
auto &value = it.second;
|
||
mapitemscnt [key.swKey] ++;
|
||
if (value.has_search ()) continue;
|
||
std::vector <std::wnstring> namepath;
|
||
key.get_path (namepath);
|
||
// KeyToPath (key, namepath);
|
||
if (PathEquals (itempath, namepath))
|
||
{
|
||
taskkey = (TASKITEM_SEARCH *)&key;
|
||
willcont = false;
|
||
break;
|
||
}
|
||
}
|
||
if (willcont) continue;
|
||
auto keyname = taskkey->swKey;
|
||
auto keytype = taskkey->iTaskType;
|
||
std::vector <candidate_value> cands;
|
||
for each (auto candidate in candidateSet->Candidates)
|
||
{
|
||
System::String ^value = nullptr;
|
||
if (candidate->SourceFile.HasValue)
|
||
{
|
||
// 内嵌资源,暂无法处理
|
||
// value = System::String::Format ("<external in {0}>", pri->GetReferencedFileByRef (candidate->SourceFile.Value)->FullName);
|
||
value = pri->inst->GetReferencedFileByRef (candidate->SourceFile.Value)->FullName;
|
||
}
|
||
else
|
||
{
|
||
ByteSpan ^byteSpan = nullptr;
|
||
if (candidate->DataItem.HasValue) byteSpan = priFile->inst->GetDataItemByRef (candidate->DataItem.Value);
|
||
else byteSpan = candidate->Data.Value;
|
||
pri->Seek (byteSpan->Offset, System::IO::SeekOrigin::Begin);
|
||
auto binaryReader = gcnew System::IO::BinaryReader (pri, System::Text::Encoding::Default, true);
|
||
auto data = binaryReader->ReadBytes ((int)byteSpan->Length);
|
||
switch (candidate->Type)
|
||
{
|
||
case ResourceValueType::AsciiPath:
|
||
case ResourceValueType::AsciiString:
|
||
value = System::Text::Encoding::ASCII->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::Utf8Path:
|
||
case ResourceValueType::Utf8String:
|
||
value = System::Text::Encoding::UTF8->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::Path:
|
||
case ResourceValueType::String:
|
||
value = System::Text::Encoding::Unicode->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::EmbeddedData:
|
||
value = Convert::ToBase64String (data);
|
||
break;
|
||
}
|
||
delete binaryReader;
|
||
delete data;
|
||
binaryReader = nullptr;
|
||
data = nullptr;
|
||
}
|
||
auto qualifierSet = decisionInfoSection->QualifierSets [candidate->QualifierSet];
|
||
auto qualis = gcnew System::Collections::Generic::Dictionary <QualifierType, Object ^> ();
|
||
for each (auto quali in qualifierSet->Qualifiers)
|
||
{
|
||
auto type = quali->Type;
|
||
auto value = quali->Value;
|
||
qualis->Add (type, value);
|
||
}
|
||
if (qualis->ContainsKey (QualifierType::Language))
|
||
{
|
||
cands.push_back (candidate_value (MPStringToStdW (value ? value : System::String::Empty), MPStringToStdW (qualis [QualifierType::Language]->ToString ())));
|
||
}
|
||
else if (qualis->ContainsKey (QualifierType::Scale))
|
||
{
|
||
if (qualis->ContainsKey (QualifierType::Contrast))
|
||
{
|
||
Contrast ct = Contrast::None;
|
||
auto contstr = std::wnstring (MPStringToStdW (qualis [QualifierType::Contrast]->ToString ()->Trim ()->ToUpper ()));
|
||
if (contstr.equals (L"WHITE")) ct = Contrast::White;
|
||
else if (contstr.equals (L"BLACK")) ct = Contrast::Black;
|
||
else if (contstr.equals (L"HIGH")) ct = Contrast::High;
|
||
cands.push_back (candidate_value (
|
||
MPStringToStdW (value ? value : System::String::Empty),
|
||
Convert::ToUInt32 (qualis [QualifierType::Scale]),
|
||
ct
|
||
));
|
||
}
|
||
else
|
||
{
|
||
cands.push_back (candidate_value (
|
||
MPStringToStdW (value ? value : System::String::Empty),
|
||
Convert::ToUInt32 (qualis [QualifierType::Scale])
|
||
));
|
||
}
|
||
}
|
||
else cands.push_back (candidate_value (MPStringToStdW (value ? value : System::String::Empty)));
|
||
delete qualis;
|
||
qualis = nullptr;
|
||
}
|
||
switch (keytype)
|
||
{
|
||
case 0: {
|
||
TASKRESULT_FIND tfind;
|
||
tfind.iFindResult = 1;
|
||
tfind.swValue = GetSuitableStringValue (cands);
|
||
taskitems [*taskkey] = tfind;
|
||
} break;
|
||
case 1: {
|
||
TASKRESULT_FIND tfind;
|
||
tfind.iFindResult = 1;
|
||
tfind.swValue = GetSuitablePathValue (cands);
|
||
taskitems [*taskkey] = tfind;
|
||
} break;
|
||
default: {
|
||
TASKRESULT_FIND tfind;
|
||
tfind.iFindResult = 0;
|
||
try
|
||
{
|
||
tfind.swValue = cands.at (0).value;
|
||
}
|
||
catch (const std::exception &e) {}
|
||
taskitems [*taskkey] = tfind;
|
||
} break;
|
||
}
|
||
}
|
||
// delete resourceMapSection;
|
||
resourceMapSection = nullptr;
|
||
}
|
||
isallsearched = true;
|
||
for (auto &it : mapitemscnt)
|
||
{
|
||
auto &result = taskitems [TASKITEM_SEARCH (it.first)];
|
||
isallsearched = isallsearched && (it.second >= allitemslen && result.has_search ());
|
||
if (it.second >= allitemslen)
|
||
{
|
||
if (!result.has_search ()) result.iFindResult = 0;
|
||
}
|
||
it.second = 0;
|
||
}
|
||
if (!isallsearched)
|
||
{
|
||
for (auto &it : mapitemscnt) it.second = 0;
|
||
goto SearchLoop;
|
||
}
|
||
// task.bIsRunning = false;
|
||
}
|
||
void PriFileIterateTaskCli (Object^ pFilePriObj)
|
||
{
|
||
if (pFilePriObj == nullptr) return;
|
||
IntPtr ptr = safe_cast <IntPtr> (pFilePriObj);
|
||
PCSPRIFILE pFilePri = (PCSPRIFILE)ptr.ToPointer ();
|
||
PriFileIterateTask (pFilePri);
|
||
}
|
||
//void AddPriResourceName (PCSPRIFILE pFilePri, const std::vector <std::wnstring> &urilist)
|
||
//{
|
||
// if (!pFilePri) return;
|
||
// if (!urilist.size ()) return;
|
||
// try { g_tasklist.at (pFilePri); } catch (const std::exception &e) { g_tasklist [pFilePri] = TASKINFO_SEARCH (); }
|
||
// auto &task = g_tasklist.at (pFilePri);
|
||
// bool isallfined = true;
|
||
// {
|
||
// CreateScopedLock (g_threadlock);
|
||
// CreateScopedLock (g_iterlock);
|
||
// for (auto &it : urilist)
|
||
// {
|
||
// if (it.empty ()) continue;
|
||
// try
|
||
// {
|
||
// if (task.mapTasks [TASKITEM_SEARCH (it)].has_search ())
|
||
// {
|
||
// isallfined = isallfined && true;
|
||
// continue;
|
||
// }
|
||
// else isallfined = isallfined && false;
|
||
// }
|
||
// catch (const std::exception &e)
|
||
// {
|
||
// task.mapTasks [TASKITEM_SEARCH (it)] = TASKRESULT_FIND ();
|
||
// isallfined = isallfined && false;
|
||
// }
|
||
// }
|
||
// }
|
||
// if (isallfined) return;
|
||
// // while (task.bIsRunning) { Sleep (200); }
|
||
// System::Threading::Thread ^t = nullptr;
|
||
// if (!task.bIsRunning)
|
||
// {
|
||
// // task.bIsRunning = true;
|
||
// t = gcnew System::Threading::Thread (gcnew System::Threading::ParameterizedThreadStart (PriFileIterateTaskCli));
|
||
// t->IsBackground = true;
|
||
// t->Start (IntPtr (pFilePri));
|
||
// }
|
||
//}
|
||
#ifdef ELDER_FUNC
|
||
void AddPriResourceName (PCSPRIFILE pFilePri, const std::vector <std::wnstring> &urilist)
|
||
{
|
||
if (!pFilePri) return;
|
||
if (!urilist.size ()) return;
|
||
{
|
||
CreateScopedLock (g_threadlock);
|
||
CreateScopedLock (g_iterlock);
|
||
if (g_tasklist.find (pFilePri) == g_tasklist.end ())
|
||
{
|
||
g_tasklist [pFilePri] = TASKINFO_SEARCH ();
|
||
}
|
||
}
|
||
TASKINFO_SEARCH *ptask = nullptr;
|
||
{
|
||
CreateScopedLock (g_threadlock);
|
||
CreateScopedLock (g_iterlock);
|
||
ptask = &g_tasklist.at (pFilePri);
|
||
}
|
||
auto &task = *ptask;
|
||
bool isallfined = true;
|
||
{
|
||
CreateScopedLock (g_threadlock);
|
||
CreateScopedLock (g_iterlock);
|
||
for (auto &it : urilist)
|
||
{
|
||
if (it.empty ()) continue;
|
||
TASKITEM_SEARCH key (it);
|
||
auto itFound = task.mapTasks.find (key);
|
||
if (itFound != task.mapTasks.end ())
|
||
{
|
||
if (itFound->second.has_search ())
|
||
{
|
||
isallfined = isallfined && true;
|
||
continue;
|
||
}
|
||
else isallfined = isallfined && false;
|
||
}
|
||
else
|
||
{
|
||
task.mapTasks [key] = TASKRESULT_FIND ();
|
||
isallfined = isallfined && false;
|
||
}
|
||
}
|
||
}
|
||
if (isallfined) return;
|
||
{
|
||
CreateScopedLock (g_threadlock);
|
||
CreateScopedLock (g_iterlock);
|
||
if (!task.bIsRunning)
|
||
{
|
||
System::Threading::Thread ^t = gcnew System::Threading::Thread (gcnew System::Threading::ParameterizedThreadStart (PriFileIterateTaskCli));
|
||
t->IsBackground = true;
|
||
t->Start (IntPtr (pFilePri));
|
||
}
|
||
}
|
||
}
|
||
void FindPriResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hUriList)
|
||
{
|
||
if (!pFilePri) return;
|
||
if (!hUriList || !hUriList->dwLength) return;
|
||
std::vector <std::wnstring> list;
|
||
for (size_t i = 0; i < hUriList->dwLength; i ++)
|
||
{
|
||
auto &str = hUriList->aswArray [i];
|
||
if (!str || !*str) continue;
|
||
std::wnstring wstr (str);
|
||
if (wstr.empty ()) continue;
|
||
list.emplace_back (wstr);
|
||
}
|
||
AddPriResourceName (pFilePri, list);
|
||
}
|
||
void FindPriStringResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hUriList)
|
||
{
|
||
FindPriResource (pFilePri, hUriList);
|
||
}
|
||
void FindPriPathResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hPathList)
|
||
{
|
||
FindPriResource (pFilePri, hPathList);
|
||
}
|
||
LPWSTR GetPriResource (PCSPRIFILE pFilePri, LPCWSTR lpswResId)
|
||
{
|
||
if (!pFilePri || !lpswResId || !*lpswResId) return nullptr;
|
||
try { g_tasklist.at (pFilePri); }
|
||
catch (const std::exception &e) { g_tasklist [pFilePri]; }
|
||
auto &task = g_tasklist.at (pFilePri);
|
||
{
|
||
auto &result = task.mapTasks [TASKITEM_SEARCH (lpswResId)];
|
||
if (result.has_search ()) return _wcsdup (result.swValue.c_str ());
|
||
}
|
||
BYTE buf [sizeof (LPCWSTRLIST) + sizeof (LPCWSTR)] = { 0 };
|
||
HLPCWSTRLIST hStrList = (HLPCWSTRLIST)buf;
|
||
hStrList->dwLength = 1;
|
||
hStrList->aswArray [0] = lpswResId;
|
||
FindPriResource (pFilePri, hStrList);
|
||
while (task.bIsRunning) { Sleep (200); }
|
||
try
|
||
{
|
||
auto item = task.mapTasks.at (TASKITEM_SEARCH (lpswResId));
|
||
if (!item.has_search ()) return GetPriResource (pFilePri, lpswResId);
|
||
return _wcsdup (item.swValue.c_str ());
|
||
}
|
||
catch (const std::exception &e)
|
||
{
|
||
SetPriLastError (StringToWString (e.what () ? e.what () : "Error: cannot find the resource."));
|
||
return nullptr;
|
||
}
|
||
}
|
||
LPWSTR GetPriStringResource (PCSPRIFILE pFilePri, LPCWSTR lpswUri) { return GetPriResource (pFilePri, lpswUri); }
|
||
LPWSTR GetPriPathResource (PCSPRIFILE pFilePri, LPCWSTR lpswFilePath) { return GetPriResource (pFilePri, lpswFilePath); }
|
||
#endif
|
||
void ClearPriCacheData ()
|
||
{
|
||
g_tasklist.clear ();
|
||
}
|
||
|
||
BOOL IsMsResourcePrefix (LPCWSTR pResName)
|
||
{
|
||
return std::wnstring (GetStringLeft (std::wnstring::trim (std::wstring (pResName ? pResName : L"")), g_cbMsResPNameLength)) == g_swMsResUriProtocolName;
|
||
}
|
||
BOOL IsMsResourceUriFull (LPCWSTR pResUri)
|
||
{
|
||
const std::wstring root = L"//";
|
||
return std::wnstring (GetStringLeft (std::wnstring::trim (std::wstring (pResUri)), g_cbMsResPNameLength + root.length ())) == g_swMsResUriProtocolName + root;
|
||
}
|
||
BOOL IsMsResourceUri (LPCWSTR pResUri)
|
||
{
|
||
if (!IsMsResourcePrefix (pResUri)) return false;
|
||
try { Uri ^uri = gcnew Uri (gcnew String (pResUri ? pResUri : L"")); delete uri; }
|
||
catch (Exception ^e) { return false; }
|
||
return true;
|
||
}
|
||
|
||
void PriFormatFreeString (LPWSTR lpStrFromThisDll)
|
||
{
|
||
if (!lpStrFromThisDll) return;
|
||
free (lpStrFromThisDll);
|
||
}
|
||
|
||
PriFileInst ^GetPriFileInst (PCSPRIFILE file)
|
||
{
|
||
if (!file) return nullptr;
|
||
using namespace System::Runtime::InteropServices;
|
||
IntPtr ptr (file); // void* → IntPtr
|
||
GCHandle handle = GCHandle::FromIntPtr (ptr);
|
||
return safe_cast<PriFileInst^>(handle.Target);
|
||
}
|
||
|
||
// 高 16 位:
|
||
// 高 4 位:0: Scale 资源, 1: TargetSize 资源, 2: 字符串资源(防止无法获取资源)
|
||
// 低 4 位:对比度 0 None, 1 White, 2 Black, 3 High, 4 Low
|
||
// 低 16 位:
|
||
// Scale 或 TargetSize 或 LCID
|
||
// 运行时,外部不可使用 output
|
||
#define PRI_TYPE_SHIFT 28
|
||
#define PRI_CONTRAST_SHIFT 24
|
||
#define PRI_TYPE_MASK 0xF0000000
|
||
#define PRI_CONTRAST_MASK 0x0F000000
|
||
#define PRI_VALUE_MASK 0x0000FFFF
|
||
#define PRI_MAKE_KEY(type, contrast, value) \
|
||
( ((DWORD)(type) << PRI_TYPE_SHIFT) | \
|
||
((DWORD)(contrast) << PRI_CONTRAST_SHIFT) | \
|
||
((DWORD)(value) & PRI_VALUE_MASK) )
|
||
#define PRI_MAKE_SCALE(scale, contrast) PRI_MAKE_KEY(0, contrast, scale)
|
||
#define PRI_MAKE_TARGETSIZE(size, contrast) PRI_MAKE_KEY(1, contrast, size)
|
||
#define PRI_MAKE_STRING(lcid) PRI_MAKE_KEY(2, 0, lcid)
|
||
size_t GetPriScaleAndTargetSizeFileList (
|
||
PCSPRIFILE pPriFile,
|
||
const std::vector <std::wstring> &resnames,
|
||
std::map <std::wnstring, std::map <DWORD, std::wnstring>> &output
|
||
)
|
||
{
|
||
output.clear ();
|
||
if (!pPriFile) return 0;
|
||
auto inst = GetPriFileInst (pPriFile);
|
||
auto pri = inst->inst;
|
||
auto priFile = inst;
|
||
auto resmapsect = pri->PriDescriptorSection->ResourceMapSections;
|
||
std::set <std::wnstring> rnlist;
|
||
for (auto &it : resnames) rnlist.insert (std::wnstring (it));
|
||
for (size_t i = 0; i < resmapsect->Count; i ++)
|
||
{
|
||
auto resourceMapSectionRef = resmapsect [i];
|
||
auto resourceMapSection = pri->GetSectionByRef (resourceMapSectionRef);
|
||
if (resourceMapSection->HierarchicalSchemaReference != nullptr) continue;
|
||
auto decisionInfoSection = pri->GetSectionByRef (resourceMapSection->DecisionInfoSection);
|
||
for each (auto candidateSet in resourceMapSection->CandidateSets->Values)
|
||
{
|
||
auto item = pri->GetResourceMapItemByRef (candidateSet->ResourceMapItem);
|
||
std::wstring itemfullname = MPStringToStdW (item->FullName);
|
||
std::vector <std::wnstring> itempath;
|
||
{
|
||
auto ips = split_wcstok (itemfullname, L"\\");
|
||
for (auto &it : ips)
|
||
{
|
||
if (std::wnstring::empty (it)) continue;
|
||
itempath.push_back (it);
|
||
}
|
||
}
|
||
bool isfind = false;
|
||
std::wnstring taskkey = L"";
|
||
int tasktype = 1;
|
||
for (auto &it : rnlist)
|
||
{
|
||
TASKITEM_SEARCH key (it);
|
||
std::vector <std::wnstring> namepath;
|
||
key.get_path (namepath);
|
||
if (PathEquals (itempath, namepath))
|
||
{
|
||
taskkey = it;
|
||
tasktype = key.iTaskType;
|
||
isfind = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!isfind) continue;
|
||
std::map <DWORD, std::wnstring> values;
|
||
for each (auto candidate in candidateSet->Candidates)
|
||
{
|
||
DWORD resc = 0;
|
||
System::String ^value = nullptr;
|
||
if (candidate->SourceFile.HasValue)
|
||
{
|
||
// 内嵌资源,暂无法处理
|
||
// value = System::String::Format ("<external in {0}>", pri->GetReferencedFileByRef (candidate->SourceFile.Value)->FullName);
|
||
value = pri->GetReferencedFileByRef (candidate->SourceFile.Value)->FullName;
|
||
}
|
||
else
|
||
{
|
||
ByteSpan ^byteSpan = nullptr;
|
||
if (candidate->DataItem.HasValue) byteSpan = priFile->inst->GetDataItemByRef (candidate->DataItem.Value);
|
||
else byteSpan = candidate->Data.Value;
|
||
priFile->Seek (byteSpan->Offset, System::IO::SeekOrigin::Begin);
|
||
auto binaryReader = gcnew System::IO::BinaryReader (priFile, System::Text::Encoding::Default, true);
|
||
auto data = binaryReader->ReadBytes ((int)byteSpan->Length);
|
||
switch (candidate->Type)
|
||
{
|
||
case ResourceValueType::AsciiPath:
|
||
case ResourceValueType::AsciiString:
|
||
value = System::Text::Encoding::ASCII->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::Utf8Path:
|
||
case ResourceValueType::Utf8String:
|
||
value = System::Text::Encoding::UTF8->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::Path:
|
||
case ResourceValueType::String:
|
||
value = System::Text::Encoding::Unicode->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::EmbeddedData:
|
||
value = Convert::ToBase64String (data);
|
||
break;
|
||
}
|
||
delete binaryReader;
|
||
delete data;
|
||
binaryReader = nullptr;
|
||
data = nullptr;
|
||
}
|
||
auto qualifierSet = decisionInfoSection->QualifierSets [candidate->QualifierSet];
|
||
auto qualis = gcnew System::Collections::Generic::Dictionary <QualifierType, Object ^> ();
|
||
for each (auto quali in qualifierSet->Qualifiers)
|
||
{
|
||
auto type = quali->Type;
|
||
auto value = quali->Value;
|
||
qualis->Add (type, value);
|
||
}
|
||
if (qualis->ContainsKey (QualifierType::Language))
|
||
{
|
||
resc = PRI_MAKE_STRING (LocaleCodeToLcidW (MPStringToStdW (qualis [QualifierType::Language]->ToString ())));
|
||
values [resc] = MPStringToStdW (value ? value : System::String::Empty);
|
||
}
|
||
else if (qualis->ContainsKey (QualifierType::TargetSize))
|
||
{
|
||
if (qualis->ContainsKey (QualifierType::Contrast))
|
||
{
|
||
Contrast ct = Contrast::None;
|
||
auto contstr = std::wnstring (MPStringToStdW (qualis [QualifierType::Contrast]->ToString ()->Trim ()->ToUpper ()));
|
||
if (contstr.equals (L"WHITE")) ct = Contrast::White;
|
||
else if (contstr.equals (L"BLACK")) ct = Contrast::Black;
|
||
else if (contstr.equals (L"HIGH")) ct = Contrast::High;
|
||
resc = PRI_MAKE_TARGETSIZE (Convert::ToUInt32 (qualis [QualifierType::TargetSize]), (DWORD)ct);
|
||
values [resc] = MPStringToStdW (value ? value : System::String::Empty);
|
||
}
|
||
else
|
||
{
|
||
resc = PRI_MAKE_TARGETSIZE (Convert::ToUInt32 (qualis [QualifierType::TargetSize]), 0);
|
||
values [resc] = MPStringToStdW (value ? value : System::String::Empty);
|
||
}
|
||
}
|
||
else if (qualis->ContainsKey (QualifierType::Scale))
|
||
{
|
||
if (qualis->ContainsKey (QualifierType::Contrast))
|
||
{
|
||
Contrast ct = Contrast::None;
|
||
auto contstr = std::wnstring (MPStringToStdW (qualis [QualifierType::Contrast]->ToString ()->Trim ()->ToUpper ()));
|
||
if (contstr.equals (L"WHITE")) ct = Contrast::White;
|
||
else if (contstr.equals (L"BLACK")) ct = Contrast::Black;
|
||
else if (contstr.equals (L"HIGH")) ct = Contrast::High;
|
||
resc = PRI_MAKE_SCALE (Convert::ToUInt32 (qualis [QualifierType::Scale]), (DWORD)ct);
|
||
values [resc] = MPStringToStdW (value ? value : System::String::Empty);
|
||
}
|
||
else
|
||
{
|
||
resc = PRI_MAKE_SCALE (Convert::ToUInt32 (qualis [QualifierType::Scale]), 0);
|
||
values [resc] = MPStringToStdW (value ? value : System::String::Empty);
|
||
}
|
||
}
|
||
delete qualis;
|
||
qualis = nullptr;
|
||
}
|
||
output [taskkey] = values;
|
||
rnlist.erase (taskkey);
|
||
}
|
||
resourceMapSection = nullptr;
|
||
}
|
||
}
|
||
HDWSPAIRLIST CreateDWSPAIRLISTFromMap (const std::map <DWORD, std::wstring> &input)
|
||
{
|
||
DWORD count = (DWORD)input.size ();
|
||
if (count == 0) return nullptr;
|
||
size_t totalSize = sizeof (DWSPAIRLIST) + sizeof (DWORDWSTRPAIR) * (count - 1);
|
||
HDWSPAIRLIST list = (HDWSPAIRLIST)malloc (totalSize);
|
||
if (!list) return nullptr;
|
||
list->dwLength = count;
|
||
DWORD index = 0;
|
||
for (auto &it : input)
|
||
{
|
||
list->lpArray [index].dwKey = it.first;
|
||
list->lpArray [index].lpValue = _wcsdup (it.second.c_str ());
|
||
index ++;
|
||
}
|
||
return list;
|
||
}
|
||
HDWSPAIRLIST CreateDWSPAIRLISTFromMap (const std::map <DWORD, std::wnstring> &input)
|
||
{
|
||
DWORD count = (DWORD)input.size ();
|
||
if (count == 0) return nullptr;
|
||
size_t totalSize = sizeof (DWSPAIRLIST) + sizeof (DWORDWSTRPAIR) * (count - 1);
|
||
HDWSPAIRLIST list = (HDWSPAIRLIST)malloc (totalSize);
|
||
if (!list) return nullptr;
|
||
list->dwLength = count;
|
||
DWORD index = 0;
|
||
for (auto &it : input)
|
||
{
|
||
list->lpArray [index].dwKey = it.first;
|
||
list->lpArray [index].lpValue = _wcsdup (it.second.c_str ());
|
||
index ++;
|
||
}
|
||
return list;
|
||
}
|
||
void DestroyPriResourceAllValueList (HDWSPAIRLIST list)
|
||
{
|
||
if (!list) return;
|
||
for (DWORD i = 0; i < list->dwLength; i++)
|
||
{
|
||
if (list->lpArray [i].lpValue)
|
||
{
|
||
free (list->lpArray [i].lpValue); // 对应 _wcsdup
|
||
list->lpArray [i].lpValue = NULL;
|
||
}
|
||
}
|
||
free (list);
|
||
}
|
||
HDWSPAIRLIST GetPriResourceAllValueList (PCSPRIFILE pPriFile, LPCWSTR lpResName)
|
||
{
|
||
if (!pPriFile || !lpResName) return nullptr;
|
||
std::map <std::wnstring, std::map <DWORD, std::wnstring>> rnout;
|
||
std::vector <std::wstring> rnl = {lpResName ? lpResName : L""};
|
||
GetPriScaleAndTargetSizeFileList (pPriFile, rnl, rnout);
|
||
for (auto &it : rnout) return CreateDWSPAIRLISTFromMap (it.second);
|
||
return nullptr;
|
||
}
|
||
HWSDSPAIRLIST CreateWSDSPAIRLISTFromMap (const std::map <std::wnstring, std::map <DWORD, std::wnstring>> &input)
|
||
{
|
||
DWORD count = (DWORD)input.size ();
|
||
if (count == 0) return nullptr;
|
||
size_t totalSize = sizeof (WSDSPAIRLIST) + sizeof (WSDSPAIR) * (count - 1);
|
||
HWSDSPAIRLIST list = (HWSDSPAIRLIST)malloc (totalSize);
|
||
if (!list) return nullptr;
|
||
list->dwLength = count;
|
||
DWORD index = 0;
|
||
for (auto &it : input)
|
||
{
|
||
list->lpArray [index].lpKey = _wcsdup (it.first.c_str ());
|
||
list->lpArray [index].lpValue = nullptr;
|
||
if (!it.second.empty ())
|
||
{
|
||
list->lpArray [index].lpValue = CreateDWSPAIRLISTFromMap (it.second);
|
||
}
|
||
index ++;
|
||
}
|
||
return list;
|
||
}
|
||
void DestroyResourcesAllValuesList (HWSDSPAIRLIST list)
|
||
{
|
||
if (!list) return;
|
||
for (DWORD i = 0; i < list->dwLength; i++)
|
||
{
|
||
if (list->lpArray [i].lpKey)
|
||
{
|
||
free (list->lpArray [i].lpKey);
|
||
list->lpArray [i].lpKey = nullptr;
|
||
}
|
||
if (list->lpArray [i].lpValue)
|
||
{
|
||
DestroyPriResourceAllValueList (list->lpArray [i].lpValue);
|
||
list->lpArray [i].lpValue = nullptr;
|
||
}
|
||
}
|
||
free (list);
|
||
}
|
||
HWSDSPAIRLIST GetPriResourcesAllValuesList (PCSPRIFILE pPriFile, const LPCWSTR *lpResNames, DWORD dwCount)
|
||
{
|
||
if (!pPriFile || !lpResNames || dwCount == 0) return nullptr;
|
||
std::map <std::wnstring, std::map <DWORD, std::wnstring>> rnout;
|
||
std::vector<std::wstring> rnl;
|
||
rnl.reserve (dwCount);
|
||
for (DWORD i = 0; i < dwCount; i++)
|
||
{
|
||
if (lpResNames [i])
|
||
rnl.emplace_back (lpResNames [i]);
|
||
}
|
||
if (rnl.empty ()) return nullptr;
|
||
GetPriScaleAndTargetSizeFileList (pPriFile, rnl, rnout);
|
||
if (rnout.empty ()) return nullptr;
|
||
return CreateWSDSPAIRLISTFromMap (rnout);
|
||
}
|
||
|
||
#ifndef ELDER_FUNC
|
||
size_t GetPriLocaleStringResources (
|
||
PCSPRIFILE pPriFile,
|
||
const std::vector <std::wstring> &resnames,
|
||
std::map <std::wnstring, std::map <std::wnstring, std::wstring>> &output
|
||
)
|
||
{
|
||
output.clear ();
|
||
if (!pPriFile) return 0;
|
||
auto inst = GetPriFileInst (pPriFile);
|
||
auto pri = inst->inst;
|
||
auto priFile = inst;
|
||
auto resmapsect = pri->PriDescriptorSection->ResourceMapSections;
|
||
std::set <std::wnstring> rnlist;
|
||
for (auto &it : resnames) rnlist.insert (std::wnstring (it));
|
||
for (size_t i = 0; i < resmapsect->Count; i ++)
|
||
{
|
||
auto resourceMapSectionRef = resmapsect [i];
|
||
auto resourceMapSection = pri->GetSectionByRef (resourceMapSectionRef);
|
||
if (resourceMapSection->HierarchicalSchemaReference != nullptr) continue;
|
||
auto decisionInfoSection = pri->GetSectionByRef (resourceMapSection->DecisionInfoSection);
|
||
for each (auto candidateSet in resourceMapSection->CandidateSets->Values)
|
||
{
|
||
auto item = pri->GetResourceMapItemByRef (candidateSet->ResourceMapItem);
|
||
std::wstring itemfullname = MPStringToStdW (item->FullName);
|
||
std::vector <std::wnstring> itempath;
|
||
{
|
||
auto ips = split_wcstok (itemfullname, L"\\");
|
||
for (auto &it : ips)
|
||
{
|
||
if (std::wnstring::empty (it)) continue;
|
||
itempath.push_back (it);
|
||
}
|
||
}
|
||
bool isfind = false;
|
||
std::wnstring taskkey = L"";
|
||
int tasktype = 1;
|
||
for (auto &it : rnlist)
|
||
{
|
||
TASKITEM_SEARCH key (it);
|
||
std::vector <std::wnstring> namepath;
|
||
key.get_path (namepath);
|
||
if (PathEquals (itempath, namepath))
|
||
{
|
||
taskkey = it;
|
||
tasktype = key.iTaskType;
|
||
isfind = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!isfind) continue;
|
||
std::map <std::wnstring, std::wstring> values;
|
||
for each (auto candidate in candidateSet->Candidates)
|
||
{
|
||
std::wnstring resc = L"";
|
||
System::String ^value = nullptr;
|
||
if (candidate->SourceFile.HasValue)
|
||
{
|
||
// 内嵌资源,暂无法处理
|
||
// value = System::String::Format ("<external in {0}>", pri->GetReferencedFileByRef (candidate->SourceFile.Value)->FullName);
|
||
value = pri->GetReferencedFileByRef (candidate->SourceFile.Value)->FullName;
|
||
}
|
||
else
|
||
{
|
||
ByteSpan ^byteSpan = nullptr;
|
||
if (candidate->DataItem.HasValue) byteSpan = priFile->inst->GetDataItemByRef (candidate->DataItem.Value);
|
||
else byteSpan = candidate->Data.Value;
|
||
priFile->Seek (byteSpan->Offset, System::IO::SeekOrigin::Begin);
|
||
auto binaryReader = gcnew System::IO::BinaryReader (priFile, System::Text::Encoding::Default, true);
|
||
auto data = binaryReader->ReadBytes ((int)byteSpan->Length);
|
||
switch (candidate->Type)
|
||
{
|
||
case ResourceValueType::AsciiPath:
|
||
case ResourceValueType::AsciiString:
|
||
value = System::Text::Encoding::ASCII->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::Utf8Path:
|
||
case ResourceValueType::Utf8String:
|
||
value = System::Text::Encoding::UTF8->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::Path:
|
||
case ResourceValueType::String:
|
||
value = System::Text::Encoding::Unicode->GetString (data)->TrimEnd ('\0');
|
||
break;
|
||
case ResourceValueType::EmbeddedData:
|
||
value = Convert::ToBase64String (data);
|
||
break;
|
||
}
|
||
delete binaryReader;
|
||
delete data;
|
||
binaryReader = nullptr;
|
||
data = nullptr;
|
||
}
|
||
auto qualifierSet = decisionInfoSection->QualifierSets [candidate->QualifierSet];
|
||
auto qualis = gcnew System::Collections::Generic::Dictionary <QualifierType, Object ^> ();
|
||
for each (auto quali in qualifierSet->Qualifiers)
|
||
{
|
||
auto type = quali->Type;
|
||
auto value = quali->Value;
|
||
qualis->Add (type, value);
|
||
}
|
||
if (qualis->ContainsKey (QualifierType::Language))
|
||
{
|
||
resc = MPStringToStdW (qualis [QualifierType::Language]->ToString ());
|
||
values [resc] = MPStringToStdW (value ? value : System::String::Empty);
|
||
}
|
||
delete qualis;
|
||
qualis = nullptr;
|
||
}
|
||
output [taskkey] = values;
|
||
rnlist.erase (taskkey);
|
||
}
|
||
resourceMapSection = nullptr;
|
||
}
|
||
}
|
||
std::wstring GetConfirmLocaleResources (const std::map <std::wnstring, std::wstring> &strvalue, const std::wnstring &lang)
|
||
{
|
||
for (auto &it : strvalue)
|
||
{
|
||
if (it.first.equals (lang)) return it.second;
|
||
}
|
||
for (auto &it : strvalue)
|
||
{
|
||
if (LocaleNameCompare (it.first, lang)) return it.second;
|
||
}
|
||
auto rest = GetLocaleRestrictedCode (lang);
|
||
for (auto &it : strvalue)
|
||
{
|
||
if (LocaleNameCompare (GetLocaleRestrictedCode (it.first), rest)) return it.second;
|
||
}
|
||
return L"";
|
||
}
|
||
std::wstring GetSuitableLocaleResources (const std::map <std::wnstring, std::wstring> &strvalue)
|
||
{
|
||
auto ret = GetConfirmLocaleResources (strvalue, GetComputerLocaleCodeW ());
|
||
if (ret.empty ()) ret = GetConfirmLocaleResources (strvalue, L"en-US");
|
||
if (ret.empty ())
|
||
{
|
||
if (strvalue.size () > 0) ret = strvalue.begin ()->second;
|
||
}
|
||
return ret;
|
||
}
|
||
std::wstring GetConfirmFileResources (const std::map <DWORD, std::wnstring> &input, unsigned short dpi, unsigned short contrast)
|
||
{
|
||
auto &output = input;
|
||
auto get_type = [] (DWORD key) -> DWORD {
|
||
return (key & PRI_TYPE_MASK) >> PRI_TYPE_SHIFT;
|
||
};
|
||
auto get_contrast = [] (DWORD key) -> DWORD {
|
||
return (key & PRI_CONTRAST_MASK) >> PRI_CONTRAST_SHIFT;
|
||
};
|
||
auto get_value = [] (DWORD key) -> DWORD {
|
||
return key & PRI_VALUE_MASK;
|
||
};
|
||
struct Candidate
|
||
{
|
||
DWORD scale;
|
||
std::wnstring value;
|
||
};
|
||
std::vector <Candidate> exact_contrast;
|
||
std::vector <Candidate> none_contrast;
|
||
for (const auto& kv : output) {
|
||
DWORD key = kv.first;
|
||
DWORD type = get_type (key);
|
||
if (type != 0) continue;
|
||
DWORD cont = get_contrast (key);
|
||
DWORD scale = get_value (key);
|
||
if (StrInclude (kv.second, L"layoutdir-RTL", true)) continue;
|
||
if (cont == contrast) {
|
||
exact_contrast.push_back ({ scale, kv.second });
|
||
}
|
||
else if (cont == 0) {
|
||
none_contrast.push_back ({ scale, kv.second });
|
||
}
|
||
}
|
||
auto select_best = [dpi] (std::vector<Candidate>& candidates) -> std::wstring {
|
||
if (candidates.empty ()) return L"";
|
||
std::sort (candidates.begin (), candidates.end (),
|
||
[] (const Candidate& a, const Candidate& b) {
|
||
return a.scale < b.scale;
|
||
});
|
||
for (const auto &cand : candidates) {
|
||
if (cand.scale == dpi) {
|
||
return cand.value.c_str ();
|
||
}
|
||
}
|
||
for (const auto &cand : candidates) {
|
||
if (cand.scale > dpi) {
|
||
return cand.value.c_str ();
|
||
}
|
||
}
|
||
return candidates.back ().value.c_str ();
|
||
};
|
||
std::wstring result = select_best (exact_contrast);
|
||
if (!result.empty ()) return result;
|
||
return L"";
|
||
}
|
||
std::wstring GetSuitableFileResources (const std::map <DWORD, std::wnstring> &input)
|
||
{
|
||
std::wstring ret = GetConfirmFileResources (input, GetDPI (), 0);
|
||
if (ret.empty ()) ret = GetConfirmFileResources (input, GetDPI (), 2);
|
||
if (ret.empty ()) ret = GetConfirmFileResources (input, GetDPI (), 1);
|
||
if (ret.empty ())
|
||
{
|
||
if (input.size () > 0)
|
||
{
|
||
ret = input.begin ()->second;
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
void AddPriResourceName (PCSPRIFILE pFilePri, const std::vector <std::wnstring> &urilist) {}
|
||
void FindPriResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hUriList) {}
|
||
void FindPriStringResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hUriList) {}
|
||
void FindPriPathResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hPathList) {}
|
||
LPWSTR GetPriResource (PCSPRIFILE pFilePri, LPCWSTR lpswResId)
|
||
{
|
||
if (strnull (lpswResId)) return NULL;
|
||
auto resid = lpswResId ? lpswResId : L"";
|
||
std::vector <std::wstring> ress;
|
||
ress.push_back (lpswResId ? lpswResId : L"");
|
||
std::map <std::wnstring, std::map <std::wnstring, std::wstring>> strRes;
|
||
if (IsMsResourcePrefix (lpswResId))
|
||
{
|
||
GetPriLocaleStringResources (pFilePri, ress, strRes);
|
||
if (strRes.size () > 0)
|
||
{
|
||
auto &res = strRes [std::wnstring (resid)];
|
||
return _wcsdup (GetSuitableLocaleResources (res).c_str ());
|
||
}
|
||
}
|
||
std::map <std::wnstring, std::map <DWORD, std::wnstring>> fileRes;
|
||
GetPriScaleAndTargetSizeFileList (pFilePri, ress, fileRes);
|
||
if (fileRes.size () > 0)
|
||
{
|
||
auto &fres = fileRes [std::wnstring (resid)];
|
||
return _wcsdup (GetSuitableFileResources (fres).c_str ());
|
||
}
|
||
GetPriLocaleStringResources (pFilePri, ress, strRes);
|
||
if (strRes.size () > 0)
|
||
{
|
||
auto &res = strRes [std::wnstring (resid)];
|
||
return _wcsdup (GetSuitableLocaleResources (res).c_str ());
|
||
}
|
||
}
|
||
LPWSTR GetPriStringResource (PCSPRIFILE pFilePri, LPCWSTR lpswUri) { return GetPriResource (pFilePri, lpswUri); }
|
||
LPWSTR GetPriPathResource (PCSPRIFILE pFilePri, LPCWSTR lpswFilePath) { return GetPriResource (pFilePri, lpswFilePath); }
|
||
#endif |