/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "dictionary/structure/dictionary_structure_with_buffer_policy_factory.h" #include #include "defines.h" #include "dictionary/structure/backward/v402/ver4_dict_buffers.h" #include "dictionary/structure/backward/v402/ver4_dict_constants.h" #include "dictionary/structure/backward/v402/ver4_patricia_trie_policy.h" #include "dictionary/structure/pt_common/dynamic_pt_writing_utils.h" #include "dictionary/structure/v2/patricia_trie_policy.h" #include "dictionary/structure/v4/ver4_dict_buffers.h" #include "dictionary/structure/v4/ver4_dict_constants.h" #include "dictionary/structure/v4/ver4_patricia_trie_policy.h" #include "dictionary/utils/dict_file_writing_utils.h" #include "dictionary/utils/file_utils.h" #include "dictionary/utils/format_utils.h" #include "dictionary/utils/mmapped_buffer.h" #include "utils/byte_array_view.h" namespace latinime { /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr DictionaryStructureWithBufferPolicyFactory::newPolicyForExistingDictFile( const char *const path, const int bufOffset, const int size, const bool isUpdatable) { if (FileUtils::existsDir(path)) { // Given path represents a directory. return newPolicyForDirectoryDict(path, isUpdatable); } else { if (isUpdatable) { AKLOGE("One file dictionaries don't support updating. path: %s", path); ASSERT(false); return nullptr; } return newPolicyForFileDict(path, bufOffset, size); } } /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr DictionaryStructureWithBufferPolicyFactory:: newPolicyForOnMemoryDict( const int formatVersion, const std::vector &locale, const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { FormatUtils::FORMAT_VERSION dictFormatVersion = FormatUtils::getFormatVersion(formatVersion); switch (dictFormatVersion) { case FormatUtils::VERSION_402: { return newPolicyForOnMemoryV4Dict( dictFormatVersion, locale, attributeMap); } case FormatUtils::VERSION_4_ONLY_FOR_TESTING: case FormatUtils::VERSION_403: { return newPolicyForOnMemoryV4Dict( dictFormatVersion, locale, attributeMap); } default: AKLOGE("DICT: dictionary format %d is not supported for on memory dictionary", formatVersion); break; } return nullptr; } template /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr DictionaryStructureWithBufferPolicyFactory::newPolicyForOnMemoryV4Dict( const FormatUtils::FORMAT_VERSION formatVersion, const std::vector &locale, const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { HeaderPolicy headerPolicy(formatVersion, locale, attributeMap); DictBuffersPtr dictBuffers = DictBuffers::createVer4DictBuffers(&headerPolicy, DictConstants::MAX_DICT_EXTENDED_REGION_SIZE); if (!DynamicPtWritingUtils::writeEmptyDictionary( dictBuffers->getWritableTrieBuffer(), 0 /* rootPos */)) { AKLOGE("Empty ver4 dictionary structure cannot be created on memory."); return nullptr; } return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( new StructurePolicy(std::move(dictBuffers))); } /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr DictionaryStructureWithBufferPolicyFactory::newPolicyForDirectoryDict( const char *const path, const bool isUpdatable) { const int headerFilePathBufSize = PATH_MAX + 1 /* terminator */; char headerFilePath[headerFilePathBufSize]; getHeaderFilePathInDictDir(path, headerFilePathBufSize, headerFilePath); // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of // MmappedBufferPtr if the instance has the responsibility. MmappedBuffer::MmappedBufferPtr mmappedBuffer = MmappedBuffer::openBuffer(headerFilePath, isUpdatable); if (!mmappedBuffer) { return nullptr; } const FormatUtils::FORMAT_VERSION formatVersion = FormatUtils::detectFormatVersion( mmappedBuffer->getReadOnlyByteArrayView()); switch (formatVersion) { case FormatUtils::VERSION_2: case FormatUtils::VERSION_201: case FormatUtils::VERSION_202: AKLOGE("Given path is a directory but the format is version 2xx. path: %s", path); break; case FormatUtils::VERSION_402: { return newPolicyForV4Dict( headerFilePath, formatVersion, std::move(mmappedBuffer)); } case FormatUtils::VERSION_4_ONLY_FOR_TESTING: case FormatUtils::VERSION_403: { return newPolicyForV4Dict( headerFilePath, formatVersion, std::move(mmappedBuffer)); } default: AKLOGE("DICT: dictionary format is unknown, bad magic number. path: %s", path); break; } ASSERT(false); return nullptr; } template /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr DictionaryStructureWithBufferPolicyFactory::newPolicyForV4Dict( const char *const headerFilePath, const FormatUtils::FORMAT_VERSION formatVersion, MmappedBuffer::MmappedBufferPtr &&mmappedBuffer) { const int dictDirPathBufSize = strlen(headerFilePath) + 1 /* terminator */; char dictPath[dictDirPathBufSize]; if (!FileUtils::getFilePathWithoutSuffix(headerFilePath, DictConstants::HEADER_FILE_EXTENSION, dictDirPathBufSize, dictPath)) { AKLOGE("Dictionary file name is not valid as a ver4 dictionary. header path: %s", headerFilePath); ASSERT(false); return nullptr; } DictBuffersPtr dictBuffers = DictBuffers::openVer4DictBuffers(dictPath, std::move(mmappedBuffer), formatVersion); if (!dictBuffers || !dictBuffers->isValid()) { AKLOGE("DICT: The dictionary doesn't satisfy ver4 format requirements. path: %s", dictPath); ASSERT(false); return nullptr; } return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( new StructurePolicy(std::move(dictBuffers))); } /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr DictionaryStructureWithBufferPolicyFactory::newPolicyForFileDict( const char *const path, const int bufOffset, const int size) { // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of // MmappedBufferPtr if the instance has the responsibility. MmappedBuffer::MmappedBufferPtr mmappedBuffer( MmappedBuffer::openBuffer(path, bufOffset, size, false /* isUpdatable */)); if (!mmappedBuffer) { return nullptr; } switch (FormatUtils::detectFormatVersion(mmappedBuffer->getReadOnlyByteArrayView())) { case FormatUtils::VERSION_2: case FormatUtils::VERSION_201: AKLOGE("Dictionary versions 2 and 201 are incompatible with this version"); break; case FormatUtils::VERSION_202: return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( new PatriciaTriePolicy(std::move(mmappedBuffer))); case FormatUtils::VERSION_4_ONLY_FOR_TESTING: case FormatUtils::VERSION_402: case FormatUtils::VERSION_403: AKLOGE("Given path is a file but the format is version 4. path: %s", path); break; default: AKLOGE("DICT: dictionary format is unknown, bad magic number. path: %s", path); break; } ASSERT(false); return nullptr; } /* static */ void DictionaryStructureWithBufferPolicyFactory::getHeaderFilePathInDictDir( const char *const dictDirPath, const int outHeaderFileBufSize, char *const outHeaderFilePath) { const int dictNameBufSize = strlen(dictDirPath) + 1 /* terminator */; char dictName[dictNameBufSize]; FileUtils::getBasename(dictDirPath, dictNameBufSize, dictName); snprintf(outHeaderFilePath, outHeaderFileBufSize, "%s/%s%s", dictDirPath, dictName, Ver4DictConstants::HEADER_FILE_EXTENSION); } } // namespace latinime