Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2007 Esmertec AG.
      3  * Copyright (C) 2007 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 #include "csp13_hash.h"
     22 
     23 /* TODOs:
     24  * - use string table?
     25  * - move common WBXML routines to WbxmlEncoder
     26  * - so called "token" based IMPS value encoding
     27  */
     28 
     29 struct XmlnsPrefix {
     30     const char * prefix;
     31     int attrToken;
     32 };
     33 static const XmlnsPrefix csp13xmlns[] = {
     34     { "http://www.wireless-village.org/CSP",        0x05 },
     35     { "http://www.wireless-village.org/PA",         0x06 },
     36     { "http://www.wireless-village.org/TRC",        0x07 },
     37     { "http://www.openmobilealliance.org/DTD/WV-CSP",   0x08 },
     38     { "http://www.openmobilealliance.org/DTD/WV-PA",    0x09 },
     39     { "http://www.openmobilealliance.org/DTD/WV-TRC",   0x0a },
     40     { "http://www.openmobilealliance.org/DTD/IMPS-CSP", 0x0b },
     41     { "http://www.openmobilealliance.org/DTD/IMPS-PA",  0x0c },
     42     { "http://www.openmobilealliance.org/DTD/IMPS-TRC", 0x0d },
     43 };
     44 
     45 static bool isDatetimeElement(const char *name)
     46 {
     47     return (strcmp("DateTime", name) == 0 || strcmp("DeliveryTime", name) == 0);
     48 }
     49 
     50 void ImpsWbxmlEncoder::reset()
     51 {
     52     clearResult();
     53 
     54     mTagCodePage = 0;
     55     mCurrElement.clear();
     56     mDepth = 0;
     57 }
     58 
     59 EncoderError ImpsWbxmlEncoder::startElement(const char *name, const char **atts)
     60 {
     61     if (name == NULL) {
     62         return ERROR_INVALID_DATA;
     63     }
     64 
     65     bool isUnknownTag = false;
     66     int stag = csp13TagNameToKey(name);
     67     if (stag == -1) {
     68         stag = TOKEN_LITERAL;
     69         isUnknownTag = true;
     70     }
     71     mDepth++;
     72     mCurrElement = name;
     73 
     74     if (((stag >> 8) & 0xff) != mTagCodePage) {
     75         // SWITCH_PAGE
     76         mTagCodePage = (stag >> 8) & 0xff;
     77         appendResult(TOKEN_SWITCH_PAGE);
     78         appendResult(mTagCodePage);
     79     }
     80     stag &= 0xff;
     81     stag |= 0x40;       // TODO: assuming we always have content
     82 
     83     if (atts && atts[0]) {
     84         stag |= 0x80;   // has attribute
     85     }
     86     appendResult(stag);
     87 
     88     if (isUnknownTag) {
     89         int index = appendToStringTable(name);
     90         encodeMbuint(index);
     91     }
     92     if (stag & 0x80) {
     93         for (size_t i = 0; atts[i]; i += 2) {
     94             EncoderError err = encodeAttrib(atts[i], atts[i + 1]);
     95             if (err != NO_ERROR) {
     96                 return err;
     97             }
     98         }
     99         appendResult(TOKEN_END);
    100     }
    101     return NO_ERROR;
    102 }
    103 
    104 EncoderError ImpsWbxmlEncoder::characters(const char *chars, int len)
    105 {
    106     if (chars == NULL || len < 0) {
    107         return ERROR_INVALID_DATA;
    108     }
    109     if (!len) {
    110         return NO_ERROR;
    111     }
    112     while (len && isXmlWhitespace(*chars)) {
    113         chars++;
    114         len--;
    115     }
    116     while (len && isXmlWhitespace(chars[len - 1])) {
    117         len--;
    118     }
    119     if (!len) {
    120         return NO_ERROR;
    121     }
    122 
    123     if (csp13IsIntegerTag(mCurrElement.c_str())) {
    124         return encodeInteger(chars, len);
    125     } else if (isDatetimeElement(mCurrElement.c_str())) {
    126         return encodeDatetime(chars, len);
    127     } else {
    128         return encodeString(chars, len);
    129     }
    130 }
    131 
    132 EncoderError ImpsWbxmlEncoder::opaque(const char *chars, int len)
    133 {
    134     if (chars == NULL || len < 0) {
    135         return ERROR_INVALID_DATA;
    136     }
    137     if (!len) {
    138         return NO_ERROR;
    139     }
    140     appendResult(TOKEN_OPAQUE);
    141     encodeMbuint((uint32_t)len);
    142     appendResult(chars, len);
    143     return NO_ERROR;
    144 }
    145 
    146 EncoderError ImpsWbxmlEncoder::endElement()
    147 {
    148     mDepth--;
    149     if (mDepth < 0) {
    150         return ERROR_INVALID_END_ELEMENT;
    151     }
    152     appendResult(TOKEN_END);
    153     mCurrElement.clear();
    154     if (mDepth == 0) {
    155         sendResult();
    156     }
    157     return NO_ERROR;
    158 }
    159 
    160 EncoderError ImpsWbxmlEncoder::encodeString(const char *chars, int len)
    161 {
    162     // FIXME: should match and replace based on tokens (words)
    163     int token = csp13ValueTokenToKey(chars, len);
    164     if (token == -1) {
    165         encodeInlinedStr(chars, len);
    166     } else {
    167         appendResult(TOKEN_EXT_T_0);
    168         encodeMbuint(token);
    169     }
    170     return NO_ERROR;
    171 }
    172 
    173 EncoderError ImpsWbxmlEncoder::encodeAttrib(const char *name, const char *value)
    174 {
    175     // IMPS so far has only "xmlns" attribute.
    176     // TODO: rewrite in a more generic way and move this to WbxmlEncoder
    177     if (strcmp(name, "xmlns")) {
    178         return ERROR_UNSUPPORTED_ATTR;
    179     }
    180     int valueLen = strlen(value);
    181     size_t csp13xmlnsCount = sizeof(csp13xmlns) / sizeof(csp13xmlns[0]);
    182     size_t i;
    183     for (i = 0; i < csp13xmlnsCount; i++) {
    184         const char * prefix = csp13xmlns[i].prefix;
    185         int prefixLen = strlen(csp13xmlns[i].prefix);
    186         if (strncmp(prefix, value, prefixLen) == 0) {
    187             appendResult(csp13xmlns[i].attrToken);
    188             if (valueLen > prefixLen) {
    189                 encodeInlinedStr(value + prefixLen, valueLen - prefixLen);
    190             }
    191             return NO_ERROR;
    192         }
    193     }
    194     if (i == csp13xmlnsCount) {
    195         // not predefined attribute
    196         appendResult(TOKEN_LITERAL);
    197         int index = appendToStringTable(name);
    198         encodeMbuint(index);
    199     }
    200     encodeInlinedStr(value, valueLen);
    201     return NO_ERROR;
    202 }
    203