Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 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 | |
Keisuke Kuroyanagi | 88bc312 | 2014-12-17 16:02:09 +0900 | [diff] [blame^] | 17 | #include "dictionary/utils/dict_file_writing_utils.h" |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 18 | |
| 19 | #include <cstdio> |
Keisuke Kuroyanagi | ed16af7 | 2014-05-14 17:48:28 +0900 | [diff] [blame] | 20 | #include <errno.h> |
| 21 | #include <fcntl.h> |
| 22 | #include <sys/stat.h> |
| 23 | #include <sys/types.h> |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 24 | |
Keisuke Kuroyanagi | 88bc312 | 2014-12-17 16:02:09 +0900 | [diff] [blame^] | 25 | #include "dictionary/header/header_policy.h" |
| 26 | #include "dictionary/structure/backward/v402/ver4_dict_buffers.h" |
| 27 | #include "dictionary/structure/pt_common/dynamic_pt_writing_utils.h" |
| 28 | #include "dictionary/structure/v4/ver4_dict_buffers.h" |
| 29 | #include "dictionary/utils/buffer_with_extendable_buffer.h" |
| 30 | #include "dictionary/utils/entry_counters.h" |
| 31 | #include "dictionary/utils/file_utils.h" |
| 32 | #include "dictionary/utils/format_utils.h" |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 33 | #include "utils/time_keeper.h" |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 34 | |
| 35 | namespace latinime { |
| 36 | |
| 37 | const char *const DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE = ".tmp"; |
Keisuke Kuroyanagi | 2ac9342 | 2014-07-11 15:15:47 +0900 | [diff] [blame] | 38 | // Enough size to describe buffer size. |
| 39 | const int DictFileWritingUtils::SIZE_OF_BUFFER_SIZE_FIELD = 4; |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 40 | |
| 41 | /* static */ bool DictFileWritingUtils::createEmptyDictFile(const char *const filePath, |
Jean Chalard | 43cf907 | 2014-02-04 23:51:05 +0900 | [diff] [blame] | 42 | const int dictVersion, const std::vector<int> localeAsCodePointVector, |
Keisuke Kuroyanagi | fc9ca59 | 2014-02-06 17:55:45 +0900 | [diff] [blame] | 43 | const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 44 | TimeKeeper::setCurrentTime(); |
Keisuke Kuroyanagi | 455dc84 | 2014-05-09 15:17:01 +0900 | [diff] [blame] | 45 | const FormatUtils::FORMAT_VERSION formatVersion = FormatUtils::getFormatVersion(dictVersion); |
| 46 | switch (formatVersion) { |
Keisuke Kuroyanagi | ea468cc | 2014-10-30 12:54:06 +0900 | [diff] [blame] | 47 | case FormatUtils::VERSION_402: |
Keisuke Kuroyanagi | 07e1412 | 2014-06-10 19:22:40 +0900 | [diff] [blame] | 48 | return createEmptyV4DictFile<backward::v402::Ver4DictConstants, |
| 49 | backward::v402::Ver4DictBuffers, |
| 50 | backward::v402::Ver4DictBuffers::Ver4DictBuffersPtr>( |
| 51 | filePath, localeAsCodePointVector, attributeMap, formatVersion); |
Keisuke Kuroyanagi | 7116ea9 | 2014-05-14 22:37:05 +0900 | [diff] [blame] | 52 | case FormatUtils::VERSION_4_ONLY_FOR_TESTING: |
Keisuke Kuroyanagi | ea468cc | 2014-10-30 12:54:06 +0900 | [diff] [blame] | 53 | case FormatUtils::VERSION_403: |
Keisuke Kuroyanagi | 7116ea9 | 2014-05-14 22:37:05 +0900 | [diff] [blame] | 54 | return createEmptyV4DictFile<Ver4DictConstants, Ver4DictBuffers, |
| 55 | Ver4DictBuffers::Ver4DictBuffersPtr>( |
| 56 | filePath, localeAsCodePointVector, attributeMap, formatVersion); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 57 | default: |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 58 | AKLOGE("Cannot create dictionary %s because format version %d is not supported.", |
| 59 | filePath, dictVersion); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 60 | return false; |
| 61 | } |
| 62 | } |
| 63 | |
Keisuke Kuroyanagi | 7116ea9 | 2014-05-14 22:37:05 +0900 | [diff] [blame] | 64 | template<class DictConstants, class DictBuffers, class DictBuffersPtr> |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 65 | /* static */ bool DictFileWritingUtils::createEmptyV4DictFile(const char *const dirPath, |
Jean Chalard | 43cf907 | 2014-02-04 23:51:05 +0900 | [diff] [blame] | 66 | const std::vector<int> localeAsCodePointVector, |
Keisuke Kuroyanagi | 455dc84 | 2014-05-09 15:17:01 +0900 | [diff] [blame] | 67 | const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap, |
| 68 | const FormatUtils::FORMAT_VERSION formatVersion) { |
| 69 | HeaderPolicy headerPolicy(formatVersion, localeAsCodePointVector, attributeMap); |
Keisuke Kuroyanagi | 7116ea9 | 2014-05-14 22:37:05 +0900 | [diff] [blame] | 70 | DictBuffersPtr dictBuffers = DictBuffers::createVer4DictBuffers(&headerPolicy, |
| 71 | DictConstants::MAX_DICT_EXTENDED_REGION_SIZE); |
Jean Chalard | a137c21 | 2014-01-30 18:15:35 +0900 | [diff] [blame] | 72 | headerPolicy.fillInAndWriteHeaderToBuffer(true /* updatesLastDecayedTime */, |
Keisuke Kuroyanagi | e8750d9 | 2014-10-21 15:46:14 +0900 | [diff] [blame] | 73 | EntryCounts(), 0 /* extendedRegionSize */, dictBuffers->getWritableHeaderBuffer()); |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 74 | if (!DynamicPtWritingUtils::writeEmptyDictionary( |
Keisuke Kuroyanagi | 4ce480d | 2014-03-06 23:36:38 +0900 | [diff] [blame] | 75 | dictBuffers->getWritableTrieBuffer(), 0 /* rootPos */)) { |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 76 | AKLOGE("Empty ver4 dictionary structure cannot be created on memory."); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 77 | return false; |
| 78 | } |
Keisuke Kuroyanagi | 4ce480d | 2014-03-06 23:36:38 +0900 | [diff] [blame] | 79 | return dictBuffers->flush(dirPath); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 80 | } |
| 81 | |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 82 | /* static */ bool DictFileWritingUtils::flushBufferToFileWithSuffix(const char *const basePath, |
| 83 | const char *const suffix, const BufferWithExtendableBuffer *const buffer) { |
| 84 | const int filePathBufSize = FileUtils::getFilePathWithSuffixBufSize(basePath, suffix); |
| 85 | char filePath[filePathBufSize]; |
| 86 | FileUtils::getFilePathWithSuffix(basePath, suffix, filePathBufSize, filePath); |
| 87 | return flushBufferToFile(filePath, buffer); |
| 88 | } |
| 89 | |
Keisuke Kuroyanagi | 2ac9342 | 2014-07-11 15:15:47 +0900 | [diff] [blame] | 90 | /* static */ bool DictFileWritingUtils::writeBufferToFileTail(FILE *const file, |
| 91 | const BufferWithExtendableBuffer *const buffer) { |
| 92 | uint8_t bufferSize[SIZE_OF_BUFFER_SIZE_FIELD]; |
| 93 | int writingPos = 0; |
| 94 | ByteArrayUtils::writeUintAndAdvancePosition(bufferSize, buffer->getTailPosition(), |
| 95 | SIZE_OF_BUFFER_SIZE_FIELD, &writingPos); |
| 96 | if (fwrite(bufferSize, SIZE_OF_BUFFER_SIZE_FIELD, 1 /* count */, file) < 1) { |
| 97 | return false; |
| 98 | } |
| 99 | return writeBufferToFile(file, buffer); |
| 100 | } |
| 101 | |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 102 | /* static */ bool DictFileWritingUtils::flushBufferToFile(const char *const filePath, |
| 103 | const BufferWithExtendableBuffer *const buffer) { |
Keisuke Kuroyanagi | ed16af7 | 2014-05-14 17:48:28 +0900 | [diff] [blame] | 104 | const int fd = open(filePath, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); |
| 105 | if (fd == -1) { |
| 106 | AKLOGE("File %s cannot be opened. errno: %d", filePath, errno); |
| 107 | ASSERT(false); |
| 108 | return false; |
| 109 | } |
| 110 | FILE *const file = fdopen(fd, "wb"); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 111 | if (!file) { |
Keisuke Kuroyanagi | ed16af7 | 2014-05-14 17:48:28 +0900 | [diff] [blame] | 112 | AKLOGE("fdopen failed for the file %s. errno: %d", filePath, errno); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 113 | ASSERT(false); |
| 114 | return false; |
| 115 | } |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 116 | if (!writeBufferToFile(file, buffer)) { |
Keisuke Kuroyanagi | 2ac9342 | 2014-07-11 15:15:47 +0900 | [diff] [blame] | 117 | fclose(file); |
Ken Wakasa | 2fa3693 | 2013-12-13 17:09:16 +0900 | [diff] [blame] | 118 | remove(filePath); |
| 119 | AKLOGE("Buffer cannot be written to the file %s. size: %d", filePath, |
| 120 | buffer->getTailPosition()); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 121 | ASSERT(false); |
| 122 | return false; |
| 123 | } |
| 124 | fclose(file); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 125 | return true; |
| 126 | } |
| 127 | |
Keisuke Kuroyanagi | 2ac9342 | 2014-07-11 15:15:47 +0900 | [diff] [blame] | 128 | // Returns whether the writing was succeeded or not. |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 129 | /* static */ bool DictFileWritingUtils::writeBufferToFile(FILE *const file, |
| 130 | const BufferWithExtendableBuffer *const buffer) { |
| 131 | const int originalBufSize = buffer->getOriginalBufferSize(); |
| 132 | if (originalBufSize > 0 && fwrite(buffer->getBuffer(false /* usesAdditionalBuffer */), |
| 133 | originalBufSize, 1, file) < 1) { |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 134 | return false; |
| 135 | } |
Keisuke Kuroyanagi | c185100 | 2013-09-30 13:57:54 +0900 | [diff] [blame] | 136 | const int additionalBufSize = buffer->getUsedAdditionalBufferSize(); |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 137 | if (additionalBufSize > 0 && fwrite(buffer->getBuffer(true /* usesAdditionalBuffer */), |
| 138 | additionalBufSize, 1, file) < 1) { |
Keisuke Kuroyanagi | 1592eb8 | 2013-09-26 10:48:43 +0900 | [diff] [blame] | 139 | return false; |
| 140 | } |
| 141 | return true; |
| 142 | } |
| 143 | |
| 144 | } // namespace latinime |