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 27namespace latinime { 28 29const int HeaderReadWriteUtils::MAX_ATTRIBUTE_KEY_LENGTH = 256; 30const int HeaderReadWriteUtils::MAX_ATTRIBUTE_VALUE_LENGTH = 256; 31 32const int HeaderReadWriteUtils::HEADER_MAGIC_NUMBER_SIZE = 4; 33const int HeaderReadWriteUtils::HEADER_DICTIONARY_VERSION_SIZE = 2; 34const int HeaderReadWriteUtils::HEADER_FLAG_SIZE = 2; 35const int HeaderReadWriteUtils::HEADER_SIZE_FIELD_SIZE = 4; 36 37const 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. 41const HeaderReadWriteUtils::DictionaryFlags 42 HeaderReadWriteUtils::GERMAN_UMLAUT_PROCESSING_FLAG = 0x1; 43const HeaderReadWriteUtils::DictionaryFlags 44 HeaderReadWriteUtils::SUPPORTS_DYNAMIC_UPDATE_FLAG = 0x2; 45const HeaderReadWriteUtils::DictionaryFlags 46 HeaderReadWriteUtils::FRENCH_LIGATURE_PROCESSING_FLAG = 0x4; 47 48// Note that these are corresponding definitions in Java side in FormatSpec.FileHeader. 49const char *const HeaderReadWriteUtils::SUPPORTS_DYNAMIC_UPDATE_KEY = "SUPPORTS_DYNAMIC_UPDATE"; 50const char *const HeaderReadWriteUtils::REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY = 51 "REQUIRES_GERMAN_UMLAUT_PROCESSING"; 52const 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