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 "dictionary/structure/dictionary_structure_with_buffer_policy_factory.h"
18
19 #include <climits>
20
21 #include "defines.h"
22 #include "dictionary/structure/backward/v402/ver4_dict_buffers.h"
23 #include "dictionary/structure/backward/v402/ver4_dict_constants.h"
24 #include "dictionary/structure/backward/v402/ver4_patricia_trie_policy.h"
25 #include "dictionary/structure/pt_common/dynamic_pt_writing_utils.h"
26 #include "dictionary/structure/v2/patricia_trie_policy.h"
27 #include "dictionary/structure/v4/ver4_dict_buffers.h"
28 #include "dictionary/structure/v4/ver4_dict_constants.h"
29 #include "dictionary/structure/v4/ver4_patricia_trie_policy.h"
30 #include "dictionary/utils/dict_file_writing_utils.h"
31 #include "dictionary/utils/file_utils.h"
32 #include "dictionary/utils/format_utils.h"
33 #include "dictionary/utils/mmapped_buffer.h"
34 #include "utils/byte_array_view.h"
35
36 namespace latinime {
37
38 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr
newPolicyForExistingDictFile(const char * const path,const int bufOffset,const int size,const bool isUpdatable)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
newPolicyForOnMemoryDict(const int formatVersion,const std::vector<int> & locale,const DictionaryHeaderStructurePolicy::AttributeMap * const attributeMap)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_402: {
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_403: {
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
newPolicyForOnMemoryV4Dict(const FormatUtils::FORMAT_VERSION formatVersion,const std::vector<int> & locale,const DictionaryHeaderStructurePolicy::AttributeMap * const attributeMap)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
newPolicyForDirectoryDict(const char * const path,const bool isUpdatable)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());
115 switch (formatVersion) {
116 case FormatUtils::VERSION_2:
117 case FormatUtils::VERSION_201:
118 case FormatUtils::VERSION_202:
119 AKLOGE("Given path is a directory but the format is version 2xx. path: %s", path);
120 break;
121 case FormatUtils::VERSION_402: {
122 return newPolicyForV4Dict<backward::v402::Ver4DictConstants,
123 backward::v402::Ver4DictBuffers,
124 backward::v402::Ver4DictBuffers::Ver4DictBuffersPtr,
125 backward::v402::Ver4PatriciaTriePolicy>(
126 headerFilePath, formatVersion, std::move(mmappedBuffer));
127 }
128 case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
129 case FormatUtils::VERSION_403: {
130 return newPolicyForV4Dict<Ver4DictConstants, Ver4DictBuffers,
131 Ver4DictBuffers::Ver4DictBuffersPtr, Ver4PatriciaTriePolicy>(
132 headerFilePath, formatVersion, std::move(mmappedBuffer));
133 }
134 default:
135 AKLOGE("DICT: dictionary format is unknown, bad magic number. path: %s", path);
136 break;
137 }
138 ASSERT(false);
139 return nullptr;
140 }
141
142 template<class DictConstants, class DictBuffers, class DictBuffersPtr, class StructurePolicy>
143 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr
newPolicyForV4Dict(const char * const headerFilePath,const FormatUtils::FORMAT_VERSION formatVersion,MmappedBuffer::MmappedBufferPtr && mmappedBuffer)144 DictionaryStructureWithBufferPolicyFactory::newPolicyForV4Dict(
145 const char *const headerFilePath, const FormatUtils::FORMAT_VERSION formatVersion,
146 MmappedBuffer::MmappedBufferPtr &&mmappedBuffer) {
147 const int dictDirPathBufSize = strlen(headerFilePath) + 1 /* terminator */;
148 char dictPath[dictDirPathBufSize];
149 if (!FileUtils::getFilePathWithoutSuffix(headerFilePath,
150 DictConstants::HEADER_FILE_EXTENSION, dictDirPathBufSize, dictPath)) {
151 AKLOGE("Dictionary file name is not valid as a ver4 dictionary. header path: %s",
152 headerFilePath);
153 ASSERT(false);
154 return nullptr;
155 }
156 DictBuffersPtr dictBuffers =
157 DictBuffers::openVer4DictBuffers(dictPath, std::move(mmappedBuffer), formatVersion);
158 if (!dictBuffers || !dictBuffers->isValid()) {
159 AKLOGE("DICT: The dictionary doesn't satisfy ver4 format requirements. path: %s",
160 dictPath);
161 ASSERT(false);
162 return nullptr;
163 }
164 return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(
165 new StructurePolicy(std::move(dictBuffers)));
166 }
167
168 /* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr
newPolicyForFileDict(const char * const path,const int bufOffset,const int size)169 DictionaryStructureWithBufferPolicyFactory::newPolicyForFileDict(
170 const char *const path, const int bufOffset, const int size) {
171 // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of
172 // MmappedBufferPtr if the instance has the responsibility.
173 MmappedBuffer::MmappedBufferPtr mmappedBuffer(
174 MmappedBuffer::openBuffer(path, bufOffset, size, false /* isUpdatable */));
175 if (!mmappedBuffer) {
176 return nullptr;
177 }
178 switch (FormatUtils::detectFormatVersion(mmappedBuffer->getReadOnlyByteArrayView())) {
179 case FormatUtils::VERSION_2:
180 case FormatUtils::VERSION_201:
181 AKLOGE("Dictionary versions 2 and 201 are incompatible with this version");
182 break;
183 case FormatUtils::VERSION_202:
184 return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(
185 new PatriciaTriePolicy(std::move(mmappedBuffer)));
186 case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
187 case FormatUtils::VERSION_402:
188 case FormatUtils::VERSION_403:
189 AKLOGE("Given path is a file but the format is version 4. path: %s", path);
190 break;
191 default:
192 AKLOGE("DICT: dictionary format is unknown, bad magic number. path: %s", path);
193 break;
194 }
195 ASSERT(false);
196 return nullptr;
197 }
198
getHeaderFilePathInDictDir(const char * const dictDirPath,const int outHeaderFileBufSize,char * const outHeaderFilePath)199 /* static */ void DictionaryStructureWithBufferPolicyFactory::getHeaderFilePathInDictDir(
200 const char *const dictDirPath, const int outHeaderFileBufSize,
201 char *const outHeaderFilePath) {
202 const int dictNameBufSize = strlen(dictDirPath) + 1 /* terminator */;
203 char dictName[dictNameBufSize];
204 FileUtils::getBasename(dictDirPath, dictNameBufSize, dictName);
205 snprintf(outHeaderFilePath, outHeaderFileBufSize, "%s/%s%s", dictDirPath,
206 dictName, Ver4DictConstants::HEADER_FILE_EXTENSION);
207 }
208
209 } // namespace latinime
210