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