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 const int HeaderReadWriteUtils::MAX_ATTRIBUTE_KEY_LENGTH = 256; 30 const int HeaderReadWriteUtils::MAX_ATTRIBUTE_VALUE_LENGTH = 256; 31 32 const int HeaderReadWriteUtils::HEADER_MAGIC_NUMBER_SIZE = 4; 33 const int HeaderReadWriteUtils::HEADER_DICTIONARY_VERSION_SIZE = 2; 34 const int HeaderReadWriteUtils::HEADER_FLAG_SIZE = 2; 35 const int HeaderReadWriteUtils::HEADER_SIZE_FIELD_SIZE = 4; 36 37 const HeaderReadWriteUtils::DictionaryFlags HeaderReadWriteUtils::NO_FLAGS = 0; 38 // Flags for special processing 39 // Those *must* match the flags in makedict (FormatSpec#*_PROCESSING_FLAG) or 40 // something very bad (like, the apocalypse) will happen. Please update both at the same time. 41 const HeaderReadWriteUtils::DictionaryFlags 42 HeaderReadWriteUtils::GERMAN_UMLAUT_PROCESSING_FLAG = 0x1; 43 const HeaderReadWriteUtils::DictionaryFlags 44 HeaderReadWriteUtils::SUPPORTS_DYNAMIC_UPDATE_FLAG = 0x2; 45 const HeaderReadWriteUtils::DictionaryFlags 46 HeaderReadWriteUtils::FRENCH_LIGATURE_PROCESSING_FLAG = 0x4; 47 48 // Note that these are corresponding definitions in Java side in FormatSpec.FileHeader. 49 const char *const HeaderReadWriteUtils::SUPPORTS_DYNAMIC_UPDATE_KEY = "SUPPORTS_DYNAMIC_UPDATE"; 50 const char *const HeaderReadWriteUtils::REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY = 51 "REQUIRES_GERMAN_UMLAUT_PROCESSING"; 52 const char *const HeaderReadWriteUtils::REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY = 53 "REQUIRES_FRENCH_LIGATURE_PROCESSING"; 54 55 /* static */ int HeaderReadWriteUtils::getHeaderSize(const uint8_t *const dictBuf) { 56 // See the format of the header in the comment in 57 // BinaryDictionaryFormatUtils::detectFormatVersion() 58 return ByteArrayUtils::readUint32(dictBuf, HEADER_MAGIC_NUMBER_SIZE 59 + HEADER_DICTIONARY_VERSION_SIZE + HEADER_FLAG_SIZE); 60 } 61 62 /* static */ HeaderReadWriteUtils::DictionaryFlags 63 HeaderReadWriteUtils::getFlags(const uint8_t *const dictBuf) { 64 return ByteArrayUtils::readUint16(dictBuf, 65 HEADER_MAGIC_NUMBER_SIZE + HEADER_DICTIONARY_VERSION_SIZE); 66 } 67 68 /* static */ HeaderReadWriteUtils::DictionaryFlags 69 HeaderReadWriteUtils::createAndGetDictionaryFlagsUsingAttributeMap( 70 const HeaderReadWriteUtils::AttributeMap *const attributeMap) { 71 const bool requiresGermanUmlautProcessing = readBoolAttributeValue(attributeMap, 72 REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY, false /* defaultValue */); 73 const bool requiresFrenchLigatureProcessing = readBoolAttributeValue(attributeMap, 74 REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY, false /* defaultValue */); 75 const bool supportsDynamicUpdate = readBoolAttributeValue(attributeMap, 76 SUPPORTS_DYNAMIC_UPDATE_KEY, false /* defaultValue */); 77 DictionaryFlags dictflags = NO_FLAGS; 78 dictflags |= requiresGermanUmlautProcessing ? GERMAN_UMLAUT_PROCESSING_FLAG : 0; 79 dictflags |= requiresFrenchLigatureProcessing ? FRENCH_LIGATURE_PROCESSING_FLAG : 0; 80 dictflags |= supportsDynamicUpdate ? SUPPORTS_DYNAMIC_UPDATE_FLAG : 0; 81 return dictflags; 82 } 83 84 /* static */ void HeaderReadWriteUtils::fetchAllHeaderAttributes(const uint8_t *const dictBuf, 85 AttributeMap *const headerAttributes) { 86 const int headerSize = getHeaderSize(dictBuf); 87 int pos = getHeaderOptionsPosition(); 88 if (pos == NOT_A_DICT_POS) { 89 // The header doesn't have header options. 90 return; 91 } 92 int keyBuffer[MAX_ATTRIBUTE_KEY_LENGTH]; 93 int valueBuffer[MAX_ATTRIBUTE_VALUE_LENGTH]; 94 while (pos < headerSize) { 95 const int keyLength = ByteArrayUtils::readStringAndAdvancePosition(dictBuf, 96 MAX_ATTRIBUTE_KEY_LENGTH, keyBuffer, &pos); 97 std::vector<int> key; 98 key.insert(key.end(), keyBuffer, keyBuffer + keyLength); 99 const int valueLength = ByteArrayUtils::readStringAndAdvancePosition(dictBuf, 100 MAX_ATTRIBUTE_VALUE_LENGTH, valueBuffer, &pos); 101 std::vector<int> value; 102 value.insert(value.end(), valueBuffer, valueBuffer + valueLength); 103 headerAttributes->insert(AttributeMap::value_type(key, value)); 104 } 105 } 106 107 /* static */ bool HeaderReadWriteUtils::writeDictionaryVersion( 108 BufferWithExtendableBuffer *const buffer, const FormatUtils::FORMAT_VERSION version, 109 int *const writingPos) { 110 if (!buffer->writeUintAndAdvancePosition(FormatUtils::MAGIC_NUMBER, HEADER_MAGIC_NUMBER_SIZE, 111 writingPos)) { 112 return false; 113 } 114 switch (version) { 115 case FormatUtils::VERSION_2: 116 // Version 2 dictionary writing is not supported. 117 return false; 118 case FormatUtils::VERSION_3: 119 return buffer->writeUintAndAdvancePosition(3 /* data */, 120 HEADER_DICTIONARY_VERSION_SIZE, writingPos); 121 default: 122 return false; 123 } 124 } 125 126 /* static */ bool HeaderReadWriteUtils::writeDictionaryFlags( 127 BufferWithExtendableBuffer *const buffer, const DictionaryFlags flags, 128 int *const writingPos) { 129 return buffer->writeUintAndAdvancePosition(flags, HEADER_FLAG_SIZE, writingPos); 130 } 131 132 /* static */ bool HeaderReadWriteUtils::writeDictionaryHeaderSize( 133 BufferWithExtendableBuffer *const buffer, const int size, int *const writingPos) { 134 return buffer->writeUintAndAdvancePosition(size, HEADER_SIZE_FIELD_SIZE, writingPos); 135 } 136 137 /* static */ bool HeaderReadWriteUtils::writeHeaderAttributes( 138 BufferWithExtendableBuffer *const buffer, const AttributeMap *const headerAttributes, 139 int *const writingPos) { 140 for (AttributeMap::const_iterator it = headerAttributes->begin(); 141 it != headerAttributes->end(); ++it) { 142 if (it->first.empty() || it->second.empty()) { 143 continue; 144 } 145 // Write a key. 146 if (!buffer->writeCodePointsAndAdvancePosition(&(it->first.at(0)), it->first.size(), 147 true /* writesTerminator */, writingPos)) { 148 return false; 149 } 150 // Write a value. 151 if (!buffer->writeCodePointsAndAdvancePosition(&(it->second.at(0)), it->second.size(), 152 true /* writesTerminator */, writingPos)) { 153 return false; 154 } 155 } 156 return true; 157 } 158 159 /* static */ void HeaderReadWriteUtils::setBoolAttribute(AttributeMap *const headerAttributes, 160 const char *const key, const bool value) { 161 setIntAttribute(headerAttributes, key, value ? 1 : 0); 162 } 163 164 /* static */ void HeaderReadWriteUtils::setIntAttribute(AttributeMap *const headerAttributes, 165 const char *const key, const int value) { 166 AttributeMap::key_type keyVector; 167 insertCharactersIntoVector(key, &keyVector); 168 setIntAttributeInner(headerAttributes, &keyVector, value); 169 } 170 171 /* static */ void HeaderReadWriteUtils::setIntAttributeInner(AttributeMap *const headerAttributes, 172 const AttributeMap::key_type *const key, const int value) { 173 AttributeMap::mapped_type valueVector; 174 char charBuf[LARGEST_INT_DIGIT_COUNT + 1]; 175 snprintf(charBuf, LARGEST_INT_DIGIT_COUNT + 1, "%d", value); 176 insertCharactersIntoVector(charBuf, &valueVector); 177 (*headerAttributes)[*key] = valueVector; 178 } 179 180 /* static */ bool HeaderReadWriteUtils::readBoolAttributeValue( 181 const AttributeMap *const headerAttributes, const char *const key, 182 const bool defaultValue) { 183 const int intDefaultValue = defaultValue ? 1 : 0; 184 const int intValue = readIntAttributeValue(headerAttributes, key, intDefaultValue); 185 return intValue != 0; 186 } 187 188 /* static */ int HeaderReadWriteUtils::readIntAttributeValue( 189 const AttributeMap *const headerAttributes, const char *const key, 190 const int defaultValue) { 191 AttributeMap::key_type keyVector; 192 insertCharactersIntoVector(key, &keyVector); 193 return readIntAttributeValueInner(headerAttributes, &keyVector, defaultValue); 194 } 195 196 /* static */ int HeaderReadWriteUtils::readIntAttributeValueInner( 197 const AttributeMap *const headerAttributes, const AttributeMap::key_type *const key, 198 const int defaultValue) { 199 AttributeMap::const_iterator it = headerAttributes->find(*key); 200 if (it != headerAttributes->end()) { 201 int value = 0; 202 bool isNegative = false; 203 for (size_t i = 0; i < it->second.size(); ++i) { 204 if (i == 0 && it->second.at(i) == '-') { 205 isNegative = true; 206 } else { 207 if (!isdigit(it->second.at(i))) { 208 // If not a number. 209 return defaultValue; 210 } 211 value *= 10; 212 value += it->second.at(i) - '0'; 213 } 214 } 215 return isNegative ? -value : value; 216 } 217 return defaultValue; 218 } 219 220 /* static */ void HeaderReadWriteUtils::insertCharactersIntoVector(const char *const characters, 221 std::vector<int> *const vector) { 222 for (int i = 0; characters[i]; ++i) { 223 vector->push_back(characters[i]); 224 } 225 } 226 227 } // namespace latinime 228