From: Shane Carr Date: Tue, 4 Dec 2018 07:32:13 +0000 (-0800) Subject: ICU-20293 Adds common base class to implement C API validation methods. X-Git-Tag: release-64-rc~211 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cd4644c4a0c19382a0cf876aa5213ecc23ae08c7;p=icu ICU-20293 Adds common base class to implement C API validation methods. --- diff --git a/icu4c/source/common/capi_helper.h b/icu4c/source/common/capi_helper.h new file mode 100644 index 00000000000..890488211e3 --- /dev/null +++ b/icu4c/source/common/capi_helper.h @@ -0,0 +1,86 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#ifndef __CAPI_HELPER_H__ +#define __CAPI_HELPER_H__ + +#include "unicode/utypes.h" + +U_NAMESPACE_BEGIN + +/** + * An internal helper class to help convert between C and C++ APIs. + */ +template +class IcuCApiHelper { + public: + /** + * Convert from the C type to the C++ type (const version). + */ + static const CPPType* validate(const CType* input, UErrorCode& status); + + /** + * Convert from the C type to the C++ type (non-const version). + */ + static CPPType* validate(CType* input, UErrorCode& status); + + /** + * Convert from the C++ type to the C type. + */ + CType* exportForC(); + + /** + * Invalidates the object. + */ + ~IcuCApiHelper(); + + private: + /** + * While the object is valid, fMagic equals kMagic. + */ + int32_t fMagic = kMagic; +}; + + +template +const CPPType* +IcuCApiHelper::validate(const CType* input, UErrorCode& status) { + if (U_FAILURE(status)) { + return nullptr; + } + if (input == nullptr) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return nullptr; + } + auto* impl = reinterpret_cast(input); + if (impl->fMagic != kMagic) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + return impl; +} + +template +CPPType* +IcuCApiHelper::validate(CType* input, UErrorCode& status) { + auto* constInput = static_cast(input); + auto* validated = validate(constInput, status); + return const_cast(validated); +} + +template +CType* +IcuCApiHelper::exportForC() { + return reinterpret_cast(static_cast(this)); +} + +template +IcuCApiHelper::~IcuCApiHelper() { + // head off application errors by preventing use of of deleted objects. + fMagic = 0; +} + + +U_NAMESPACE_END + +#endif // __CAPI_HELPER_H__ diff --git a/icu4c/source/common/common.vcxproj b/icu4c/source/common/common.vcxproj index 399c175ac72..eb9b456ce55 100644 --- a/icu4c/source/common/common.vcxproj +++ b/icu4c/source/common/common.vcxproj @@ -444,6 +444,7 @@ + diff --git a/icu4c/source/common/common.vcxproj.filters b/icu4c/source/common/common.vcxproj.filters index 99ed94fbd70..85d0d9b5eef 100644 --- a/icu4c/source/common/common.vcxproj.filters +++ b/icu4c/source/common/common.vcxproj.filters @@ -948,6 +948,9 @@ formatting + + data & memory + diff --git a/icu4c/source/common/common_uwp.vcxproj b/icu4c/source/common/common_uwp.vcxproj index 91c538d5177..7508a949403 100644 --- a/icu4c/source/common/common_uwp.vcxproj +++ b/icu4c/source/common/common_uwp.vcxproj @@ -570,6 +570,7 @@ + diff --git a/icu4c/source/i18n/number_capi.cpp b/icu4c/source/i18n/number_capi.cpp index ca7918bc82e..d96da6816e1 100644 --- a/icu4c/source/i18n/number_capi.cpp +++ b/icu4c/source/i18n/number_capi.cpp @@ -20,69 +20,6 @@ using namespace icu::number; using namespace icu::number::impl; -////////////////////////////////// -/// C API CONVERSION FUNCTIONS /// -////////////////////////////////// - -UNumberFormatterData* UNumberFormatterData::validate(UNumberFormatter* input, UErrorCode& status) { - auto* constInput = static_cast(input); - auto* validated = validate(constInput, status); - return const_cast(validated); -} - -const UNumberFormatterData* -UNumberFormatterData::validate(const UNumberFormatter* input, UErrorCode& status) { - if (U_FAILURE(status)) { - return nullptr; - } - if (input == nullptr) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return nullptr; - } - auto* impl = reinterpret_cast(input); - if (impl->fMagic != UNumberFormatterData::kMagic) { - status = U_INVALID_FORMAT_ERROR; - return nullptr; - } - return impl; -} - -UNumberFormatter* UNumberFormatterData::exportForC() { - return reinterpret_cast(this); -} - -UFormattedNumberData* UFormattedNumberData::validate(UFormattedNumber* input, UErrorCode& status) { - auto* constInput = static_cast(input); - auto* validated = validate(constInput, status); - return const_cast(validated); -} - -const UFormattedNumberData* -UFormattedNumberData::validate(const UFormattedNumber* input, UErrorCode& status) { - if (U_FAILURE(status)) { - return nullptr; - } - if (input == nullptr) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return nullptr; - } - auto* impl = reinterpret_cast(input); - if (impl->fMagic != UFormattedNumberData::kMagic) { - status = U_INVALID_FORMAT_ERROR; - return nullptr; - } - return impl; -} - -UFormattedNumber* UFormattedNumberData::exportForC() { - return reinterpret_cast(this); -} - -///////////////////////////////////// -/// END CAPI CONVERSION FUNCTIONS /// -///////////////////////////////////// - - U_CAPI UNumberFormatter* U_EXPORT2 unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale, UErrorCode* ec) { diff --git a/icu4c/source/i18n/number_utypes.h b/icu4c/source/i18n/number_utypes.h index 48bfce19697..303f82e6a95 100644 --- a/icu4c/source/i18n/number_utypes.h +++ b/icu4c/source/i18n/number_utypes.h @@ -11,38 +11,24 @@ #include "number_types.h" #include "number_decimalquantity.h" #include "number_stringbuilder.h" +#include "capi_helper.h" U_NAMESPACE_BEGIN namespace number { namespace impl { /** - * Implementation class for UNumberFormatter with a magic number for safety. - * - * Wraps a LocalizedNumberFormatter by value. + * Implementation class for UNumberFormatter. Wraps a LocalizedNumberFormatter. */ -struct UNumberFormatterData : public UMemory { - // The magic number to identify incoming objects. - // Reads in ASCII as "NFR" (NumberFormatteR with room at the end) - static constexpr int32_t kMagic = 0x4E465200; - - // Data members: - int32_t fMagic = kMagic; +struct UNumberFormatterData : public UMemory, + // Magic number as ASCII == "NFR" (NumberFormatteR) + public IcuCApiHelper { LocalizedNumberFormatter fFormatter; - - /** Convert from UNumberFormatter -> UNumberFormatterData. */ - static UNumberFormatterData* validate(UNumberFormatter* input, UErrorCode& status); - - /** Convert from UNumberFormatter -> UNumberFormatterData (const version). */ - static const UNumberFormatterData* validate(const UNumberFormatter* input, UErrorCode& status); - - /** Convert from UNumberFormatterData -> UNumberFormatter. */ - UNumberFormatter* exportForC(); }; /** - * Implementation class for UFormattedNumber with magic number for safety. + * Implementation class for UFormattedNumber. * * This struct is also held internally by the C++ version FormattedNumber since the member types are not * declared in the public header file. @@ -50,24 +36,11 @@ struct UNumberFormatterData : public UMemory { * The DecimalQuantity is not currently being used by FormattedNumber, but at some point it could be used * to add a toDecNumber() or similar method. */ -struct UFormattedNumberData : public UMemory { - // The magic number to identify incoming objects. - // Reads in ASCII as "FDN" (FormatteDNumber with room at the end) - static constexpr int32_t kMagic = 0x46444E00; - - // Data members: - int32_t fMagic = kMagic; +struct UFormattedNumberData : public UMemory, + // Magic number as ASCII == "FDN" (FormatteDNumber) + public IcuCApiHelper { DecimalQuantity quantity; NumberStringBuilder string; - - /** Convert from UFormattedNumber -> UFormattedNumberData. */ - static UFormattedNumberData* validate(UFormattedNumber* input, UErrorCode& status); - - /** Convert from UFormattedNumber -> UFormattedNumberData (const version). */ - static const UFormattedNumberData* validate(const UFormattedNumber* input, UErrorCode& status); - - /** Convert from UFormattedNumberData -> UFormattedNumber. */ - UFormattedNumber* exportForC(); }; diff --git a/icu4c/source/i18n/uspoof_impl.cpp b/icu4c/source/i18n/uspoof_impl.cpp index 2c1f088b12d..463a2f93c6f 100644 --- a/icu4c/source/i18n/uspoof_impl.cpp +++ b/icu4c/source/i18n/uspoof_impl.cpp @@ -52,7 +52,6 @@ SpoofImpl::SpoofImpl() { } void SpoofImpl::construct(UErrorCode& status) { - fMagic = USPOOF_MAGIC; fChecks = USPOOF_ALL_CHECKS; fSpoofData = NULL; fAllowedCharsSet = NULL; @@ -74,12 +73,11 @@ void SpoofImpl::construct(UErrorCode& status) { // Copy Constructor, used by the user level clone() function. SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status) : - fMagic(0), fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) , + fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) , fAllowedLocales(NULL) { if (U_FAILURE(status)) { return; } - fMagic = src.fMagic; fChecks = src.fChecks; if (src.fSpoofData != NULL) { fSpoofData = src.fSpoofData->addReference(); @@ -93,8 +91,6 @@ SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status) : } SpoofImpl::~SpoofImpl() { - fMagic = 0; // head off application errors by preventing use of - // of deleted objects. if (fSpoofData != NULL) { fSpoofData->removeReference(); // Will delete if refCount goes to zero. } @@ -104,7 +100,7 @@ SpoofImpl::~SpoofImpl() { // Cast this instance as a USpoofChecker for the C API. USpoofChecker *SpoofImpl::asUSpoofChecker() { - return reinterpret_cast(this); + return exportForC(); } // @@ -112,18 +108,10 @@ USpoofChecker *SpoofImpl::asUSpoofChecker() { // received from the C API. // const SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) { + auto* This = validate(sc, status); if (U_FAILURE(status)) { return NULL; } - if (sc == NULL) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; - } - SpoofImpl *This = (SpoofImpl *)sc; - if (This->fMagic != USPOOF_MAGIC) { - status = U_INVALID_FORMAT_ERROR; - return NULL; - } if (This->fSpoofData != NULL && !This->fSpoofData->validateDataVersion(status)) { return NULL; } @@ -454,12 +442,12 @@ UChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorC // //----------------------------------------- -CheckResult::CheckResult() : fMagic(USPOOF_CHECK_MAGIC) { +CheckResult::CheckResult() { clear(); } USpoofCheckResult* CheckResult::asUSpoofCheckResult() { - return reinterpret_cast(this); + return exportForC(); } // @@ -467,22 +455,11 @@ USpoofCheckResult* CheckResult::asUSpoofCheckResult() { // received from the C API. // const CheckResult* CheckResult::validateThis(const USpoofCheckResult *ptr, UErrorCode &status) { - if (U_FAILURE(status)) { return NULL; } - if (ptr == NULL) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; - } - CheckResult *This = (CheckResult*) ptr; - if (This->fMagic != USPOOF_CHECK_MAGIC) { - status = U_INVALID_FORMAT_ERROR; - return NULL; - } - return This; + return validate(ptr, status); } CheckResult* CheckResult::validateThis(USpoofCheckResult *ptr, UErrorCode &status) { - return const_cast - (CheckResult::validateThis(const_cast(ptr), status)); + return validate(ptr, status); } void CheckResult::clear() { diff --git a/icu4c/source/i18n/uspoof_impl.h b/icu4c/source/i18n/uspoof_impl.h index 0eee0e58a8a..b111d4b16a9 100644 --- a/icu4c/source/i18n/uspoof_impl.h +++ b/icu4c/source/i18n/uspoof_impl.h @@ -27,6 +27,8 @@ #ifdef __cplusplus +#include "capi_helper.h" + U_NAMESPACE_BEGIN // The maximium length (in UTF-16 UChars) of the skeleton replacement string resulting from @@ -52,7 +54,8 @@ class ConfusableDataUtils; * Class SpoofImpl corresponds directly to the plain C API opaque type * USpoofChecker. One can be cast to the other. */ -class SpoofImpl : public UObject { +class SpoofImpl : public UObject, + public IcuCApiHelper { public: SpoofImpl(SpoofData *data, UErrorCode& status); SpoofImpl(UErrorCode& status); @@ -96,7 +99,6 @@ public: // Data Members // - int32_t fMagic; // Internal sanity check. int32_t fChecks; // Bit vector of checks to perform. SpoofData *fSpoofData; @@ -112,7 +114,8 @@ public: * Class CheckResult corresponds directly to the plain C API opaque type * USpoofCheckResult. One can be cast to the other. */ -class CheckResult : public UObject { +class CheckResult : public UObject, + public IcuCApiHelper { public: CheckResult(); virtual ~CheckResult(); @@ -127,7 +130,6 @@ public: int32_t toCombinedBitmask(int32_t expectedChecks); // Data Members - int32_t fMagic; // Internal sanity check. int32_t fChecks; // Bit vector of checks that were failed. UnicodeSet fNumerics; // Set of numerics found in the string. URestrictionLevel fRestrictionLevel; // The restriction level of the string.