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
isDatetimeElement(const char * name)45 static bool isDatetimeElement(const char *name)
46 {
47 return (strcmp("DateTime", name) == 0 || strcmp("DeliveryTime", name) == 0);
48 }
49
reset()50 void ImpsWbxmlEncoder::reset()
51 {
52 clearResult();
53
54 mTagCodePage = 0;
55 mCurrElement.clear();
56 mDepth = 0;
57 }
58
startElement(const char * name,const char ** atts)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
characters(const char * chars,int len)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
opaque(const char * chars,int len)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
endElement()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
encodeString(const char * chars,int len)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
encodeAttrib(const char * name,const char * value)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