1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h" 18 19 #include <climits> 20 21 #include "defines.h" 22 #include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h" 23 #include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h" 24 #include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h" 25 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" 26 #include "suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h" 27 #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" 28 #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" 29 #include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h" 30 #include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" 31 #include "suggest/policyimpl/dictionary/utils/file_utils.h" 32 #include "suggest/policyimpl/dictionary/utils/format_utils.h" 33 #include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" 34 #include "utils/byte_array_view.h" 35 36 namespace latinime { 37 38 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr 39 DictionaryStructureWithBufferPolicyFactory::newPolicyForExistingDictFile( 40 const char *const path, const int bufOffset, const int size, 41 const bool isUpdatable) { 42 if (FileUtils::existsDir(path)) { 43 // Given path represents a directory. 44 return newPolicyForDirectoryDict(path, isUpdatable); 45 } else { 46 if (isUpdatable) { 47 AKLOGE("One file dictionaries don't support updating. path: %s", path); 48 ASSERT(false); 49 return nullptr; 50 } 51 return newPolicyForFileDict(path, bufOffset, size); 52 } 53 } 54 55 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr 56 DictionaryStructureWithBufferPolicyFactory:: newPolicyForOnMemoryDict( 57 const int formatVersion, const std::vector<int> &locale, 58 const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { 59 FormatUtils::FORMAT_VERSION dictFormatVersion = FormatUtils::getFormatVersion(formatVersion); 60 switch (dictFormatVersion) { 61 case FormatUtils::VERSION_4: { 62 return newPolicyForOnMemoryV4Dict<backward::v402::Ver4DictConstants, 63 backward::v402::Ver4DictBuffers, 64 backward::v402::Ver4DictBuffers::Ver4DictBuffersPtr, 65 backward::v402::Ver4PatriciaTriePolicy>( 66 dictFormatVersion, locale, attributeMap); 67 } 68 case FormatUtils::VERSION_4_ONLY_FOR_TESTING: 69 case FormatUtils::VERSION_4_DEV: { 70 return newPolicyForOnMemoryV4Dict<Ver4DictConstants, Ver4DictBuffers, 71 Ver4DictBuffers::Ver4DictBuffersPtr, Ver4PatriciaTriePolicy>( 72 dictFormatVersion, locale, attributeMap); 73 } 74 default: 75 AKLOGE("DICT: dictionary format %d is not supported for on memory dictionary", 76 formatVersion); 77 break; 78 } 79 return nullptr; 80 } 81 82 template<class DictConstants, class DictBuffers, class DictBuffersPtr, class StructurePolicy> 83 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr 84 DictionaryStructureWithBufferPolicyFactory::newPolicyForOnMemoryV4Dict( 85 const FormatUtils::FORMAT_VERSION formatVersion, 86 const std::vector<int> &locale, 87 const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { 88 HeaderPolicy headerPolicy(formatVersion, locale, attributeMap); 89 DictBuffersPtr dictBuffers = DictBuffers::createVer4DictBuffers(&headerPolicy, 90 DictConstants::MAX_DICT_EXTENDED_REGION_SIZE); 91 if (!DynamicPtWritingUtils::writeEmptyDictionary( 92 dictBuffers->getWritableTrieBuffer(), 0 /* rootPos */)) { 93 AKLOGE("Empty ver4 dictionary structure cannot be created on memory."); 94 return nullptr; 95 } 96 return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( 97 new StructurePolicy(std::move(dictBuffers))); 98 } 99 100 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr 101 DictionaryStructureWithBufferPolicyFactory::newPolicyForDirectoryDict( 102 const char *const path, const bool isUpdatable) { 103 const int headerFilePathBufSize = PATH_MAX + 1 /* terminator */; 104 char headerFilePath[headerFilePathBufSize]; 105 getHeaderFilePathInDictDir(path, headerFilePathBufSize, headerFilePath); 106 // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of 107 // MmappedBufferPtr if the instance has the responsibility. 108 MmappedBuffer::MmappedBufferPtr mmappedBuffer = 109 MmappedBuffer::openBuffer(headerFilePath, isUpdatable); 110 if (!mmappedBuffer) { 111 return nullptr; 112 } 113 const FormatUtils::FORMAT_VERSION formatVersion = FormatUtils::detectFormatVersion( 114 mmappedBuffer->getReadOnlyByteArrayView().data(), 115 mmappedBuffer->getReadOnlyByteArrayView().size()); 116 switch (formatVersion) { 117 case FormatUtils::VERSION_2: 118 AKLOGE("Given path is a directory but the format is version 2. path: %s", path); 119 break; 120 case FormatUtils::VERSION_4: { 121 return newPolicyForV4Dict<backward::v402::Ver4DictConstants, 122 backward::v402::Ver4DictBuffers, 123 backward::v402::Ver4DictBuffers::Ver4DictBuffersPtr, 124 backward::v402::Ver4PatriciaTriePolicy>( 125 headerFilePath, formatVersion, std::move(mmappedBuffer)); 126 } 127 case FormatUtils::VERSION_4_ONLY_FOR_TESTING: 128 case FormatUtils::VERSION_4_DEV: { 129 return newPolicyForV4Dict<Ver4DictConstants, Ver4DictBuffers, 130 Ver4DictBuffers::Ver4DictBuffersPtr, Ver4PatriciaTriePolicy>( 131 headerFilePath, formatVersion, std::move(mmappedBuffer)); 132 } 133 default: 134 AKLOGE("DICT: dictionary format is unknown, bad magic number. path: %s", path); 135 break; 136 } 137 ASSERT(false); 138 return nullptr; 139 } 140 141 template<class DictConstants, class DictBuffers, class DictBuffersPtr, class StructurePolicy> 142 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr 143 DictionaryStructureWithBufferPolicyFactory::newPolicyForV4Dict( 144 const char *const headerFilePath, const FormatUtils::FORMAT_VERSION formatVersion, 145 MmappedBuffer::MmappedBufferPtr &&mmappedBuffer) { 146 const int dictDirPathBufSize = strlen(headerFilePath) + 1 /* terminator */; 147 char dictPath[dictDirPathBufSize]; 148 if (!FileUtils::getFilePathWithoutSuffix(headerFilePath, 149 DictConstants::HEADER_FILE_EXTENSION, dictDirPathBufSize, dictPath)) { 150 AKLOGE("Dictionary file name is not valid as a ver4 dictionary. header path: %s", 151 headerFilePath); 152 ASSERT(false); 153 return nullptr; 154 } 155 DictBuffersPtr dictBuffers = 156 DictBuffers::openVer4DictBuffers(dictPath, std::move(mmappedBuffer), formatVersion); 157 if (!dictBuffers || !dictBuffers->isValid()) { 158 AKLOGE("DICT: The dictionary doesn't satisfy ver4 format requirements. path: %s", 159 dictPath); 160 ASSERT(false); 161 return nullptr; 162 } 163 return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( 164 new StructurePolicy(std::move(dictBuffers))); 165 } 166 167 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr 168 DictionaryStructureWithBufferPolicyFactory::newPolicyForFileDict( 169 const char *const path, const int bufOffset, const int size) { 170 // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of 171 // MmappedBufferPtr if the instance has the responsibility. 172 MmappedBuffer::MmappedBufferPtr mmappedBuffer( 173 MmappedBuffer::openBuffer(path, bufOffset, size, false /* isUpdatable */)); 174 if (!mmappedBuffer) { 175 return nullptr; 176 } 177 switch (FormatUtils::detectFormatVersion(mmappedBuffer->getReadOnlyByteArrayView().data(), 178 mmappedBuffer->getReadOnlyByteArrayView().size())) { 179 case FormatUtils::VERSION_2: 180 return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( 181 new PatriciaTriePolicy(std::move(mmappedBuffer))); 182 case FormatUtils::VERSION_4_ONLY_FOR_TESTING: 183 case FormatUtils::VERSION_4: 184 case FormatUtils::VERSION_4_DEV: 185 AKLOGE("Given path is a file but the format is version 4. path: %s", path); 186 break; 187 default: 188 AKLOGE("DICT: dictionary format is unknown, bad magic number. path: %s", path); 189 break; 190 } 191 ASSERT(false); 192 return nullptr; 193 } 194 195 /* static */ void DictionaryStructureWithBufferPolicyFactory::getHeaderFilePathInDictDir( 196 const char *const dictDirPath, const int outHeaderFileBufSize, 197 char *const outHeaderFilePath) { 198 const int dictNameBufSize = strlen(dictDirPath) + 1 /* terminator */; 199 char dictName[dictNameBufSize]; 200 FileUtils::getBasename(dictDirPath, dictNameBufSize, dictName); 201 snprintf(outHeaderFilePath, outHeaderFileBufSize, "%s/%s%s", dictDirPath, 202 dictName, Ver4DictConstants::HEADER_FILE_EXTENSION); 203 } 204 205 } // namespace latinime 206