| OLD | NEW |
| (Empty) | |
| 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 "third_party/prediction/suggest/policyimpl/dictionary/structure/v4/ver4
_dict_buffers.h" |
| 18 |
| 19 #include <cerrno> |
| 20 #include <cstring> |
| 21 #include <fcntl.h> |
| 22 #include <sys/stat.h> |
| 23 #include <sys/types.h> |
| 24 #include <vector> |
| 25 |
| 26 #include "third_party/prediction/suggest/policyimpl/dictionary/utils/byte_array_
utils.h" |
| 27 #include "third_party/prediction/suggest/policyimpl/dictionary/utils/dict_file_w
riting_utils.h" |
| 28 #include "third_party/prediction/suggest/policyimpl/dictionary/utils/file_utils.
h" |
| 29 #include "third_party/prediction/utils/byte_array_view.h" |
| 30 |
| 31 namespace latinime { |
| 32 |
| 33 /* static */ Ver4DictBuffers::Ver4DictBuffersPtr |
| 34 Ver4DictBuffers::openVer4DictBuffers( |
| 35 const char* const dictPath, |
| 36 MmappedBuffer::MmappedBufferPtr&& headerBuffer, |
| 37 const FormatUtils::FORMAT_VERSION formatVersion) { |
| 38 if (!headerBuffer) { |
| 39 ASSERT(false); |
| 40 AKLOGE("The header buffer must be valid to open ver4 dict buffers."); |
| 41 return Ver4DictBuffersPtr(nullptr); |
| 42 } |
| 43 // TODO: take only dictDirPath, and open both header and trie files in the |
| 44 // constructor below |
| 45 const bool isUpdatable = headerBuffer->isUpdatable(); |
| 46 MmappedBuffer::MmappedBufferPtr bodyBuffer = MmappedBuffer::openBuffer( |
| 47 dictPath, Ver4DictConstants::BODY_FILE_EXTENSION, isUpdatable); |
| 48 if (!bodyBuffer) { |
| 49 return Ver4DictBuffersPtr(nullptr); |
| 50 } |
| 51 std::vector<uint8_t*> buffers; |
| 52 std::vector<int> bufferSizes; |
| 53 const ReadWriteByteArrayView buffer = bodyBuffer->getReadWriteByteArrayView(); |
| 54 int position = 0; |
| 55 while (position < static_cast<int>(buffer.size())) { |
| 56 const int bufferSize = |
| 57 ByteArrayUtils::readUint32AndAdvancePosition(buffer.data(), &position); |
| 58 const ReadWriteByteArrayView subBuffer = |
| 59 buffer.subView(position, bufferSize); |
| 60 buffers.push_back(subBuffer.data()); |
| 61 bufferSizes.push_back(subBuffer.size()); |
| 62 position += bufferSize; |
| 63 if (bufferSize < 0 || position < 0 || |
| 64 position > static_cast<int>(buffer.size())) { |
| 65 AKLOGE("The dict body file is corrupted."); |
| 66 return Ver4DictBuffersPtr(nullptr); |
| 67 } |
| 68 } |
| 69 if (buffers.size() != |
| 70 Ver4DictConstants::NUM_OF_CONTENT_BUFFERS_IN_BODY_FILE) { |
| 71 AKLOGE("The dict body file is corrupted."); |
| 72 return Ver4DictBuffersPtr(nullptr); |
| 73 } |
| 74 return Ver4DictBuffersPtr( |
| 75 new Ver4DictBuffers(std::move(headerBuffer), std::move(bodyBuffer), |
| 76 formatVersion, buffers, bufferSizes)); |
| 77 } |
| 78 |
| 79 bool Ver4DictBuffers::flushHeaderAndDictBuffers( |
| 80 const char* const dictDirPath, |
| 81 const BufferWithExtendableBuffer* const headerBuffer) const { |
| 82 // Create temporary directory. |
| 83 const int tmpDirPathBufSize = FileUtils::getFilePathWithSuffixBufSize( |
| 84 dictDirPath, |
| 85 DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE); |
| 86 char tmpDirPath[tmpDirPathBufSize]; |
| 87 FileUtils::getFilePathWithSuffix( |
| 88 dictDirPath, DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE, |
| 89 tmpDirPathBufSize, tmpDirPath); |
| 90 if (FileUtils::existsDir(tmpDirPath)) { |
| 91 if (!FileUtils::removeDirAndFiles(tmpDirPath)) { |
| 92 AKLOGE("Existing directory %s cannot be removed.", tmpDirPath); |
| 93 ASSERT(false); |
| 94 return false; |
| 95 } |
| 96 } |
| 97 umask(S_IWGRP | S_IWOTH); |
| 98 if (mkdir(tmpDirPath, S_IRWXU) == -1) { |
| 99 AKLOGE("Cannot create directory: %s. errno: %d.", tmpDirPath, errno); |
| 100 return false; |
| 101 } |
| 102 // Get dictionary base path. |
| 103 const int dictNameBufSize = strlen(dictDirPath) + 1 /* terminator */; |
| 104 char dictName[dictNameBufSize]; |
| 105 FileUtils::getBasename(dictDirPath, dictNameBufSize, dictName); |
| 106 const int dictPathBufSize = |
| 107 FileUtils::getFilePathBufSize(tmpDirPath, dictName); |
| 108 char dictPath[dictPathBufSize]; |
| 109 FileUtils::getFilePath(tmpDirPath, dictName, dictPathBufSize, dictPath); |
| 110 |
| 111 // Write header file. |
| 112 if (!DictFileWritingUtils::flushBufferToFileWithSuffix( |
| 113 dictPath, Ver4DictConstants::HEADER_FILE_EXTENSION, headerBuffer)) { |
| 114 AKLOGE("Dictionary header file %s%s cannot be written.", tmpDirPath, |
| 115 Ver4DictConstants::HEADER_FILE_EXTENSION); |
| 116 return false; |
| 117 } |
| 118 |
| 119 // Write body file. |
| 120 const int bodyFilePathBufSize = FileUtils::getFilePathWithSuffixBufSize( |
| 121 dictPath, Ver4DictConstants::BODY_FILE_EXTENSION); |
| 122 char bodyFilePath[bodyFilePathBufSize]; |
| 123 FileUtils::getFilePathWithSuffix(dictPath, |
| 124 Ver4DictConstants::BODY_FILE_EXTENSION, |
| 125 bodyFilePathBufSize, bodyFilePath); |
| 126 |
| 127 const int fd = |
| 128 open(bodyFilePath, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); |
| 129 if (fd == -1) { |
| 130 AKLOGE("File %s cannot be opened. errno: %d", bodyFilePath, errno); |
| 131 ASSERT(false); |
| 132 return false; |
| 133 } |
| 134 FILE* const file = fdopen(fd, "wb"); |
| 135 if (!file) { |
| 136 AKLOGE("fdopen failed for the file %s. errno: %d", bodyFilePath, errno); |
| 137 ASSERT(false); |
| 138 return false; |
| 139 } |
| 140 |
| 141 if (!flushDictBuffers(file)) { |
| 142 fclose(file); |
| 143 return false; |
| 144 } |
| 145 fclose(file); |
| 146 // Remove existing dictionary. |
| 147 if (!FileUtils::removeDirAndFiles(dictDirPath)) { |
| 148 AKLOGE("Existing directory %s cannot be removed.", dictDirPath); |
| 149 ASSERT(false); |
| 150 return false; |
| 151 } |
| 152 // Rename temporary directory. |
| 153 if (rename(tmpDirPath, dictDirPath) != 0) { |
| 154 AKLOGE("%s cannot be renamed to %s", tmpDirPath, dictDirPath); |
| 155 ASSERT(false); |
| 156 return false; |
| 157 } |
| 158 return true; |
| 159 } |
| 160 |
| 161 bool Ver4DictBuffers::flushDictBuffers(FILE* const file) const { |
| 162 // Write trie. |
| 163 if (!DictFileWritingUtils::writeBufferToFileTail(file, |
| 164 &mExpandableTrieBuffer)) { |
| 165 AKLOGE("Trie cannot be written."); |
| 166 return false; |
| 167 } |
| 168 // Write terminal position lookup table. |
| 169 if (!mTerminalPositionLookupTable.flushToFile(file)) { |
| 170 AKLOGE("Terminal position lookup table cannot be written."); |
| 171 return false; |
| 172 } |
| 173 // Write language model content. |
| 174 if (!mLanguageModelDictContent.save(file)) { |
| 175 AKLOGE("Language model dict content cannot be written."); |
| 176 return false; |
| 177 } |
| 178 // Write bigram dict content. |
| 179 if (!mBigramDictContent.flushToFile(file)) { |
| 180 AKLOGE("Bigram dict content cannot be written."); |
| 181 return false; |
| 182 } |
| 183 // Write shortcut dict content. |
| 184 if (!mShortcutDictContent.flushToFile(file)) { |
| 185 AKLOGE("Shortcut dict content cannot be written."); |
| 186 return false; |
| 187 } |
| 188 return true; |
| 189 } |
| 190 |
| 191 Ver4DictBuffers::Ver4DictBuffers( |
| 192 MmappedBuffer::MmappedBufferPtr&& headerBuffer, |
| 193 MmappedBuffer::MmappedBufferPtr&& bodyBuffer, |
| 194 const FormatUtils::FORMAT_VERSION formatVersion, |
| 195 const std::vector<uint8_t*>& contentBuffers, |
| 196 const std::vector<int>& contentBufferSizes) |
| 197 : mHeaderBuffer(std::move(headerBuffer)), |
| 198 mDictBuffer(std::move(bodyBuffer)), |
| 199 mHeaderPolicy(mHeaderBuffer->getReadOnlyByteArrayView().data(), |
| 200 formatVersion), |
| 201 mExpandableHeaderBuffer( |
| 202 mHeaderBuffer->getReadWriteByteArrayView(), |
| 203 BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), |
| 204 mExpandableTrieBuffer( |
| 205 ReadWriteByteArrayView( |
| 206 contentBuffers[Ver4DictConstants::TRIE_BUFFER_INDEX], |
| 207 contentBufferSizes[Ver4DictConstants::TRIE_BUFFER_INDEX]), |
| 208 BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), |
| 209 mTerminalPositionLookupTable( |
| 210 contentBuffers |
| 211 [Ver4DictConstants::TERMINAL_ADDRESS_LOOKUP_TABLE_BUFFER_INDEX], |
| 212 contentBufferSizes |
| 213 [Ver4DictConstants::TERMINAL_ADDRESS_LOOKUP_TABLE_BUFFER_INDEX]), |
| 214 mLanguageModelDictContent( |
| 215 ReadWriteByteArrayView( |
| 216 contentBuffers[Ver4DictConstants::LANGUAGE_MODEL_BUFFER_INDEX], |
| 217 contentBufferSizes |
| 218 [Ver4DictConstants::LANGUAGE_MODEL_BUFFER_INDEX]), |
| 219 mHeaderPolicy.hasHistoricalInfoOfWords()), |
| 220 mBigramDictContent( |
| 221 &contentBuffers[Ver4DictConstants::BIGRAM_BUFFERS_INDEX], |
| 222 &contentBufferSizes[Ver4DictConstants::BIGRAM_BUFFERS_INDEX], |
| 223 mHeaderPolicy.hasHistoricalInfoOfWords()), |
| 224 mShortcutDictContent( |
| 225 &contentBuffers[Ver4DictConstants::SHORTCUT_BUFFERS_INDEX], |
| 226 &contentBufferSizes[Ver4DictConstants::SHORTCUT_BUFFERS_INDEX]), |
| 227 mIsUpdatable(mDictBuffer->isUpdatable()) { |
| 228 } |
| 229 |
| 230 Ver4DictBuffers::Ver4DictBuffers(const HeaderPolicy* const headerPolicy, |
| 231 const int maxTrieSize) |
| 232 : mHeaderBuffer(nullptr), |
| 233 mDictBuffer(nullptr), |
| 234 mHeaderPolicy(headerPolicy), |
| 235 mExpandableHeaderBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), |
| 236 mExpandableTrieBuffer(maxTrieSize), |
| 237 mTerminalPositionLookupTable(), |
| 238 mLanguageModelDictContent(headerPolicy->hasHistoricalInfoOfWords()), |
| 239 mBigramDictContent(headerPolicy->hasHistoricalInfoOfWords()), |
| 240 mShortcutDictContent(), |
| 241 mIsUpdatable(true) { |
| 242 } |
| 243 |
| 244 } // namespace latinime |
| OLD | NEW |