ICU-20293 Adds common base class to implement C API validation methods.

This commit is contained in:
Shane Carr 2018-12-03 23:32:13 -08:00 committed by Shane F. Carr
parent e1e5f363a0
commit cd4644c4a0
8 changed files with 113 additions and 133 deletions

View file

@ -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<typename CType, typename CPPType, int32_t kMagic>
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<typename CType, typename CPPType, int32_t kMagic>
const CPPType*
IcuCApiHelper<CType, CPPType, kMagic>::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<const CPPType*>(input);
if (impl->fMagic != kMagic) {
status = U_INVALID_FORMAT_ERROR;
return nullptr;
}
return impl;
}
template<typename CType, typename CPPType, int32_t kMagic>
CPPType*
IcuCApiHelper<CType, CPPType, kMagic>::validate(CType* input, UErrorCode& status) {
auto* constInput = static_cast<const CType*>(input);
auto* validated = validate(constInput, status);
return const_cast<CPPType*>(validated);
}
template<typename CType, typename CPPType, int32_t kMagic>
CType*
IcuCApiHelper<CType, CPPType, kMagic>::exportForC() {
return reinterpret_cast<CType*>(static_cast<CPPType*>(this));
}
template<typename CType, typename CPPType, int32_t kMagic>
IcuCApiHelper<CType, CPPType, kMagic>::~IcuCApiHelper() {
// head off application errors by preventing use of of deleted objects.
fMagic = 0;
}
U_NAMESPACE_END
#endif // __CAPI_HELPER_H__

View file

@ -444,6 +444,7 @@
<ClInclude Include="ustr_cnv.h" />
<ClInclude Include="ustr_imp.h" />
<ClInclude Include="static_unicode_sets.h" />
<ClInclude Include="capi_helper.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="common.rc" />

View file

@ -948,6 +948,9 @@
<ClInclude Include="static_unicode_sets.h">
<Filter>formatting</Filter>
</ClInclude>
<CustomBuild Include="capi_helper.h">
<Filter>data &amp; memory</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="common.rc">

View file

@ -570,6 +570,7 @@
<ClInclude Include="ustr_cnv.h" />
<ClInclude Include="ustr_imp.h" />
<ClInclude Include="static_unicode_sets.h" />
<ClInclude Include="capi_helper.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="common.rc" />

View file

@ -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<const UNumberFormatter*>(input);
auto* validated = validate(constInput, status);
return const_cast<UNumberFormatterData*>(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<const UNumberFormatterData*>(input);
if (impl->fMagic != UNumberFormatterData::kMagic) {
status = U_INVALID_FORMAT_ERROR;
return nullptr;
}
return impl;
}
UNumberFormatter* UNumberFormatterData::exportForC() {
return reinterpret_cast<UNumberFormatter*>(this);
}
UFormattedNumberData* UFormattedNumberData::validate(UFormattedNumber* input, UErrorCode& status) {
auto* constInput = static_cast<const UFormattedNumber*>(input);
auto* validated = validate(constInput, status);
return const_cast<UFormattedNumberData*>(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<const UFormattedNumberData*>(input);
if (impl->fMagic != UFormattedNumberData::kMagic) {
status = U_INVALID_FORMAT_ERROR;
return nullptr;
}
return impl;
}
UFormattedNumber* UFormattedNumberData::exportForC() {
return reinterpret_cast<UFormattedNumber*>(this);
}
/////////////////////////////////////
/// END CAPI CONVERSION FUNCTIONS ///
/////////////////////////////////////
U_CAPI UNumberFormatter* U_EXPORT2
unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale,
UErrorCode* ec) {

View file

@ -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<UNumberFormatter, UNumberFormatterData, 0x4E465200> {
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<UFormattedNumber, UFormattedNumberData, 0x46444E00> {
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();
};

View file

@ -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<USpoofChecker*>(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<USpoofCheckResult*>(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 *>
(CheckResult::validateThis(const_cast<const USpoofCheckResult*>(ptr), status));
return validate(ptr, status);
}
void CheckResult::clear() {

View file

@ -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<USpoofChecker, SpoofImpl, USPOOF_MAGIC> {
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<USpoofCheckResult, CheckResult, USPOOF_CHECK_MAGIC> {
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.