| /* |
| * Copyright (C) 2009 Esmertec AG. |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include "imps_encoder.h" |
| |
| bool WbxmlEncoder::isXmlWhitespace(int ch) |
| { |
| return ch == ' ' || ch == 9 || ch == 0xd || ch == 0xa; |
| } |
| |
| bool WbxmlEncoder::parseUint(const char * s, int len, uint32_t *res) |
| { |
| string str(s, len); |
| char *end; |
| long long val = strtoll(str.c_str(), &end, 10); |
| if (*end != 0 || val < 0 || val > 0xFFFFFFFFU) { |
| return false; |
| } |
| *res = (uint32_t)val; |
| return true; |
| } |
| |
| EncoderError WbxmlEncoder::encodeInteger(const char *chars, int len) |
| { |
| uint32_t val; |
| if (!parseUint(chars, len, &val)) { |
| return ERROR_INVALID_INTEGER_VALUE; |
| } |
| |
| appendResult(TOKEN_OPAQUE); |
| uint32_t mask = 0xff000000U; |
| int numBytes = 4; |
| while (!(val & mask) && mask) { |
| numBytes--; |
| mask >>= 8; |
| } |
| if (!numBytes) { |
| // Zero value. We generate at least 1 byte OPAQUE data. |
| // libwbxml2 generates 0 byte long OPAQUE data (0xC3 0x00) in this case. |
| numBytes = 1; |
| } |
| |
| appendResult(numBytes); |
| while (numBytes) { |
| numBytes--; |
| appendResult((val >> (numBytes * 8)) & 0xff); |
| } |
| |
| return NO_ERROR; |
| } |
| |
| EncoderError WbxmlEncoder::encodeDatetime(const char *chars, int len) |
| { |
| // to make life easier we accept only yyyymmddThhmmssZ |
| if (len != 16 || chars[8] != 'T' || chars[15] != 'Z') { |
| return ERROR_INVALID_DATETIME_VALUE; |
| } |
| appendResult(TOKEN_OPAQUE); |
| appendResult(6); |
| |
| uint32_t year, month, day, hour, min, sec; |
| if (!parseUint(chars, 4, &year) |
| || !parseUint(chars + 4, 2, &month) |
| || !parseUint(chars + 6, 2, &day) |
| || !parseUint(chars + 9, 2, &hour) |
| || !parseUint(chars + 11,2, &min) |
| || !parseUint(chars + 13,2, &sec)) { |
| return ERROR_INVALID_DATETIME_VALUE; |
| } |
| if (year > 4095 || month > 12 || day > 31 || hour > 23 || min > 59 || sec > 59) { |
| return ERROR_INVALID_DATETIME_VALUE; |
| } |
| |
| appendResult(year >> 6); |
| appendResult(((year & 0x3f) << 2) | (month >> 2)); |
| appendResult(((month & 0x3) << 6) | (day << 1) | (hour >> 4)); |
| appendResult(((hour & 0xf) << 4) | (min >> 2)); |
| appendResult(((min & 0x2) << 6) | sec); |
| appendResult('Z'); |
| return NO_ERROR; |
| } |
| |
| void WbxmlEncoder::encodeInlinedStr(const char *s, int len) |
| { |
| // TODO: handle ENTITY |
| appendResult(TOKEN_STR_I); |
| appendResult(s, len); |
| appendResult('\0'); |
| } |
| |
| void WbxmlEncoder::encodeMbuint(uint32_t val) |
| { |
| char buf[32 / 7 + 1]; // each byte holds up to 7 bits |
| int i = sizeof(buf); |
| |
| buf[--i] = val & 0x7f; |
| val >>= 7; |
| while ((i > 0) && (val & 0x7f)) { |
| buf[--i] = 0x80 | (val & 0x7f); |
| val >>= 7; |
| } |
| |
| appendResult(buf + i, sizeof(buf) - i); |
| } |
| |
| int WbxmlEncoder::appendToStringTable(const char *s) |
| { |
| int stringTableSize = mStringTable.size(); |
| int offset = 0; |
| |
| // search the string table to find if the string already exist |
| int index = 0; |
| for (; index < stringTableSize; index++) { |
| if (mStringTable[index] == s) { |
| break; |
| } |
| offset += mStringTable[index].length(); |
| ++offset; // '\0' for each string in the table |
| } |
| if (index == stringTableSize) { |
| // not found, insert a new one |
| mStringTable.push_back(s); |
| } |
| return offset; |
| } |
| |
| void WbxmlEncoder::sendResult() |
| { |
| if (mHandler) { |
| string data; |
| string tmp = mResult; |
| mResult = data; |
| |
| // WBXML 1.3, UTF-8 |
| char header[3] = { 0x03, (char) mPublicId, 0x6A }; |
| appendResult(header, 3); |
| |
| // calculate the length of string table |
| int len = 0; |
| for (int i = 0; i < mStringTable.size(); i++) { |
| len += mStringTable[i].length(); |
| ++len; |
| } |
| |
| encodeMbuint(len); |
| |
| // encode each string in the table |
| for (int i = 0; i < mStringTable.size(); i++) { |
| mResult += mStringTable[i]; |
| mResult += '\0'; |
| } |
| |
| mResult += tmp; |
| |
| mHandler->wbxmlData(mResult.c_str(), mResult.size()); |
| } |
| } |