fix: fix issues

- restore some CKGlobals behavior because it will cause runtime exception.
- move some classes from CmdHelper to UnvirtContext to make CmdHelper more common to use.
- output warning string when fail to get utf8 or ordinary string.
This commit is contained in:
yyc12345 2024-08-27 11:25:53 +08:00
parent 3735a202f3
commit 65861143bf
14 changed files with 91 additions and 70 deletions

View File

@ -281,7 +281,7 @@ namespace LibCmo::CK2 {
#pragma region Encoding utilities #pragma region Encoding utilities
void CKContext::GetUTF8String(const std::string& native_name, XContainer::XString& u8_name) { bool CKContext::GetUTF8String(const std::string& native_name, XContainer::XString& u8_name) {
bool conv_success = false, has_valid_token = false; bool conv_success = false, has_valid_token = false;
for (const auto& token : this->m_NameEncoding) { for (const auto& token : this->m_NameEncoding) {
if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue; if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue;
@ -298,9 +298,11 @@ namespace LibCmo::CK2 {
this->OutputToConsole(u8"Error when converting to UTF8 string from ordinary string. The string will leave to blank."); this->OutputToConsole(u8"Error when converting to UTF8 string from ordinary string. The string will leave to blank.");
} }
} }
// return value
return conv_success;
} }
void CKContext::GetOrdinaryString(const XContainer::XString& u8_name, std::string& native_name) { bool CKContext::GetOrdinaryString(const XContainer::XString& u8_name, std::string& native_name) {
bool conv_success = false, has_valid_token = false; bool conv_success = false, has_valid_token = false;
for (const auto& token : this->m_NameEncoding) { for (const auto& token : this->m_NameEncoding) {
if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue; if (token == EncodingHelper::INVALID_ENCODING_TOKEN) continue;
@ -317,6 +319,8 @@ namespace LibCmo::CK2 {
this->OutputToConsole(u8"Error when converting to ordinary string from UTF8 string. The string will leave to blank."); this->OutputToConsole(u8"Error when converting to ordinary string from UTF8 string. The string will leave to blank.");
} }
} }
// return value
return conv_success;
} }
void CKContext::SetEncoding(const XContainer::XArray<XContainer::XString>& encoding_seq) { void CKContext::SetEncoding(const XContainer::XArray<XContainer::XString>& encoding_seq) {

View File

@ -104,6 +104,7 @@ namespace LibCmo::CK2 {
* @brief Convert given ordinary string to UTF8 string. * @brief Convert given ordinary string to UTF8 string.
* @param[in] native_name The input ordinary string. * @param[in] native_name The input ordinary string.
* @param[out] u8_name The output UTF8 string. * @param[out] u8_name The output UTF8 string.
* @return True if convertion is success, otherwise false.
* @exception RuntimeException Raised when perform this operation with a blank encoding sequence. * @exception RuntimeException Raised when perform this operation with a blank encoding sequence.
* @remarks * @remarks
* The encoding of ordinary is specified by encoding sequence. * The encoding of ordinary is specified by encoding sequence.
@ -111,11 +112,12 @@ namespace LibCmo::CK2 {
* However, if you use this function with blank encoding sequence, it will raise exception. * However, if you use this function with blank encoding sequence, it will raise exception.
* So becore using this function, please make sure that you have checked by calling IsValidEncoding(). * So becore using this function, please make sure that you have checked by calling IsValidEncoding().
*/ */
void GetUTF8String(const std::string& native_name, XContainer::XString& u8_name); bool GetUTF8String(const std::string& native_name, XContainer::XString& u8_name);
/** /**
* @brief Convert given UTF8 string to ordinary string. * @brief Convert given UTF8 string to ordinary string.
* @param[in] u8_name The input UTF8 string. * @param[in] u8_name The input UTF8 string.
* @param[out] native_name The output ordinary string. * @param[out] native_name The output ordinary string.
* @return True if convertion is success, otherwise false.
* @exception RuntimeException Raised when perform this operation with a blank encoding sequence. * @exception RuntimeException Raised when perform this operation with a blank encoding sequence.
* @remarks * @remarks
* The encoding of ordinary is specified by encoding sequence. * The encoding of ordinary is specified by encoding sequence.
@ -123,7 +125,7 @@ namespace LibCmo::CK2 {
* However, if you use this function with blank encoding sequence, it will raise exception. * However, if you use this function with blank encoding sequence, it will raise exception.
* So becore using this function, please make sure that you have checked by calling IsValidEncoding(). * So becore using this function, please make sure that you have checked by calling IsValidEncoding().
*/ */
void GetOrdinaryString(const XContainer::XString& u8_name, std::string& native_name); bool GetOrdinaryString(const XContainer::XString& u8_name, std::string& native_name);
/** /**
* @brief Set the encoding sequence. * @brief Set the encoding sequence.
* @param[in] encoding_series The encoding name in this sequence. * @param[in] encoding_series The encoding name in this sequence.

View File

@ -133,7 +133,8 @@ namespace LibCmo::CK2 {
if (namelen != 0) { if (namelen != 0) {
name_conv.resize(namelen); name_conv.resize(namelen);
parser->Read(name_conv.data(), namelen); parser->Read(name_conv.data(), namelen);
m_Ctx->GetUTF8String(name_conv, fileobj.Name); if (!m_Ctx->GetUTF8String(name_conv, fileobj.Name))
m_Ctx->OutputToConsole(u8"Fail to get UTF8 name for CKObject when reading file header. Some objects name will leave to blank.");
} else { } else {
XContainer::NSXString::FromCKSTRING(fileobj.Name, nullptr); XContainer::NSXString::FromCKSTRING(fileobj.Name, nullptr);
} }
@ -311,7 +312,8 @@ namespace LibCmo::CK2 {
// read filename // read filename
if (filenamelen != 0) { if (filenamelen != 0) {
parser->Read(name_conv.data(), filenamelen); parser->Read(name_conv.data(), filenamelen);
m_Ctx->GetUTF8String(name_conv, file); if (!m_Ctx->GetUTF8String(name_conv, file))
m_Ctx->OutputToConsole(u8"Fail to get UTF8 name for included file when reading file body. Some included files may be stripped.");
} }
// read file body length // read file body length

View File

@ -91,7 +91,8 @@ namespace LibCmo::CK2 {
sumHdrObjSize += 4 * CKSizeof(CKDWORD); sumHdrObjSize += 4 * CKSizeof(CKDWORD);
if (XContainer::NSXString::ToCKSTRING(obj.Name) != nullptr) { if (XContainer::NSXString::ToCKSTRING(obj.Name) != nullptr) {
// += Name size // += Name size
m_Ctx->GetOrdinaryString(obj.Name, name_conv); if (!m_Ctx->GetOrdinaryString(obj.Name, name_conv))
m_Ctx->OutputToConsole(u8"Fail to get ordinary string for CKObject name when computing the size of saved file. It may cause application crash or saved file has blank object name.");
sumHdrObjSize += static_cast<CKDWORD>(name_conv.size()); sumHdrObjSize += static_cast<CKDWORD>(name_conv.size());
} }
@ -178,7 +179,8 @@ namespace LibCmo::CK2 {
if (XContainer::NSXString::ToCKSTRING(obj.Name) != nullptr) { if (XContainer::NSXString::ToCKSTRING(obj.Name) != nullptr) {
// if have name, write it // if have name, write it
m_Ctx->GetOrdinaryString(obj.Name, name_conv); if (!m_Ctx->GetOrdinaryString(obj.Name, name_conv))
m_Ctx->OutputToConsole(u8"Fail to get ordinary string for CKObject name when saving file. Some objects may be saved with blank name.");
CKDWORD namelen = static_cast<CKDWORD>(name_conv.size()); CKDWORD namelen = static_cast<CKDWORD>(name_conv.size());
hdrparser->Write(&namelen); hdrparser->Write(&namelen);
hdrparser->Write(name_conv.data(), namelen); hdrparser->Write(name_conv.data(), namelen);
@ -318,7 +320,8 @@ namespace LibCmo::CK2 {
m_Ctx->GetPathManager()->GetFileName(filename); m_Ctx->GetPathManager()->GetFileName(filename);
// write filename // write filename
m_Ctx->GetOrdinaryString(filename, name_conv); if (!m_Ctx->GetOrdinaryString(filename, name_conv))
m_Ctx->OutputToConsole(u8"Fail to get ordinary string for included file when saving file. Some included files may not be saved correctly.");
CKDWORD filenamelen = static_cast<CKDWORD>(name_conv.size()); CKDWORD filenamelen = static_cast<CKDWORD>(name_conv.size());
std::fwrite(&filenamelen, sizeof(CKDWORD), 1, fs); std::fwrite(&filenamelen, sizeof(CKDWORD), 1, fs);
std::fwrite(name_conv.data(), sizeof(CKBYTE), filenamelen, fs); std::fwrite(name_conv.data(), sizeof(CKBYTE), filenamelen, fs);

View File

@ -145,8 +145,7 @@ namespace LibCmo::CK2 {
void CKClassNeedNotificationFrom(CK_CLASSID listener, CK_CLASSID listenTo) { void CKClassNeedNotificationFrom(CK_CLASSID listener, CK_CLASSID listenTo) {
size_t idxListener, idxListenTo; size_t idxListener, idxListenTo;
if (!GetClassIdIndex(listener, idxListener) || !GetClassIdIndex(listenTo, idxListenTo)) if (!GetClassIdIndex(listener, idxListener) || !GetClassIdIndex(listenTo, idxListenTo)) return;
throw LogicException("Invalid CK_CLASSID in argument.");
XContainer::NSXBitArray::Set(g_CKClassInfo[idxListener].ToBeNotify, static_cast<CKDWORD>(idxListenTo)); XContainer::NSXBitArray::Set(g_CKClassInfo[idxListener].ToBeNotify, static_cast<CKDWORD>(idxListenTo));
} }
@ -191,25 +190,25 @@ namespace LibCmo::CK2 {
const CKClassDesc* CKGetClassDesc(CK_CLASSID cid) { const CKClassDesc* CKGetClassDesc(CK_CLASSID cid) {
size_t intcid; size_t intcid;
if (!GetClassIdIndex(cid, intcid)) if (!GetClassIdIndex(cid, intcid)) return nullptr;
throw LogicException("Invalid CK_CLASSID.");
return &g_CKClassInfo[intcid]; return &g_CKClassInfo[intcid];
} }
CKSTRING CKClassIDToString(CK_CLASSID cid) { CKSTRING CKClassIDToString(CK_CLASSID cid) {
const CKClassDesc* desc = CKGetClassDesc(cid); const CKClassDesc* desc = CKGetClassDesc(cid);
if (desc == nullptr) return u8"Undefined Type";
return desc->NameFct(); return desc->NameFct();
} }
bool CKIsChildClassOf(CK_CLASSID child, CK_CLASSID parent) { bool CKIsChildClassOf(CK_CLASSID child, CK_CLASSID parent) {
size_t intchild, intparent; size_t intchild, intparent;
if (!GetClassIdIndex(child, intchild) || !GetClassIdIndex(parent, intparent)) if (!GetClassIdIndex(child, intchild) || !GetClassIdIndex(parent, intparent)) return false;
throw LogicException("Invalid CK_CLASSID.");
return g_CKClassInfo[intchild].Parents[intparent]; return g_CKClassInfo[intchild].Parents[intparent];
} }
CK_CLASSID CKGetParentClassID(CK_CLASSID child) { CK_CLASSID CKGetParentClassID(CK_CLASSID child) {
const CKClassDesc* desc = CKGetClassDesc(child); const CKClassDesc* desc = CKGetClassDesc(child);
if (desc == nullptr) return CK_CLASSID::CKCID_OBJECT;
return desc->Parent; return desc->Parent;
} }
@ -228,6 +227,7 @@ namespace LibCmo::CK2 {
bool CKIsNeedNotify(CK_CLASSID listener, CK_CLASSID deletedObjCid) { bool CKIsNeedNotify(CK_CLASSID listener, CK_CLASSID deletedObjCid) {
const CKClassDesc* desc = CKGetClassDesc(listener); const CKClassDesc* desc = CKGetClassDesc(listener);
if (desc == nullptr) return false;
return XContainer::NSXBitArray::IsSet(desc->CommonToBeNotify, static_cast<CKDWORD>(deletedObjCid)); return XContainer::NSXBitArray::IsSet(desc->CommonToBeNotify, static_cast<CKDWORD>(deletedObjCid));
} }
@ -238,6 +238,8 @@ namespace LibCmo::CK2 {
if (!XContainer::NSXBitArray::IsSet(delObjCids, static_cast<CKDWORD>(i))) continue; if (!XContainer::NSXBitArray::IsSet(delObjCids, static_cast<CKDWORD>(i))) continue;
const CKClassDesc* desc = CKGetClassDesc(static_cast<CK_CLASSID>(i)); const CKClassDesc* desc = CKGetClassDesc(static_cast<CK_CLASSID>(i));
if (desc == nullptr) continue;
XContainer::NSXBitArray::Or(result, desc->ToNotify); XContainer::NSXBitArray::Or(result, desc->ToNotify);
} }

View File

@ -155,7 +155,7 @@ namespace LibCmo::CK2 {
* @brief Order that first class id will be notified when deleting object whose class id is second argument * @brief Order that first class id will be notified when deleting object whose class id is second argument
* @param[in] listener The id of class will be notified. * @param[in] listener The id of class will be notified.
* @param[in] listenTo The id of class which first argument interested in. * @param[in] listenTo The id of class which first argument interested in.
* @exception LogicException Raised if given CK_CLASSID is invalid. * @remarks If one of given class ids is invalid, this function simply return and do nothing.
*/ */
void CKClassNeedNotificationFrom(CK_CLASSID listener, CK_CLASSID listenTo); void CKClassNeedNotificationFrom(CK_CLASSID listener, CK_CLASSID listenTo);
/** /**
@ -188,15 +188,15 @@ namespace LibCmo::CK2 {
* @brief Get the class description struct by given class id. * @brief Get the class description struct by given class id.
* @param[in] cid Class id for fetching. * @param[in] cid Class id for fetching.
* @return The pointer to corresponding class description. * @return The pointer to corresponding class description.
* We guaranteen that this pointer must not be nullptr. * If given class id is invalid, this function will return nullptr.
* @exception LogicException Raised if given CK_CLASSID is invalid. * According to this, caller can utilize this function to validate class id.
*/ */
const CKClassDesc* CKGetClassDesc(CK_CLASSID cid); const CKClassDesc* CKGetClassDesc(CK_CLASSID cid);
/** /**
* @brief Get the name representation of given class id. * @brief Get the name representation of given class id.
* @param[in] cid Class id for fetching. * @param[in] cid Class id for fetching.
* @return The name of given class id. * @return The name of given class id.
* @exception LogicException Raised if given CK_CLASSID is invalid. * If given class id is invalid, it return a predefined name.
*/ */
CKSTRING CKClassIDToString(CK_CLASSID cid); CKSTRING CKClassIDToString(CK_CLASSID cid);
@ -205,14 +205,14 @@ namespace LibCmo::CK2 {
* @param[in] child The id of first class assumed as child class. * @param[in] child The id of first class assumed as child class.
* @param[in] parent The id of second class assumed as parent class. * @param[in] parent The id of second class assumed as parent class.
* @return True if relation is satisfied, otherwise false. * @return True if relation is satisfied, otherwise false.
* @exception LogicException Raised if given CK_CLASSID is invalid. * If one of given class ids is invalid, this function always return false.
*/ */
bool CKIsChildClassOf(CK_CLASSID child, CK_CLASSID parent); bool CKIsChildClassOf(CK_CLASSID child, CK_CLASSID parent);
/** /**
* @brief Get the parent class id of given class id. * @brief Get the parent class id of given class id.
* @param[in] child The id to class which need to find parent class. * @param[in] child The id to class which need to find parent class.
* @return The parent class id. * @return The parent class id.
* @exception LogicException Raised if given CK_CLASSID is invalid. * If given class id is invalid, this function always return the class id of CKObject.
*/ */
CK_CLASSID CKGetParentClassID(CK_CLASSID child); CK_CLASSID CKGetParentClassID(CK_CLASSID child);
/** /**
@ -220,7 +220,6 @@ namespace LibCmo::CK2 {
* @param[in] cid1 The id of first class finding common parent. * @param[in] cid1 The id of first class finding common parent.
* @param[in] cid2 The id of second class finding common parent. * @param[in] cid2 The id of second class finding common parent.
* @return The cloest common parent class id. * @return The cloest common parent class id.
* @exception LogicException Raised if given CK_CLASSID is invalid.
*/ */
CK_CLASSID CKGetCommonParent(CK_CLASSID cid1, CK_CLASSID cid2); CK_CLASSID CKGetCommonParent(CK_CLASSID cid1, CK_CLASSID cid2);
@ -229,14 +228,13 @@ namespace LibCmo::CK2 {
* @param[in] listener The class id of checking whether need to be notified. * @param[in] listener The class id of checking whether need to be notified.
* @param[in] deletedObjCid The class id of deleting object. * @param[in] deletedObjCid The class id of deleting object.
* @return True if it need to be notified, otherwise false. * @return True if it need to be notified, otherwise false.
* @exception LogicException Raised if given CK_CLASSID is invalid. * If the class id of checking is invalid, this function always return false.
*/ */
bool CKIsNeedNotify(CK_CLASSID listener, CK_CLASSID deletedObjCid); /** bool CKIsNeedNotify(CK_CLASSID listener, CK_CLASSID deletedObjCid); /**
/** /**
* @brief Get all class ids need to be notified when objects whose class id included in \c delObjCids are deleting. * @brief Get all class ids need to be notified when objects whose class id included in \c delObjCids are deleting.
* @param[in] delObjCids The bit array representing class ids which need to be queried. * @param[in] delObjCids The bit array representing class ids which need to be queried.
* @return The queried bit array representing class ids need to be notified. * @return The queried bit array representing class ids need to be notified.
* @exception LogicException Raised if given CK_CLASSID is invalid.
* @see CKIsNeedNotify() * @see CKIsNeedNotify()
*/ */
XContainer::XBitArray CKGetAllNotifyClassID(const XContainer::XBitArray& delObjCids); XContainer::XBitArray CKGetAllNotifyClassID(const XContainer::XBitArray& delObjCids);

View File

@ -148,7 +148,13 @@ namespace LibCmo::CK2 {
} }
// convert encoding // convert encoding
m_BindContext->GetUTF8String(cache, *strl); if (!m_BindContext->GetUTF8String(cache, *strl)) {
m_BindContext->OutputToConsole(u8"Fail to get UTF8 string when reading CKStateChunk. Some objects may be loaded incorrectly.");
strl->clear();
return false;
}
// okey
return true; return true;
} }

View File

@ -138,7 +138,8 @@ namespace LibCmo::CK2 {
// convert encoding // convert encoding
std::string cache; std::string cache;
m_BindContext->GetOrdinaryString(*strl, cache); if (!m_BindContext->GetOrdinaryString(*strl, cache))
m_BindContext->OutputToConsole(u8"Fail to get ordinary string when saving CKStateChunk. Some objects may be saved incorrectly.");
if (cache.empty()) { if (cache.empty()) {
// write zero string // write zero string

View File

@ -20,6 +20,8 @@ namespace LibCmo::CK2::MgrImpls {
// get description first // get description first
const CKClassDesc* desc = CKGetClassDesc(cls); const CKClassDesc* desc = CKGetClassDesc(cls);
// if no description, return directly to reject creating object.
if (desc == nullptr) return nullptr;
// allocate a CK_ID first // allocate a CK_ID first
CKDWORD decided_off; CKDWORD decided_off;
@ -60,7 +62,9 @@ namespace LibCmo::CK2::MgrImpls {
void CKObjectManager::InternalDestroy(ObjImpls::CKObject* obj) { void CKObjectManager::InternalDestroy(ObjImpls::CKObject* obj) {
// find desc by classid // find desc by classid
const CKClassDesc* desc = CKGetClassDesc(obj->GetClassID()); const CKClassDesc* desc = CKGetClassDesc(obj->GetClassID());
// a create CKObject instance definitely can find corresponding desc.
// if not, throw exception.
if (desc == nullptr) throw LogicException("Invalid CK_CLASSID");
// free it // free it
desc->ReleaseFct(m_Context, obj); desc->ReleaseFct(m_Context, obj);
} }

View File

@ -187,7 +187,8 @@ namespace LibCmo::CK2::ObjImpls {
props.m_ReaderGuid.d1 = realprops.m_ReaderGuid.d1; props.m_ReaderGuid.d1 = realprops.m_ReaderGuid.d1;
props.m_ReaderGuid.d2 = realprops.m_ReaderGuid.d2; props.m_ReaderGuid.d2 = realprops.m_ReaderGuid.d2;
std::string ext; std::string ext;
m_Context->GetOrdinaryString(realprops.m_Ext.GetExt(), ext); if (!m_Context->GetOrdinaryString(realprops.m_Ext.GetExt(), ext))
m_Context->OutputToConsole(u8"Fail to get ordinary string for the extension of bitmap properties when saving CKTexture. Some textures may be saved with blank extension.");
std::memcpy( std::memcpy(
props.m_Ext.m_Data, props.m_Ext.m_Data,
ext.c_str(), ext.c_str(),
@ -314,7 +315,8 @@ namespace LibCmo::CK2::ObjImpls {
// get utf8 extension // get utf8 extension
XContainer::XString ext; XContainer::XString ext;
m_Context->GetUTF8String(props->m_Ext.m_Data, ext); if (!m_Context->GetUTF8String(props->m_Ext.m_Data, ext))
m_Context->OutputToConsole(u8"Fail to get UTF8 extension when loading CKTexture. Some textures may have blank extension in bitmap properties.");
// get my bitmap prop // get my bitmap prop
CKBitmapProperties myprops( CKBitmapProperties myprops(

View File

@ -522,6 +522,11 @@ if (!this->IsRootNode()) { \
#pragma region String Argument #pragma region String Argument
StringArgument::StringArgument(const std::u8string_view& argname, Constraint_t constraint) :
AbstractArgument(argname), m_Constraint(constraint) {}
StringArgument::~StringArgument() {}
bool StringArgument::BeginConsume(const std::u8string& cur_cmd, ArgumentsMap& am) { bool StringArgument::BeginConsume(const std::u8string& cur_cmd, ArgumentsMap& am) {
// check constraint // check constraint
if (m_Constraint.IsValid() && !m_Constraint.m_CheckFct(cur_cmd)) if (m_Constraint.IsValid() && !m_Constraint.m_CheckFct(cur_cmd))
@ -531,23 +536,6 @@ if (!this->IsRootNode()) { \
return true; return true;
} }
#pragma endregion
#pragma region Encoding List Argument
bool EncodingListArgument::BeginConsume(const std::u8string& cur_cmd, ArgumentsMap& am) {
// split given argument
std::vector<std::u8string> encs = YYCC::StringHelper::Split(cur_cmd, u8",");
// check each parts is a valid encoding name
for (const auto& item : encs) {
if (!LibCmo::EncodingHelper::IsValidEncodingName(item))
return false;
}
// okey, add into map
am.Add<ArgValue_t>(m_ArgumentName, encs);
return true;
}
#pragma endregion #pragma endregion
} }

View File

@ -498,9 +498,8 @@ namespace Unvirt::CmdHelper {
using ArgValue_t = AMItems::StringItem; using ArgValue_t = AMItems::StringItem;
using Constraint_t = YYCC::Constraints::Constraint<std::u8string>; using Constraint_t = YYCC::Constraints::Constraint<std::u8string>;
public: public:
StringArgument(const std::u8string_view& argname, Constraint_t constraint = Constraint_t {}) : StringArgument(const std::u8string_view& argname, Constraint_t constraint = Constraint_t {});
AbstractArgument(argname), m_Constraint(constraint) {} virtual ~StringArgument();
virtual ~StringArgument() {}
YYCC_DEF_CLS_COPY_MOVE(StringArgument); YYCC_DEF_CLS_COPY_MOVE(StringArgument);
protected: protected:
@ -508,19 +507,6 @@ namespace Unvirt::CmdHelper {
Constraint_t m_Constraint; Constraint_t m_Constraint;
}; };
class EncodingListArgument : public AbstractArgument {
public:
using ArgValue_t = AMItems::StringArrayItem;
public:
EncodingListArgument(const std::u8string_view& argname) :
AbstractArgument(argname) {}
virtual ~EncodingListArgument() {}
YYCC_DEF_CLS_COPY_MOVE(EncodingListArgument);
protected:
virtual bool BeginConsume(const std::u8string& cur_cmd, ArgumentsMap& am) override;
};
} }
class CommandParser { class CommandParser {

View File

@ -204,7 +204,7 @@ namespace Unvirt::StructFormatter {
for (LibCmo::CKDWORD i = 0; i < slot_count; ++i) { for (LibCmo::CKDWORD i = 0; i < slot_count; ++i) {
auto desc = bd.GetImageDesc(i); auto desc = bd.GetImageDesc(i);
Console::FormatLine(u8"#%" PRIuCKDWORD "\t%" PRIuCKDWORD "\t%" PRIuCKDWORD "\t0x%" PRIxCKDWORD " bytes\t", Console::FormatLine(u8"#%" PRIuCKDWORD "\t%" PRIuCKDWORD "\t%" PRIuCKDWORD "\t%s\t0x%" PRIxCKDWORD " bytes\t%s",
i, i,
desc->GetWidth(), desc->GetWidth(),
desc->GetHeight(), desc->GetHeight(),

View File

@ -7,7 +7,31 @@
namespace Unvirt::Context { namespace Unvirt::Context {
#pragma region Constraint Help Function #pragma region Specialized for CmdHelper
class EncodingListArgument : public CmdHelper::Nodes::AbstractArgument {
public:
using ArgValue_t = CmdHelper::AMItems::StringArrayItem;
public:
EncodingListArgument(const std::u8string_view& argname) :
AbstractArgument(argname) {}
virtual ~EncodingListArgument() {}
YYCC_DEF_CLS_COPY_MOVE(EncodingListArgument);
protected:
virtual bool BeginConsume(const std::u8string& cur_cmd, CmdHelper::ArgumentsMap& am) override {
// split given argument
std::vector<std::u8string> encs = YYCC::StringHelper::Split(cur_cmd, u8",");
// check each parts is a valid encoding name
for (const auto& item : encs) {
if (!LibCmo::EncodingHelper::IsValidEncodingName(item))
return false;
}
// okey, add into map
am.Add<ArgValue_t>(m_ArgumentName, encs);
return true;
}
};
static YYCC::Constraints::Constraint<size_t> GetOneBasedIndexConstraint() { static YYCC::Constraints::Constraint<size_t> GetOneBasedIndexConstraint() {
return YYCC::Constraints::Constraint<size_t> { return YYCC::Constraints::Constraint<size_t> {
@ -19,7 +43,6 @@ namespace Unvirt::Context {
#pragma endregion #pragma endregion
#pragma region UnvirtContext Misc #pragma region UnvirtContext Misc
UnvirtContext::UnvirtContext() : UnvirtContext::UnvirtContext() :
@ -136,7 +159,7 @@ namespace Unvirt::Context {
) )
) )
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"encoding") .Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"encoding")
.Then<CmdHelper::Nodes::EncodingListArgument>(CmdHelper::Nodes::EncodingListArgument(u8"enc") .Then<EncodingListArgument>(EncodingListArgument(u8"enc")
.Comment(u8"CKContext used encoding splitted by ','. Support mutiple encoding.") .Comment(u8"CKContext used encoding splitted by ','. Support mutiple encoding.")
.Executes( .Executes(
std::bind(&UnvirtContext::ProcEncoding, this, std::placeholders::_1), std::bind(&UnvirtContext::ProcEncoding, this, std::placeholders::_1),
@ -644,7 +667,7 @@ namespace Unvirt::Context {
} }
void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap& amap) { void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap& amap) {
const auto& encodings = amap.Get<CmdHelper::Nodes::EncodingListArgument::ArgValue_t>(u8"enc").Get(); const auto& encodings = amap.Get<EncodingListArgument::ArgValue_t>(u8"enc").Get();
m_Ctx->SetEncoding(encodings); m_Ctx->SetEncoding(encodings);
} }