blob: c84b90ee7a83edb741880d050205ec5a884e787f [file] [log] [blame]
/*
* 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());
}
}