OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Plugin tests link against this file, but not against the rest of | 5 // Plugin tests link against this file, but not against the rest of |
6 // cromo. Therefore this file should not have dependencies on the | 6 // cromo. Therefore this file should not have dependencies on the |
7 // rest of cromo. | 7 // rest of cromo. |
8 #include "utilities.h" | 8 #include "utilities.h" |
9 | 9 |
10 #include <glog/logging.h> | 10 #include <glog/logging.h> |
11 #include <stdio.h> | 11 #include <stdio.h> |
12 #include <stdlib.h> | 12 #include <stdlib.h> |
13 | 13 |
| 14 #include <iomanip> |
| 15 #include <sstream> |
| 16 |
14 namespace utilities { | 17 namespace utilities { |
15 | 18 |
16 const char *ExtractString(const DBusPropertyMap properties, | 19 const char* ExtractString(const DBusPropertyMap properties, |
17 const char *key, | 20 const char* key, |
18 const char *not_found_response, | 21 const char* not_found_response, |
19 DBus::Error &error) { | 22 DBus::Error& error) { |
20 DBusPropertyMap::const_iterator p; | 23 DBusPropertyMap::const_iterator p; |
21 const char *to_return = not_found_response; | 24 const char* to_return = not_found_response; |
22 try { | 25 try { |
23 p = properties.find(key); | 26 p = properties.find(key); |
24 if (p != properties.end()) { | 27 if (p != properties.end()) { |
25 to_return = p->second.reader().get_string(); | 28 to_return = p->second.reader().get_string(); |
26 } | 29 } |
27 } catch (const DBus::Error &e) { | 30 } catch (const DBus::Error& e) { |
28 LOG(ERROR)<<"Bad type for: " << key; | 31 LOG(ERROR)<<"Bad type for: " << key; |
29 // Setting an already-set error causes an assert fail inside dbus-c++. | 32 // Setting an already-set error causes an assert fail inside dbus-c++. |
30 if (!error.is_set()) { | 33 if (!error.is_set()) { |
31 // NB: the copy constructor for DBus::Error causes a template to | 34 // NB: the copy constructor for DBus::Error causes a template to |
32 // be instantiated that kills our -Werror build | 35 // be instantiated that kills our -Werror build |
33 error.set(e.name(), e.message()); | 36 error.set(e.name(), e.message()); |
34 } | 37 } |
35 } | 38 } |
36 return to_return; | 39 return to_return; |
37 } | 40 } |
38 | 41 |
39 uint32_t ExtractUint32(const DBusPropertyMap properties, | 42 uint32_t ExtractUint32(const DBusPropertyMap properties, |
40 const char *key, | 43 const char* key, |
41 uint32_t not_found_response, | 44 uint32_t not_found_response, |
42 DBus::Error &error) { | 45 DBus::Error& error) { |
43 DBusPropertyMap::const_iterator p; | 46 DBusPropertyMap::const_iterator p; |
44 unsigned int to_return = not_found_response; | 47 unsigned int to_return = not_found_response; |
45 try { | 48 try { |
46 p = properties.find(key); | 49 p = properties.find(key); |
47 if (p != properties.end()) { | 50 if (p != properties.end()) { |
48 to_return = p->second.reader().get_uint32(); | 51 to_return = p->second.reader().get_uint32(); |
49 } | 52 } |
50 } catch (const DBus::Error &e) { | 53 } catch (const DBus::Error& e) { |
51 LOG(ERROR)<<"Bad type for: " << key; | 54 LOG(ERROR)<<"Bad type for: " << key; |
52 // Setting an already-set error causes an assert fail inside dbus-c++. | 55 // Setting an already-set error causes an assert fail inside dbus-c++. |
53 if (!error.is_set()) { | 56 if (!error.is_set()) { |
54 // NB: the copy constructor for DBus::Error causes a template to | 57 // NB: the copy constructor for DBus::Error causes a template to |
55 // be instantiated that kills our -Werror build | 58 // be instantiated that kills our -Werror build |
56 error.set(e.name(), e.message()); | 59 error.set(e.name(), e.message()); |
57 } | 60 } |
58 } | 61 } |
59 return to_return; | 62 return to_return; |
60 } | 63 } |
61 | 64 |
62 bool HexEsnToDecimal(const std::string &esn_hex, std::string *out) { | 65 bool HexEsnToDecimal(const std::string& esn_hex, std::string* out) { |
63 size_t length = esn_hex.length(); | 66 size_t length = esn_hex.length(); |
64 if (length > 8) { | 67 if (length > 8) { |
65 LOG(ERROR) << "Long ESN: " << esn_hex; | 68 LOG(ERROR) << "Long ESN: " << esn_hex; |
66 return false; | 69 return false; |
67 } | 70 } |
68 errno = 0; | 71 errno = 0; |
69 const char *start = esn_hex.c_str(); | 72 const char* start = esn_hex.c_str(); |
70 char *end; | 73 char* end; |
71 uint32_t esn = strtoul(start, &end, 16); | 74 uint32_t esn = strtoul(start, &end, 16); |
72 if (errno != 0 || *end != '\0') { | 75 if (errno != 0 || *end != '\0') { |
73 LOG(ERROR) << "Bad ESN: " << esn_hex; | 76 LOG(ERROR) << "Bad ESN: " << esn_hex; |
74 return false; | 77 return false; |
75 } | 78 } |
76 uint32_t mfr = (esn >> 24) & 0xff; | 79 uint32_t mfr = (esn >> 24) & 0xff; |
77 uint32_t serial = esn & 0x00ffffff; | 80 uint32_t serial = esn & 0x00ffffff; |
78 | 81 |
79 // Decimal ESN is 11 chars | 82 // Decimal ESN is 11 chars |
80 char decimal[12]; | 83 char decimal[12]; |
81 memset(decimal, '\0', sizeof(decimal)); | 84 memset(decimal, '\0', sizeof(decimal)); |
82 int rc = snprintf(decimal, sizeof(decimal), "%03d%08d", mfr, serial); | 85 int rc = snprintf(decimal, sizeof(decimal), "%03d%08d", mfr, serial); |
83 if (rc != 11) { | 86 if (rc != 11) { |
84 LOG(ERROR) << "Format failure"; | 87 LOG(ERROR) << "Format failure"; |
85 return false; | 88 return false; |
86 } | 89 } |
87 if (out) { | 90 if (out) { |
88 *out = decimal; | 91 *out = decimal; |
89 } | 92 } |
90 return true; | 93 return true; |
91 } | 94 } |
| 95 |
| 96 #define C(c) {c} |
| 97 #define C2(c) {0xc2, c} |
| 98 #define C3(c) {0xc3, c} |
| 99 #define CE(c) {0xce, c} |
| 100 |
| 101 static uint8_t Gsm7ToUtf8Map[][3] = { |
| 102 C('@'), C2(0xa3), C('$'), C2(0xa5), C3(0xa8), C3(0xa9), C3(0xb9), C3(0xac), |
| 103 C3(0xb2), C3(0x87), C('\n'), C3(0x98), C3(0xb8), C('\r'), C3(0x85), C3(0xa5), |
| 104 CE(0x94), C('_'), CE(0xa6), CE(0x93), CE(0x9b), CE(0xa9), CE(0xa0), CE(0xa8), |
| 105 CE(0xa3), CE(0x98), CE(0x9e), C(' '), C3(0x86), C3(0xa6), C3(0x9f), C3(0x89), |
| 106 C(' '), C('!'), C('"'), C('#'), C2(0xa4), C('%'), C('&'), C('\''), |
| 107 C('('), C(')'), C('*'), C('+'), C(','), C('-'), C('.'), C('/'), |
| 108 C('0'), C('1'), C('2'), C('3'), C('4'), C('5'), C('6'), C('7'), |
| 109 C('8'), C('9'), C(':'), C(';'), C('<'), C('='), C('>'), C('?'), |
| 110 C2(0xa1), C('A'), C('B'), C('C'), C('D'), C('E'), C('F'), C('G'), |
| 111 C('H'), C('I'), C('J'), C('K'), C('L'), C('M'), C('N'), C('O'), |
| 112 C('P'), C('Q'), C('R'), C('S'), C('T'), C('U'), C('V'), C('W'), |
| 113 C('X'), C('Y'), C('Z'), C3(0x84), C3(0x96), C3(0x91), C3(0x9c), C2(0xa7), |
| 114 C2(0xbf), C('a'), C('b'), C('c'), C('d'), C('e'), C('f'), C('g'), |
| 115 C('h'), C('i'), C('j'), C('k'), C('l'), C('m'), C('n'), C('o'), |
| 116 C('p'), C('q'), C('r'), C('s'), C('t'), C('u'), C('v'), C('w'), |
| 117 C('x'), C('y'), C('z'), C3(0xa4), C3(0xb6), C3(0xb1), C3(0xbc), C3(0xa0) |
| 118 }; |
| 119 |
| 120 // 2nd dimension == 5 ensures that all the sub-arrays end with a 0 byte |
| 121 static uint8_t ExtGsm7ToUtf8Map[][5] = { |
| 122 {0x0a, 0xc}, |
| 123 {0x14, '^'}, |
| 124 {0x28, '{'}, |
| 125 {0x29, '}'}, |
| 126 {0x2f, '\\'}, |
| 127 {0x3c, '['}, |
| 128 {0x3d, '~'}, |
| 129 {0x3e, ']'}, |
| 130 {0x40, '|'}, |
| 131 {0x65, 0xe2, 0x82, 0xac} |
| 132 }; |
| 133 |
| 134 static std::map<std::pair<uint8_t, uint8_t>,char> Utf8ToGsm7Map; |
| 135 |
| 136 /* |
| 137 * Convert a packed GSM7 encoded string to UTF-8 by first unpacking |
| 138 * the string into septets, then mapping each character to its UTF-8 |
| 139 * equivalent. |
| 140 */ |
| 141 std::string Gsm7ToUtf8String(const uint8_t* gsm7) { |
| 142 size_t datalen = *gsm7++; |
| 143 uint8_t* septets = new uint8_t[datalen]; |
| 144 uint8_t saved_bits = 0; |
| 145 size_t written = 0; |
| 146 uint8_t* cp = septets; |
| 147 int i = 0; |
| 148 |
| 149 // unpack |
| 150 while (written < datalen) { |
| 151 for (int j = 0; written < datalen && j < 7; j++) { |
| 152 uint8_t octet = gsm7[i]; |
| 153 uint8_t mask = 0xff >> (j + 1); |
| 154 uint8_t c = ((octet & mask) << j) | saved_bits; |
| 155 *cp++ = c; |
| 156 ++written; |
| 157 saved_bits = (octet & ~mask) >> (7 - j); |
| 158 ++i; |
| 159 } |
| 160 if (written < datalen) { |
| 161 *cp++ = saved_bits; |
| 162 ++written; |
| 163 } |
| 164 saved_bits = 0; |
| 165 } |
| 166 int nseptets = cp - septets; |
| 167 cp = septets; |
| 168 |
| 169 // now map the septets into their corresponding UTF-8 characters |
| 170 std::string str; |
| 171 for (i = 0; i < nseptets; ++i, ++cp) { |
| 172 uint8_t* mp = NULL; |
| 173 if (*cp == 0x1b) { |
| 174 ++cp; |
| 175 for (int k = 0; k < 10; k++) { |
| 176 mp = &ExtGsm7ToUtf8Map[k][0]; |
| 177 if (*mp == *cp) { |
| 178 ++mp; |
| 179 ++i; |
| 180 break; |
| 181 } |
| 182 } |
| 183 } else { |
| 184 mp = &Gsm7ToUtf8Map[*cp][0]; |
| 185 } |
| 186 if (mp != NULL) |
| 187 while (*mp != '\0') |
| 188 str += *mp++; |
| 189 } |
| 190 |
| 191 delete septets; |
| 192 return str; |
| 193 } |
| 194 |
| 195 static void InitializeUtf8ToGsm7Map() { |
| 196 for (int i = 0; i < 128; i++) { |
| 197 Utf8ToGsm7Map[std::pair<uint8_t,uint8_t>(Gsm7ToUtf8Map[i][0], |
| 198 Gsm7ToUtf8Map[i][1])] = i; |
| 199 |
| 200 } |
| 201 } |
| 202 |
| 203 std::vector<uint8_t> Utf8StringToGsm7(const std::string& input) { |
| 204 if (Utf8ToGsm7Map.size() == 0) |
| 205 InitializeUtf8ToGsm7Map(); |
| 206 |
| 207 std::vector<uint8_t> septets; |
| 208 size_t length = input.length(); |
| 209 size_t num_septets = 0; |
| 210 |
| 211 // First map each UTF-8 character to its GSM7 equivalent. |
| 212 for (size_t i = 0; i < length; i++) { |
| 213 std::pair<uint8_t, uint8_t> chpair; |
| 214 char ch = input.at(i); |
| 215 uint8_t thirdch = 0xff; |
| 216 // Check whether this is a one byte UTF-8 sequence, or the |
| 217 // start of a two or three byte sequence. |
| 218 if ((ch & 0x80) == 0) { |
| 219 chpair.first = ch; |
| 220 chpair.second = 0; |
| 221 } else if ((ch & 0xe0) == 0xc0) { |
| 222 chpair.first = ch; |
| 223 chpair.second = input.at(++i); |
| 224 } else if ((ch & 0xf0) == 0xe0) { |
| 225 chpair.first = ch; |
| 226 chpair.second = input.at(++i); |
| 227 thirdch = input.at(++i); |
| 228 } |
| 229 std::map<std::pair<uint8_t,uint8_t>, char>::iterator it; |
| 230 it = Utf8ToGsm7Map.find(chpair); |
| 231 if (it != Utf8ToGsm7Map.end()) { |
| 232 septets.push_back(it->second); |
| 233 } else { |
| 234 // not found in the map. search the list of extended characters, |
| 235 // but first handle one special case for the 3-byte Euro sign |
| 236 if (chpair.first == 0xe2 && chpair.second == 0x82 && thirdch == 0xac) { |
| 237 septets.push_back(0x1b); |
| 238 septets.push_back(0x65); |
| 239 } else if (chpair.second == 0) { |
| 240 for (int j = 0; j < 9; ++j) { |
| 241 if (ExtGsm7ToUtf8Map[j][1] == chpair.first) { |
| 242 septets.push_back(0x1b); |
| 243 septets.push_back(ExtGsm7ToUtf8Map[j][0]); |
| 244 } |
| 245 } |
| 246 } |
| 247 } |
| 248 // If character wasn't mapped successfully, insert a space |
| 249 if (septets.size() == num_septets) |
| 250 septets.push_back(' '); |
| 251 num_septets = septets.size(); |
| 252 } |
| 253 |
| 254 // Now pack the septets into octets. The |
| 255 // first byte gives the number of septets. |
| 256 std::vector<uint8_t> octets; |
| 257 |
| 258 octets.push_back(num_septets); |
| 259 int shift = 0; |
| 260 for (size_t k = 0; k < num_septets; ++k) { |
| 261 uint8_t septet = septets.at(k); |
| 262 uint8_t octet; |
| 263 if (shift != 7) { |
| 264 octet = (septet >> shift); |
| 265 if (k < num_septets - 1) |
| 266 octet |= septets.at(k+1) << (7-shift); |
| 267 octets.push_back(octet); |
| 268 } |
| 269 if (++shift == 8) |
| 270 shift = 0; |
| 271 } |
| 272 |
| 273 return octets; |
| 274 } |
| 275 |
| 276 void DumpHex(const uint8_t* buf, size_t size) { |
| 277 size_t nlines = (size+15) / 16; |
| 278 size_t limit; |
| 279 |
| 280 for (size_t i = 0; i < nlines; i++) { |
| 281 std::ostringstream ostr; |
| 282 ostr << std::hex; |
| 283 ostr.fill('0'); |
| 284 ostr.width(8); |
| 285 if (i*16 + 16 >= size) |
| 286 limit = size - i*16; |
| 287 else |
| 288 limit = 16; |
| 289 ostr << i*16 << " "; |
| 290 ostr.fill('0'); |
| 291 ostr.width(2); |
| 292 for (size_t j = 0; j < limit; j++) { |
| 293 uint8_t byte = buf[i*16+j]; |
| 294 ostr << std::setw(0) << " " << std::setw(2) << std::setfill('0') |
| 295 << static_cast<unsigned int>(byte); |
| 296 } |
| 297 LOG(INFO) << ostr.str(); |
| 298 } |
| 299 } |
| 300 |
92 } // namespace utilities | 301 } // namespace utilities |
OLD | NEW |