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/utils/dict_file_writing_utils.h" 18 19 #include <cstdio> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <sys/stat.h> 23 #include <sys/types.h> 24 25 #include "suggest/policyimpl/dictionary/header/header_policy.h" 26 #include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h" 27 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" 28 #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" 29 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" 30 #include "suggest/policyimpl/dictionary/utils/file_utils.h" 31 #include "suggest/policyimpl/dictionary/utils/format_utils.h" 32 #include "utils/time_keeper.h" 33 34 namespace latinime { 35 36 const char *const DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE = ".tmp"; 37 // Enough size to describe buffer size. 38 const int DictFileWritingUtils::SIZE_OF_BUFFER_SIZE_FIELD = 4; 39 40 /* static */ bool DictFileWritingUtils::createEmptyDictFile(const char *const filePath, 41 const int dictVersion, const std::vector<int> localeAsCodePointVector, 42 const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { 43 TimeKeeper::setCurrentTime(); 44 const FormatUtils::FORMAT_VERSION formatVersion = FormatUtils::getFormatVersion(dictVersion); 45 switch (formatVersion) { 46 case FormatUtils::VERSION_4: 47 return createEmptyV4DictFile<backward::v402::Ver4DictConstants, 48 backward::v402::Ver4DictBuffers, 49 backward::v402::Ver4DictBuffers::Ver4DictBuffersPtr>( 50 filePath, localeAsCodePointVector, attributeMap, formatVersion); 51 case FormatUtils::VERSION_4_ONLY_FOR_TESTING: 52 case FormatUtils::VERSION_4_DEV: 53 return createEmptyV4DictFile<Ver4DictConstants, Ver4DictBuffers, 54 Ver4DictBuffers::Ver4DictBuffersPtr>( 55 filePath, localeAsCodePointVector, attributeMap, formatVersion); 56 default: 57 AKLOGE("Cannot create dictionary %s because format version %d is not supported.", 58 filePath, dictVersion); 59 return false; 60 } 61 } 62 63 template<class DictConstants, class DictBuffers, class DictBuffersPtr> 64 /* static */ bool DictFileWritingUtils::createEmptyV4DictFile(const char *const dirPath, 65 const std::vector<int> localeAsCodePointVector, 66 const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap, 67 const FormatUtils::FORMAT_VERSION formatVersion) { 68 HeaderPolicy headerPolicy(formatVersion, localeAsCodePointVector, attributeMap); 69 DictBuffersPtr dictBuffers = DictBuffers::createVer4DictBuffers(&headerPolicy, 70 DictConstants::MAX_DICT_EXTENDED_REGION_SIZE); 71 headerPolicy.fillInAndWriteHeaderToBuffer(true /* updatesLastDecayedTime */, 72 0 /* unigramCount */, 0 /* bigramCount */, 73 0 /* extendedRegionSize */, dictBuffers->getWritableHeaderBuffer()); 74 if (!DynamicPtWritingUtils::writeEmptyDictionary( 75 dictBuffers->getWritableTrieBuffer(), 0 /* rootPos */)) { 76 AKLOGE("Empty ver4 dictionary structure cannot be created on memory."); 77 return false; 78 } 79 return dictBuffers->flush(dirPath); 80 } 81 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 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 102 /* static */ bool DictFileWritingUtils::flushBufferToFile(const char *const filePath, 103 const BufferWithExtendableBuffer *const buffer) { 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"); 111 if (!file) { 112 AKLOGE("fdopen failed for the file %s. errno: %d", filePath, errno); 113 ASSERT(false); 114 return false; 115 } 116 if (!writeBufferToFile(file, buffer)) { 117 fclose(file); 118 remove(filePath); 119 AKLOGE("Buffer cannot be written to the file %s. size: %d", filePath, 120 buffer->getTailPosition()); 121 ASSERT(false); 122 return false; 123 } 124 fclose(file); 125 return true; 126 } 127 128 // Returns whether the writing was succeeded or not. 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) { 134 return false; 135 } 136 const int additionalBufSize = buffer->getUsedAdditionalBufferSize(); 137 if (additionalBufSize > 0 && fwrite(buffer->getBuffer(true /* usesAdditionalBuffer */), 138 additionalBufSize, 1, file) < 1) { 139 return false; 140 } 141 return true; 142 } 143 144 } // namespace latinime 145