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 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 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 62 HeaderReadWriteUtils::createAndGetDictionaryFlagsUsingAttributeMap( 63 const AttributeMap *const attributeMap) { 64 return NO_FLAGS; 65 } 66 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 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 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 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 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 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 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 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 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 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 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 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 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 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