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/header/header_read_write_utils.h"
18 
19 #include <cctype>
20 #include <cstdio>
21 #include <vector>
22 
23 #include "defines.h"
24 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
25 #include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
26 
27 namespace latinime {
28 
29 // Number of base-10 digits in the largest integer + 1 to leave room for a zero terminator.
30 // As such, this is the maximum number of characters will be needed to represent an int as a
31 // string, including the terminator; this is used as the size of a string buffer large enough to
32 // hold any value that is intended to fit in an integer, e.g. in the code that reads the header
33 // of the binary dictionary where a {key,value} string pair scheme is used.
34 const int HeaderReadWriteUtils::LARGEST_INT_DIGIT_COUNT = 11;
35 
36 const int HeaderReadWriteUtils::MAX_ATTRIBUTE_KEY_LENGTH = 256;
37 const int HeaderReadWriteUtils::MAX_ATTRIBUTE_VALUE_LENGTH = 256;
38 
39 const int HeaderReadWriteUtils::HEADER_MAGIC_NUMBER_SIZE = 4;
40 const int HeaderReadWriteUtils::HEADER_DICTIONARY_VERSION_SIZE = 2;
41 const int HeaderReadWriteUtils::HEADER_FLAG_SIZE = 2;
42 const int HeaderReadWriteUtils::HEADER_SIZE_FIELD_SIZE = 4;
43 
44 const HeaderReadWriteUtils::DictionaryFlags HeaderReadWriteUtils::NO_FLAGS = 0;
45 
46 typedef DictionaryHeaderStructurePolicy::AttributeMap AttributeMap;
47 
getHeaderSize(const uint8_t * const dictBuf)48 /* static */ int HeaderReadWriteUtils::getHeaderSize(const uint8_t *const dictBuf) {
49     // See the format of the header in the comment in
50     // BinaryDictionaryFormatUtils::detectFormatVersion()
51     return ByteArrayUtils::readUint32(dictBuf, HEADER_MAGIC_NUMBER_SIZE
52             + HEADER_DICTIONARY_VERSION_SIZE + HEADER_FLAG_SIZE);
53 }
54 
55 /* static */ HeaderReadWriteUtils::DictionaryFlags
getFlags(const uint8_t * const dictBuf)56         HeaderReadWriteUtils::getFlags(const uint8_t *const dictBuf) {
57     return ByteArrayUtils::readUint16(dictBuf,
58             HEADER_MAGIC_NUMBER_SIZE + HEADER_DICTIONARY_VERSION_SIZE);
59 }
60 
61 /* static */ HeaderReadWriteUtils::DictionaryFlags
createAndGetDictionaryFlagsUsingAttributeMap(const AttributeMap * const attributeMap)62         HeaderReadWriteUtils::createAndGetDictionaryFlagsUsingAttributeMap(
63                 const AttributeMap *const attributeMap) {
64     return NO_FLAGS;
65 }
66 
fetchAllHeaderAttributes(const uint8_t * const dictBuf,AttributeMap * const headerAttributes)67 /* static */ void HeaderReadWriteUtils::fetchAllHeaderAttributes(const uint8_t *const dictBuf,
68         AttributeMap *const headerAttributes) {
69     const int headerSize = getHeaderSize(dictBuf);
70     int pos = getHeaderOptionsPosition();
71     if (pos == NOT_A_DICT_POS) {
72         // The header doesn't have header options.
73         return;
74     }
75     int keyBuffer[MAX_ATTRIBUTE_KEY_LENGTH];
76     int valueBuffer[MAX_ATTRIBUTE_VALUE_LENGTH];
77     while (pos < headerSize) {
78         const int keyLength = ByteArrayUtils::readStringAndAdvancePosition(dictBuf,
79                 MAX_ATTRIBUTE_KEY_LENGTH, keyBuffer, &pos);
80         std::vector<int> key;
81         key.insert(key.end(), keyBuffer, keyBuffer + keyLength);
82         const int valueLength = ByteArrayUtils::readStringAndAdvancePosition(dictBuf,
83                 MAX_ATTRIBUTE_VALUE_LENGTH, valueBuffer, &pos);
84         std::vector<int> value;
85         value.insert(value.end(), valueBuffer, valueBuffer + valueLength);
86         headerAttributes->insert(AttributeMap::value_type(key, value));
87     }
88 }
89 
writeDictionaryVersion(BufferWithExtendableBuffer * const buffer,const FormatUtils::FORMAT_VERSION version,int * const writingPos)90 /* static */ bool HeaderReadWriteUtils::writeDictionaryVersion(
91         BufferWithExtendableBuffer *const buffer, const FormatUtils::FORMAT_VERSION version,
92         int *const writingPos) {
93     if (!buffer->writeUintAndAdvancePosition(FormatUtils::MAGIC_NUMBER, HEADER_MAGIC_NUMBER_SIZE,
94             writingPos)) {
95         return false;
96     }
97     switch (version) {
98         case FormatUtils::VERSION_2:
99             // Version 2 dictionary writing is not supported.
100             return false;
101         case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
102         case FormatUtils::VERSION_4:
103         case FormatUtils::VERSION_4_DEV:
104             return buffer->writeUintAndAdvancePosition(version /* data */,
105                     HEADER_DICTIONARY_VERSION_SIZE, writingPos);
106         default:
107             return false;
108     }
109 }
110 
writeDictionaryFlags(BufferWithExtendableBuffer * const buffer,const DictionaryFlags flags,int * const writingPos)111 /* static */ bool HeaderReadWriteUtils::writeDictionaryFlags(
112         BufferWithExtendableBuffer *const buffer, const DictionaryFlags flags,
113         int *const writingPos) {
114     return buffer->writeUintAndAdvancePosition(flags, HEADER_FLAG_SIZE, writingPos);
115 }
116 
writeDictionaryHeaderSize(BufferWithExtendableBuffer * const buffer,const int size,int * const writingPos)117 /* static */ bool HeaderReadWriteUtils::writeDictionaryHeaderSize(
118         BufferWithExtendableBuffer *const buffer, const int size, int *const writingPos) {
119     return buffer->writeUintAndAdvancePosition(size, HEADER_SIZE_FIELD_SIZE, writingPos);
120 }
121 
writeHeaderAttributes(BufferWithExtendableBuffer * const buffer,const AttributeMap * const headerAttributes,int * const writingPos)122 /* static */ bool HeaderReadWriteUtils::writeHeaderAttributes(
123         BufferWithExtendableBuffer *const buffer, const AttributeMap *const headerAttributes,
124         int *const writingPos) {
125     for (AttributeMap::const_iterator it = headerAttributes->begin();
126             it != headerAttributes->end(); ++it) {
127         if (it->first.empty() || it->second.empty()) {
128             continue;
129         }
130         // Write a key.
131         if (!buffer->writeCodePointsAndAdvancePosition(&(it->first.at(0)), it->first.size(),
132                 true /* writesTerminator */, writingPos)) {
133             return false;
134         }
135         // Write a value.
136         if (!buffer->writeCodePointsAndAdvancePosition(&(it->second.at(0)), it->second.size(),
137                 true /* writesTerminator */, writingPos)) {
138             return false;
139         }
140     }
141     return true;
142 }
143 
setCodePointVectorAttribute(AttributeMap * const headerAttributes,const char * const key,const std::vector<int> value)144 /* static */ void HeaderReadWriteUtils::setCodePointVectorAttribute(
145         AttributeMap *const headerAttributes, const char *const key, const std::vector<int> value) {
146     AttributeMap::key_type keyVector;
147     insertCharactersIntoVector(key, &keyVector);
148     (*headerAttributes)[keyVector] = value;
149 }
150 
setBoolAttribute(AttributeMap * const headerAttributes,const char * const key,const bool value)151 /* static */ void HeaderReadWriteUtils::setBoolAttribute(AttributeMap *const headerAttributes,
152         const char *const key, const bool value) {
153     setIntAttribute(headerAttributes, key, value ? 1 : 0);
154 }
155 
setIntAttribute(AttributeMap * const headerAttributes,const char * const key,const int value)156 /* static */ void HeaderReadWriteUtils::setIntAttribute(AttributeMap *const headerAttributes,
157         const char *const key, const int value) {
158     AttributeMap::key_type keyVector;
159     insertCharactersIntoVector(key, &keyVector);
160     setIntAttributeInner(headerAttributes, &keyVector, value);
161 }
162 
setIntAttributeInner(AttributeMap * const headerAttributes,const AttributeMap::key_type * const key,const int value)163 /* static */ void HeaderReadWriteUtils::setIntAttributeInner(AttributeMap *const headerAttributes,
164         const AttributeMap::key_type *const key, const int value) {
165     AttributeMap::mapped_type valueVector;
166     char charBuf[LARGEST_INT_DIGIT_COUNT];
167     snprintf(charBuf, sizeof(charBuf), "%d", value);
168     insertCharactersIntoVector(charBuf, &valueVector);
169     (*headerAttributes)[*key] = valueVector;
170 }
171 
readCodePointVectorAttributeValue(const AttributeMap * const headerAttributes,const char * const key)172 /* static */ const std::vector<int> HeaderReadWriteUtils::readCodePointVectorAttributeValue(
173         const AttributeMap *const headerAttributes, const char *const key) {
174     AttributeMap::key_type keyVector;
175     insertCharactersIntoVector(key, &keyVector);
176     AttributeMap::const_iterator it = headerAttributes->find(keyVector);
177     if (it == headerAttributes->end()) {
178         return std::vector<int>();
179     } else {
180         return it->second;
181     }
182 }
183 
readBoolAttributeValue(const AttributeMap * const headerAttributes,const char * const key,const bool defaultValue)184 /* static */ bool HeaderReadWriteUtils::readBoolAttributeValue(
185         const AttributeMap *const headerAttributes, const char *const key,
186         const bool defaultValue) {
187     const int intDefaultValue = defaultValue ? 1 : 0;
188     const int intValue = readIntAttributeValue(headerAttributes, key, intDefaultValue);
189     return intValue != 0;
190 }
191 
readIntAttributeValue(const AttributeMap * const headerAttributes,const char * const key,const int defaultValue)192 /* static */ int HeaderReadWriteUtils::readIntAttributeValue(
193         const AttributeMap *const headerAttributes, const char *const key,
194         const int defaultValue) {
195     AttributeMap::key_type keyVector;
196     insertCharactersIntoVector(key, &keyVector);
197     return readIntAttributeValueInner(headerAttributes, &keyVector, defaultValue);
198 }
199 
readIntAttributeValueInner(const AttributeMap * const headerAttributes,const AttributeMap::key_type * const key,const int defaultValue)200 /* static */ int HeaderReadWriteUtils::readIntAttributeValueInner(
201         const AttributeMap *const headerAttributes, const AttributeMap::key_type *const key,
202         const int defaultValue) {
203     AttributeMap::const_iterator it = headerAttributes->find(*key);
204     if (it != headerAttributes->end()) {
205         int value = 0;
206         bool isNegative = false;
207         for (size_t i = 0; i < it->second.size(); ++i) {
208             if (i == 0 && it->second.at(i) == '-') {
209                 isNegative = true;
210             } else {
211                 if (!isdigit(it->second.at(i))) {
212                     // If not a number.
213                     return defaultValue;
214                 }
215                 value *= 10;
216                 value += it->second.at(i) - '0';
217             }
218         }
219         return isNegative ? -value : value;
220     }
221     return defaultValue;
222 }
223 
insertCharactersIntoVector(const char * const characters,std::vector<int> * const vector)224 /* static */ void HeaderReadWriteUtils::insertCharactersIntoVector(const char *const characters,
225         std::vector<int> *const vector) {
226     for (int i = 0; characters[i]; ++i) {
227         vector->push_back(characters[i]);
228     }
229 }
230 
231 } // namespace latinime
232