blob: 26a30ee86df31d8627b91ad6c6cd76e6acec2447 [file] [log] [blame]
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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"
#include "csp13_hash.h"
/* TODOs:
* - use string table?
* - move common WBXML routines to WbxmlEncoder
* - so called "token" based IMPS value encoding
*/
struct XmlnsPrefix {
const char * prefix;
int attrToken;
};
static const XmlnsPrefix csp13xmlns[] = {
{ "http://www.wireless-village.org/CSP", 0x05 },
{ "http://www.wireless-village.org/PA", 0x06 },
{ "http://www.wireless-village.org/TRC", 0x07 },
{ "http://www.openmobilealliance.org/DTD/WV-CSP", 0x08 },
{ "http://www.openmobilealliance.org/DTD/WV-PA", 0x09 },
{ "http://www.openmobilealliance.org/DTD/WV-TRC", 0x0a },
{ "http://www.openmobilealliance.org/DTD/IMPS-CSP", 0x0b },
{ "http://www.openmobilealliance.org/DTD/IMPS-PA", 0x0c },
{ "http://www.openmobilealliance.org/DTD/IMPS-TRC", 0x0d },
};
static bool isDatetimeElement(const char *name)
{
return (strcmp("DateTime", name) == 0 || strcmp("DeliveryTime", name) == 0);
}
void ImpsWbxmlEncoder::reset()
{
clearResult();
mTagCodePage = 0;
mCurrElement.clear();
mDepth = 0;
}
EncoderError ImpsWbxmlEncoder::startElement(const char *name, const char **atts)
{
if (name == NULL) {
return ERROR_INVALID_DATA;
}
bool isUnknownTag = false;
int stag = csp13TagNameToKey(name);
if (stag == -1) {
stag = TOKEN_LITERAL;
isUnknownTag = true;
}
mDepth++;
mCurrElement = name;
if (((stag >> 8) & 0xff) != mTagCodePage) {
// SWITCH_PAGE
mTagCodePage = (stag >> 8) & 0xff;
appendResult(TOKEN_SWITCH_PAGE);
appendResult(mTagCodePage);
}
stag &= 0xff;
stag |= 0x40; // TODO: assuming we always have content
if (atts && atts[0]) {
stag |= 0x80; // has attribute
}
appendResult(stag);
if (isUnknownTag) {
int index = appendToStringTable(name);
encodeMbuint(index);
}
if (stag & 0x80) {
for (size_t i = 0; atts[i]; i += 2) {
EncoderError err = encodeAttrib(atts[i], atts[i + 1]);
if (err != NO_ERROR) {
return err;
}
}
appendResult(TOKEN_END);
}
return NO_ERROR;
}
EncoderError ImpsWbxmlEncoder::characters(const char *chars, int len)
{
if (chars == NULL || len < 0) {
return ERROR_INVALID_DATA;
}
if (!len) {
return NO_ERROR;
}
while (len && isXmlWhitespace(*chars)) {
chars++;
len--;
}
while (len && isXmlWhitespace(chars[len - 1])) {
len--;
}
if (!len) {
return NO_ERROR;
}
if (csp13IsIntegerTag(mCurrElement.c_str())) {
return encodeInteger(chars, len);
} else if (isDatetimeElement(mCurrElement.c_str())) {
return encodeDatetime(chars, len);
} else {
return encodeString(chars, len);
}
}
EncoderError ImpsWbxmlEncoder::opaque(const char *chars, int len)
{
if (chars == NULL || len < 0) {
return ERROR_INVALID_DATA;
}
if (!len) {
return NO_ERROR;
}
appendResult(TOKEN_OPAQUE);
encodeMbuint((uint32_t)len);
appendResult(chars, len);
return NO_ERROR;
}
EncoderError ImpsWbxmlEncoder::endElement()
{
mDepth--;
if (mDepth < 0) {
return ERROR_INVALID_END_ELEMENT;
}
appendResult(TOKEN_END);
mCurrElement.clear();
if (mDepth == 0) {
sendResult();
}
return NO_ERROR;
}
EncoderError ImpsWbxmlEncoder::encodeString(const char *chars, int len)
{
// FIXME: should match and replace based on tokens (words)
int token = csp13ValueTokenToKey(chars, len);
if (token == -1) {
encodeInlinedStr(chars, len);
} else {
appendResult(TOKEN_EXT_T_0);
encodeMbuint(token);
}
return NO_ERROR;
}
EncoderError ImpsWbxmlEncoder::encodeAttrib(const char *name, const char *value)
{
// IMPS so far has only "xmlns" attribute.
// TODO: rewrite in a more generic way and move this to WbxmlEncoder
if (strcmp(name, "xmlns")) {
return ERROR_UNSUPPORTED_ATTR;
}
int valueLen = strlen(value);
size_t csp13xmlnsCount = sizeof(csp13xmlns) / sizeof(csp13xmlns[0]);
size_t i;
for (i = 0; i < csp13xmlnsCount; i++) {
const char * prefix = csp13xmlns[i].prefix;
int prefixLen = strlen(csp13xmlns[i].prefix);
if (strncmp(prefix, value, prefixLen) == 0) {
appendResult(csp13xmlns[i].attrToken);
if (valueLen > prefixLen) {
encodeInlinedStr(value + prefixLen, valueLen - prefixLen);
}
return NO_ERROR;
}
}
if (i == csp13xmlnsCount) {
// not predefined attribute
appendResult(TOKEN_LITERAL);
int index = appendToStringTable(name);
encodeMbuint(index);
}
encodeInlinedStr(value, valueLen);
return NO_ERROR;
}