/* ******************************************************************************* * Copyright (C) 2012, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************* * dictionarydata.h * * created on: 2012may31 * created by: Markus W. Scherer & Maxime Serrano */ #include "dictionarydata.h" #include "unicode/ucharstrie.h" #include "unicode/bytestrie.h" #include "unicode/udata.h" #include "cmemory.h" #if !UCONFIG_NO_BREAK_ITERATION U_NAMESPACE_BEGIN #ifndef CYGWINMSVC /* On Cygwin/MSVC, the error redefinition of symbols occurs.*/ const int32_t DictionaryData::TRIE_TYPE_BYTES; const int32_t DictionaryData::TRIE_TYPE_UCHARS; #endif DictionaryMatcher::~DictionaryMatcher() { } UCharsDictionaryMatcher::~UCharsDictionaryMatcher() { udata_close(file); } int32_t UCharsDictionaryMatcher::getType() const { return DictionaryData::TRIE_TYPE_UCHARS; } int32_t UCharsDictionaryMatcher::matches(UText *text, int32_t maxLength, int32_t *lengths, int32_t &count, int32_t limit, int32_t *values) const { UCharsTrie uct(characters); UChar32 c = utext_next32(text); if (c < 0) { return 0; } UStringTrieResult result = uct.first(c); int32_t numChars = 1; count = 0; for (;;) { if (USTRINGTRIE_HAS_VALUE(result)) { if (count < limit) { if (values != NULL) { values[count] = uct.getValue(); } lengths[count++] = numChars; } if (result == USTRINGTRIE_FINAL_VALUE) { break; } } else if (result == USTRINGTRIE_NO_MATCH) { break; } // TODO: why do we have a text limit if the UText knows its length? if (numChars >= maxLength) { break; } c = utext_next32(text); if (c < 0) { break; } ++numChars; result = uct.next(c); } return numChars; } BytesDictionaryMatcher::~BytesDictionaryMatcher() { udata_close(file); } UChar32 BytesDictionaryMatcher::transform(UChar32 c) const { if ((transformConstant & DictionaryData::TRANSFORM_TYPE_MASK) == DictionaryData::TRANSFORM_TYPE_OFFSET) { if (c == 0x200D) { return 0xFF; } else if (c == 0x200C) { return 0xFE; } int32_t delta = c - (transformConstant & DictionaryData::TRANSFORM_OFFSET_MASK); if (delta < 0 || 0xFD < delta) { return U_SENTINEL; } return (UChar32)delta; } return c; } int32_t BytesDictionaryMatcher::getType() const { return DictionaryData::TRIE_TYPE_BYTES; } int32_t BytesDictionaryMatcher::matches(UText *text, int32_t maxLength, int32_t *lengths, int32_t &count, int32_t limit, int32_t *values) const { BytesTrie bt(characters); UChar32 c = utext_next32(text); if (c < 0) { return 0; } UStringTrieResult result = bt.first(transform(c)); int32_t numChars = 1; count = 0; for (;;) { if (USTRINGTRIE_HAS_VALUE(result)) { if (count < limit) { if (values != NULL) { values[count] = bt.getValue(); } lengths[count++] = numChars; } if (result == USTRINGTRIE_FINAL_VALUE) { break; } } else if (result == USTRINGTRIE_NO_MATCH) { break; } // TODO: why do we have a text limit if the UText knows its length? if (numChars >= maxLength) { break; } c = utext_next32(text); if (c < 0) { break; } ++numChars; result = bt.next(transform(c)); } return numChars; } U_NAMESPACE_END U_NAMESPACE_USE U_CAPI int32_t U_EXPORT2 udict_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData, UErrorCode *pErrorCode) { const UDataInfo *pInfo; int32_t headerSize; const uint8_t *inBytes; uint8_t *outBytes; const int32_t *inIndexes; int32_t indexes[DictionaryData::IX_COUNT]; int32_t i, offset, size; headerSize = udata_swapDataHeader(ds, inData, length, outData, pErrorCode); if (pErrorCode == NULL || U_FAILURE(*pErrorCode)) return 0; pInfo = (const UDataInfo *)((const char *)inData + 4); if (!(pInfo->dataFormat[0] == 0x44 && pInfo->dataFormat[1] == 0x69 && pInfo->dataFormat[2] == 0x63 && pInfo->dataFormat[3] == 0x74 && pInfo->formatVersion[0] == 1)) { udata_printError(ds, "udict_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as dictionary data\n", pInfo->dataFormat[0], pInfo->dataFormat[1], pInfo->dataFormat[2], pInfo->dataFormat[3], pInfo->formatVersion[0]); *pErrorCode = U_UNSUPPORTED_ERROR; return 0; } inBytes = (const uint8_t *)inData + headerSize; outBytes = (uint8_t *)outData + headerSize; inIndexes = (const int32_t *)inBytes; if (length >= 0) { length -= headerSize; if (length < (int32_t)(sizeof(indexes))) { udata_printError(ds, "udict_swap(): too few bytes (%d after header) for dictionary data\n", length); *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR; return 0; } } for (i = 0; i < DictionaryData::IX_COUNT; i++) { indexes[i] = udata_readInt32(ds, inIndexes[i]); } size = indexes[DictionaryData::IX_TOTAL_SIZE]; if (length >= 0) { if (length < size) { udata_printError(ds, "udict_swap(): too few bytes (%d after header) for all of dictionary data\n", length); *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR; return 0; } if (inBytes != outBytes) { uprv_memcpy(outBytes, inBytes, size); } offset = 0; ds->swapArray32(ds, inBytes, sizeof(indexes), outBytes, pErrorCode); offset = (int32_t)sizeof(indexes); int32_t trieType = indexes[DictionaryData::IX_TRIE_TYPE] & DictionaryData::TRIE_TYPE_MASK; int32_t nextOffset = indexes[DictionaryData::IX_RESERVED1_OFFSET]; if (trieType == DictionaryData::TRIE_TYPE_UCHARS) { ds->swapArray16(ds, inBytes + offset, nextOffset - offset, outBytes + offset, pErrorCode); } else if (trieType == DictionaryData::TRIE_TYPE_BYTES) { // nothing to do } else { udata_printError(ds, "udict_swap(): unknown trie type!\n"); *pErrorCode = U_UNSUPPORTED_ERROR; return 0; } // these next two sections are empty in the current format, // but may be used later. offset = nextOffset; nextOffset = indexes[DictionaryData::IX_RESERVED2_OFFSET]; offset = nextOffset; nextOffset = indexes[DictionaryData::IX_TOTAL_SIZE]; offset = nextOffset; } return headerSize + size; } #endif