1 /* 2 * Copyright (C) 2009 Esmertec AG. 3 * Copyright (C) 2009 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include "imps_encoder.h" 21 22 bool WbxmlEncoder::isXmlWhitespace(int ch) 23 { 24 return ch == ' ' || ch == 9 || ch == 0xd || ch == 0xa; 25 } 26 27 bool WbxmlEncoder::parseUint(const char * s, int len, uint32_t *res) 28 { 29 string str(s, len); 30 char *end; 31 long long val = strtoll(str.c_str(), &end, 10); 32 if (*end != 0 || val < 0 || val > 0xFFFFFFFFU) { 33 return false; 34 } 35 *res = (uint32_t)val; 36 return true; 37 } 38 39 EncoderError WbxmlEncoder::encodeInteger(const char *chars, int len) 40 { 41 uint32_t val; 42 if (!parseUint(chars, len, &val)) { 43 return ERROR_INVALID_INTEGER_VALUE; 44 } 45 46 appendResult(TOKEN_OPAQUE); 47 uint32_t mask = 0xff000000U; 48 int numBytes = 4; 49 while (!(val & mask) && mask) { 50 numBytes--; 51 mask >>= 8; 52 } 53 if (!numBytes) { 54 // Zero value. We generate at least 1 byte OPAQUE data. 55 // libwbxml2 generates 0 byte long OPAQUE data (0xC3 0x00) in this case. 56 numBytes = 1; 57 } 58 59 appendResult(numBytes); 60 while (numBytes) { 61 numBytes--; 62 appendResult((val >> (numBytes * 8)) & 0xff); 63 } 64 65 return NO_ERROR; 66 } 67 68 EncoderError WbxmlEncoder::encodeDatetime(const char *chars, int len) 69 { 70 // to make life easier we accept only yyyymmddThhmmssZ 71 if (len != 16 || chars[8] != 'T' || chars[15] != 'Z') { 72 return ERROR_INVALID_DATETIME_VALUE; 73 } 74 appendResult(TOKEN_OPAQUE); 75 appendResult(6); 76 77 uint32_t year, month, day, hour, min, sec; 78 if (!parseUint(chars, 4, &year) 79 || !parseUint(chars + 4, 2, &month) 80 || !parseUint(chars + 6, 2, &day) 81 || !parseUint(chars + 9, 2, &hour) 82 || !parseUint(chars + 11,2, &min) 83 || !parseUint(chars + 13,2, &sec)) { 84 return ERROR_INVALID_DATETIME_VALUE; 85 } 86 if (year > 4095 || month > 12 || day > 31 || hour > 23 || min > 59 || sec > 59) { 87 return ERROR_INVALID_DATETIME_VALUE; 88 } 89 90 appendResult(year >> 6); 91 appendResult(((year & 0x3f) << 2) | (month >> 2)); 92 appendResult(((month & 0x3) << 6) | (day << 1) | (hour >> 4)); 93 appendResult(((hour & 0xf) << 4) | (min >> 2)); 94 appendResult(((min & 0x2) << 6) | sec); 95 appendResult('Z'); 96 return NO_ERROR; 97 } 98 99 void WbxmlEncoder::encodeInlinedStr(const char *s, int len) 100 { 101 // TODO: handle ENTITY 102 appendResult(TOKEN_STR_I); 103 appendResult(s, len); 104 appendResult('\0'); 105 } 106 107 void WbxmlEncoder::encodeMbuint(uint32_t val) 108 { 109 char buf[32 / 7 + 1]; // each byte holds up to 7 bits 110 int i = sizeof(buf); 111 112 buf[--i] = val & 0x7f; 113 val >>= 7; 114 while ((i > 0) && (val & 0x7f)) { 115 buf[--i] = 0x80 | (val & 0x7f); 116 val >>= 7; 117 } 118 119 appendResult(buf + i, sizeof(buf) - i); 120 } 121 122 int WbxmlEncoder::appendToStringTable(const char *s) 123 { 124 int stringTableSize = mStringTable.size(); 125 int offset = 0; 126 127 // search the string table to find if the string already exist 128 int index = 0; 129 for (; index < stringTableSize; index++) { 130 if (mStringTable[index] == s) { 131 break; 132 } 133 offset += mStringTable[index].length(); 134 ++offset; // '\0' for each string in the table 135 } 136 if (index == stringTableSize) { 137 // not found, insert a new one 138 mStringTable.push_back(s); 139 } 140 return offset; 141 } 142 143 void WbxmlEncoder::sendResult() 144 { 145 if (mHandler) { 146 string data; 147 string tmp = mResult; 148 mResult = data; 149 150 // WBXML 1.3, UTF-8 151 char header[3] = { 0x03, (char) mPublicId, 0x6A }; 152 appendResult(header, 3); 153 154 // calculate the length of string table 155 int len = 0; 156 for (int i = 0; i < mStringTable.size(); i++) { 157 len += mStringTable[i].length(); 158 ++len; 159 } 160 161 encodeMbuint(len); 162 163 // encode each string in the table 164 for (int i = 0; i < mStringTable.size(); i++) { 165 mResult += mStringTable[i]; 166 mResult += '\0'; 167 } 168 169 mResult += tmp; 170 171 mHandler->wbxmlData(mResult.c_str(), mResult.size()); 172 } 173 } 174