/* * 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; }