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 <cstring> 21 22 #include "suggest/policyimpl/dictionary/header/header_policy.h" 23 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h" 24 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" 25 #include "suggest/policyimpl/dictionary/utils/format_utils.h" 26 27 namespace latinime { 28 29 const char *const DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE = ".tmp"; 30 31 /* static */ bool DictFileWritingUtils::createEmptyDictFile(const char *const filePath, 32 const int dictVersion, const HeaderReadWriteUtils::AttributeMap *const attributeMap) { 33 switch (dictVersion) { 34 case 3: 35 return createEmptyV3DictFile(filePath, attributeMap); 36 default: 37 // Only version 3 dictionary is supported for now. 38 return false; 39 } 40 } 41 42 /* static */ bool DictFileWritingUtils::createEmptyV3DictFile(const char *const filePath, 43 const HeaderReadWriteUtils::AttributeMap *const attributeMap) { 44 BufferWithExtendableBuffer headerBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */); 45 HeaderPolicy headerPolicy(FormatUtils::VERSION_3, attributeMap); 46 headerPolicy.writeHeaderToBuffer(&headerBuffer, true /* updatesLastUpdatedTime */, 47 true /* updatesLastDecayedTime */, 0 /* unigramCount */, 0 /* bigramCount */, 48 0 /* extendedRegionSize */); 49 BufferWithExtendableBuffer bodyBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */); 50 if (!DynamicPatriciaTrieWritingUtils::writeEmptyDictionary(&bodyBuffer, 0 /* rootPos */)) { 51 return false; 52 } 53 return flushAllHeaderAndBodyToFile(filePath, &headerBuffer, &bodyBuffer); 54 } 55 56 /* static */ bool DictFileWritingUtils::flushAllHeaderAndBodyToFile(const char *const filePath, 57 BufferWithExtendableBuffer *const dictHeader, BufferWithExtendableBuffer *const dictBody) { 58 const int tmpFileNameBufSize = strlen(filePath) 59 + strlen(TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE) + 1 /* terminator */; 60 // Name of a temporary file used for writing that is a connected string of original name and 61 // TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE. 62 char tmpFileName[tmpFileNameBufSize]; 63 snprintf(tmpFileName, tmpFileNameBufSize, "%s%s", filePath, 64 TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE); 65 FILE *const file = fopen(tmpFileName, "wb"); 66 if (!file) { 67 AKLOGE("Dictionary file %s cannnot be opened.", tmpFileName); 68 ASSERT(false); 69 return false; 70 } 71 // Write the dictionary header. 72 if (!writeBufferToFile(file, dictHeader)) { 73 remove(tmpFileName); 74 AKLOGE("Dictionary header cannnot be written. size: %d", dictHeader->getTailPosition()); 75 ASSERT(false); 76 return false; 77 } 78 // Write the dictionary body. 79 if (!writeBufferToFile(file, dictBody)) { 80 remove(tmpFileName); 81 AKLOGE("Dictionary body cannnot be written. size: %d", dictBody->getTailPosition()); 82 ASSERT(false); 83 return false; 84 } 85 fclose(file); 86 rename(tmpFileName, filePath); 87 return true; 88 } 89 90 // This closes file pointer when an error is caused and returns whether the writing was succeeded 91 // or not. 92 /* static */ bool DictFileWritingUtils::writeBufferToFile(FILE *const file, 93 const BufferWithExtendableBuffer *const buffer) { 94 const int originalBufSize = buffer->getOriginalBufferSize(); 95 if (originalBufSize > 0 && fwrite(buffer->getBuffer(false /* usesAdditionalBuffer */), 96 originalBufSize, 1, file) < 1) { 97 fclose(file); 98 return false; 99 } 100 const int additionalBufSize = buffer->getUsedAdditionalBufferSize(); 101 if (additionalBufSize > 0 && fwrite(buffer->getBuffer(true /* usesAdditionalBuffer */), 102 additionalBufSize, 1, file) < 1) { 103 fclose(file); 104 return false; 105 } 106 return true; 107 } 108 109 } // namespace latinime 110