1 /*
2 * Copyright (C) 2009 Esmertec AG.
3 * Copyright (C) 2009 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
isXmlWhitespace(int ch)22 bool WbxmlEncoder::isXmlWhitespace(int ch)
23 {
24 return ch == ' ' || ch == 9 || ch == 0xd || ch == 0xa;
25 }
26
parseUint(const char * s,int len,uint32_t * res)27 bool WbxmlEncoder::parseUint(const char * s, int len, uint32_t *res)
28 {
29 string str(s, len);
30 char *end;
31 long long val = strtoll(str.c_str(), &end, 10);
32 if (*end != 0 || val < 0 || val > 0xFFFFFFFFU) {
33 return false;
34 }
35 *res = (uint32_t)val;
36 return true;
37 }
38
encodeInteger(const char * chars,int len)39 EncoderError WbxmlEncoder::encodeInteger(const char *chars, int len)
40 {
41 uint32_t val;
42 if (!parseUint(chars, len, &val)) {
43 return ERROR_INVALID_INTEGER_VALUE;
44 }
45
46 appendResult(TOKEN_OPAQUE);
47 uint32_t mask = 0xff000000U;
48 int numBytes = 4;
49 while (!(val & mask) && mask) {
50 numBytes--;
51 mask >>= 8;
52 }
53 if (!numBytes) {
54 // Zero value. We generate at least 1 byte OPAQUE data.
55 // libwbxml2 generates 0 byte long OPAQUE data (0xC3 0x00) in this case.
56 numBytes = 1;
57 }
58
59 appendResult(numBytes);
60 while (numBytes) {
61 numBytes--;
62 appendResult((val >> (numBytes * 8)) & 0xff);
63 }
64
65 return NO_ERROR;
66 }
67
encodeDatetime(const char * chars,int len)68 EncoderError WbxmlEncoder::encodeDatetime(const char *chars, int len)
69 {
70 // to make life easier we accept only yyyymmddThhmmssZ
71 if (len != 16 || chars[8] != 'T' || chars[15] != 'Z') {
72 return ERROR_INVALID_DATETIME_VALUE;
73 }
74 appendResult(TOKEN_OPAQUE);
75 appendResult(6);
76
77 uint32_t year, month, day, hour, min, sec;
78 if (!parseUint(chars, 4, &year)
79 || !parseUint(chars + 4, 2, &month)
80 || !parseUint(chars + 6, 2, &day)
81 || !parseUint(chars + 9, 2, &hour)
82 || !parseUint(chars + 11,2, &min)
83 || !parseUint(chars + 13,2, &sec)) {
84 return ERROR_INVALID_DATETIME_VALUE;
85 }
86 if (year > 4095 || month > 12 || day > 31 || hour > 23 || min > 59 || sec > 59) {
87 return ERROR_INVALID_DATETIME_VALUE;
88 }
89
90 appendResult(year >> 6);
91 appendResult(((year & 0x3f) << 2) | (month >> 2));
92 appendResult(((month & 0x3) << 6) | (day << 1) | (hour >> 4));
93 appendResult(((hour & 0xf) << 4) | (min >> 2));
94 appendResult(((min & 0x2) << 6) | sec);
95 appendResult('Z');
96 return NO_ERROR;
97 }
98
encodeInlinedStr(const char * s,int len)99 void WbxmlEncoder::encodeInlinedStr(const char *s, int len)
100 {
101 // TODO: handle ENTITY
102 appendResult(TOKEN_STR_I);
103 appendResult(s, len);
104 appendResult('\0');
105 }
106
encodeMbuint(uint32_t val)107 void WbxmlEncoder::encodeMbuint(uint32_t val)
108 {
109 char buf[32 / 7 + 1]; // each byte holds up to 7 bits
110 int i = sizeof(buf);
111
112 buf[--i] = val & 0x7f;
113 val >>= 7;
114 while ((i > 0) && (val & 0x7f)) {
115 buf[--i] = 0x80 | (val & 0x7f);
116 val >>= 7;
117 }
118
119 appendResult(buf + i, sizeof(buf) - i);
120 }
121
appendToStringTable(const char * s)122 int WbxmlEncoder::appendToStringTable(const char *s)
123 {
124 int stringTableSize = mStringTable.size();
125 int offset = 0;
126
127 // search the string table to find if the string already exist
128 int index = 0;
129 for (; index < stringTableSize; index++) {
130 if (mStringTable[index] == s) {
131 break;
132 }
133 offset += mStringTable[index].length();
134 ++offset; // '\0' for each string in the table
135 }
136 if (index == stringTableSize) {
137 // not found, insert a new one
138 mStringTable.push_back(s);
139 }
140 return offset;
141 }
142
sendResult()143 void WbxmlEncoder::sendResult()
144 {
145 if (mHandler) {
146 string data;
147 string tmp = mResult;
148 mResult = data;
149
150 // WBXML 1.3, UTF-8
151 char header[3] = { 0x03, (char) mPublicId, 0x6A };
152 appendResult(header, 3);
153
154 // calculate the length of string table
155 int len = 0;
156 for (int i = 0; i < mStringTable.size(); i++) {
157 len += mStringTable[i].length();
158 ++len;
159 }
160
161 encodeMbuint(len);
162
163 // encode each string in the table
164 for (int i = 0; i < mStringTable.size(); i++) {
165 mResult += mStringTable[i];
166 mResult += '\0';
167 }
168
169 mResult += tmp;
170
171 mHandler->wbxmlData(mResult.c_str(), mResult.size());
172 }
173 }
174