Index: utilities.cc |
diff --git a/utilities.cc b/utilities.cc |
index 6d400f62f49f221b794e2a568d4be8830f0c6787..41f6c78c22c42cade00a1538b9880da313eb1ee9 100644 |
--- a/utilities.cc |
+++ b/utilities.cc |
@@ -11,20 +11,23 @@ |
#include <stdio.h> |
#include <stdlib.h> |
+#include <iomanip> |
+#include <sstream> |
+ |
namespace utilities { |
-const char *ExtractString(const DBusPropertyMap properties, |
- const char *key, |
- const char *not_found_response, |
- DBus::Error &error) { |
+const char* ExtractString(const DBusPropertyMap properties, |
+ const char* key, |
+ const char* not_found_response, |
+ DBus::Error& error) { |
DBusPropertyMap::const_iterator p; |
- const char *to_return = not_found_response; |
+ const char* to_return = not_found_response; |
try { |
p = properties.find(key); |
if (p != properties.end()) { |
to_return = p->second.reader().get_string(); |
} |
- } catch (const DBus::Error &e) { |
+ } catch (const DBus::Error& e) { |
LOG(ERROR)<<"Bad type for: " << key; |
// Setting an already-set error causes an assert fail inside dbus-c++. |
if (!error.is_set()) { |
@@ -37,9 +40,9 @@ const char *ExtractString(const DBusPropertyMap properties, |
} |
uint32_t ExtractUint32(const DBusPropertyMap properties, |
- const char *key, |
+ const char* key, |
uint32_t not_found_response, |
- DBus::Error &error) { |
+ DBus::Error& error) { |
DBusPropertyMap::const_iterator p; |
unsigned int to_return = not_found_response; |
try { |
@@ -47,7 +50,7 @@ uint32_t ExtractUint32(const DBusPropertyMap properties, |
if (p != properties.end()) { |
to_return = p->second.reader().get_uint32(); |
} |
- } catch (const DBus::Error &e) { |
+ } catch (const DBus::Error& e) { |
LOG(ERROR)<<"Bad type for: " << key; |
// Setting an already-set error causes an assert fail inside dbus-c++. |
if (!error.is_set()) { |
@@ -59,15 +62,15 @@ uint32_t ExtractUint32(const DBusPropertyMap properties, |
return to_return; |
} |
-bool HexEsnToDecimal(const std::string &esn_hex, std::string *out) { |
+bool HexEsnToDecimal(const std::string& esn_hex, std::string* out) { |
size_t length = esn_hex.length(); |
if (length > 8) { |
LOG(ERROR) << "Long ESN: " << esn_hex; |
return false; |
} |
errno = 0; |
- const char *start = esn_hex.c_str(); |
- char *end; |
+ const char* start = esn_hex.c_str(); |
+ char* end; |
uint32_t esn = strtoul(start, &end, 16); |
if (errno != 0 || *end != '\0') { |
LOG(ERROR) << "Bad ESN: " << esn_hex; |
@@ -89,4 +92,210 @@ bool HexEsnToDecimal(const std::string &esn_hex, std::string *out) { |
} |
return true; |
} |
+ |
+#define C(c) {c} |
+#define C2(c) {0xc2, c} |
+#define C3(c) {0xc3, c} |
+#define CE(c) {0xce, c} |
+ |
+static uint8_t Gsm7ToUtf8Map[][3] = { |
+ C('@'), C2(0xa3), C('$'), C2(0xa5), C3(0xa8), C3(0xa9), C3(0xb9), C3(0xac), |
+ C3(0xb2), C3(0x87), C('\n'), C3(0x98), C3(0xb8), C('\r'), C3(0x85), C3(0xa5), |
+ CE(0x94), C('_'), CE(0xa6), CE(0x93), CE(0x9b), CE(0xa9), CE(0xa0), CE(0xa8), |
+ CE(0xa3), CE(0x98), CE(0x9e), C(' '), C3(0x86), C3(0xa6), C3(0x9f), C3(0x89), |
+ C(' '), C('!'), C('"'), C('#'), C2(0xa4), C('%'), C('&'), C('\''), |
+ C('('), C(')'), C('*'), C('+'), C(','), C('-'), C('.'), C('/'), |
+ C('0'), C('1'), C('2'), C('3'), C('4'), C('5'), C('6'), C('7'), |
+ C('8'), C('9'), C(':'), C(';'), C('<'), C('='), C('>'), C('?'), |
+ C2(0xa1), C('A'), C('B'), C('C'), C('D'), C('E'), C('F'), C('G'), |
+ C('H'), C('I'), C('J'), C('K'), C('L'), C('M'), C('N'), C('O'), |
+ C('P'), C('Q'), C('R'), C('S'), C('T'), C('U'), C('V'), C('W'), |
+ C('X'), C('Y'), C('Z'), C3(0x84), C3(0x96), C3(0x91), C3(0x9c), C2(0xa7), |
+ C2(0xbf), C('a'), C('b'), C('c'), C('d'), C('e'), C('f'), C('g'), |
+ C('h'), C('i'), C('j'), C('k'), C('l'), C('m'), C('n'), C('o'), |
+ C('p'), C('q'), C('r'), C('s'), C('t'), C('u'), C('v'), C('w'), |
+ C('x'), C('y'), C('z'), C3(0xa4), C3(0xb6), C3(0xb1), C3(0xbc), C3(0xa0) |
+}; |
+ |
+// 2nd dimension == 5 ensures that all the sub-arrays end with a 0 byte |
+static uint8_t ExtGsm7ToUtf8Map[][5] = { |
+ {0x0a, 0xc}, |
+ {0x14, '^'}, |
+ {0x28, '{'}, |
+ {0x29, '}'}, |
+ {0x2f, '\\'}, |
+ {0x3c, '['}, |
+ {0x3d, '~'}, |
+ {0x3e, ']'}, |
+ {0x40, '|'}, |
+ {0x65, 0xe2, 0x82, 0xac} |
+}; |
+ |
+static std::map<std::pair<uint8_t, uint8_t>,char> Utf8ToGsm7Map; |
+ |
+/* |
+ * Convert a packed GSM7 encoded string to UTF-8 by first unpacking |
+ * the string into septets, then mapping each character to its UTF-8 |
+ * equivalent. |
+ */ |
+std::string Gsm7ToUtf8String(const uint8_t* gsm7) { |
+ size_t datalen = *gsm7++; |
+ uint8_t* septets = new uint8_t[datalen]; |
+ uint8_t saved_bits = 0; |
+ size_t written = 0; |
+ uint8_t* cp = septets; |
+ int i = 0; |
+ |
+ // unpack |
+ while (written < datalen) { |
+ for (int j = 0; written < datalen && j < 7; j++) { |
+ uint8_t octet = gsm7[i]; |
+ uint8_t mask = 0xff >> (j + 1); |
+ uint8_t c = ((octet & mask) << j) | saved_bits; |
+ *cp++ = c; |
+ ++written; |
+ saved_bits = (octet & ~mask) >> (7 - j); |
+ ++i; |
+ } |
+ if (written < datalen) { |
+ *cp++ = saved_bits; |
+ ++written; |
+ } |
+ saved_bits = 0; |
+ } |
+ int nseptets = cp - septets; |
+ cp = septets; |
+ |
+ // now map the septets into their corresponding UTF-8 characters |
+ std::string str; |
+ for (i = 0; i < nseptets; ++i, ++cp) { |
+ uint8_t* mp = NULL; |
+ if (*cp == 0x1b) { |
+ ++cp; |
+ for (int k = 0; k < 10; k++) { |
+ mp = &ExtGsm7ToUtf8Map[k][0]; |
+ if (*mp == *cp) { |
+ ++mp; |
+ ++i; |
+ break; |
+ } |
+ } |
+ } else { |
+ mp = &Gsm7ToUtf8Map[*cp][0]; |
+ } |
+ if (mp != NULL) |
+ while (*mp != '\0') |
+ str += *mp++; |
+ } |
+ |
+ delete septets; |
+ return str; |
+} |
+ |
+static void InitializeUtf8ToGsm7Map() { |
+ for (int i = 0; i < 128; i++) { |
+ Utf8ToGsm7Map[std::pair<uint8_t,uint8_t>(Gsm7ToUtf8Map[i][0], |
+ Gsm7ToUtf8Map[i][1])] = i; |
+ |
+ } |
+} |
+ |
+std::vector<uint8_t> Utf8StringToGsm7(const std::string& input) { |
+ if (Utf8ToGsm7Map.size() == 0) |
+ InitializeUtf8ToGsm7Map(); |
+ |
+ std::vector<uint8_t> septets; |
+ size_t length = input.length(); |
+ size_t num_septets = 0; |
+ |
+ // First map each UTF-8 character to its GSM7 equivalent. |
+ for (size_t i = 0; i < length; i++) { |
+ std::pair<uint8_t, uint8_t> chpair; |
+ char ch = input.at(i); |
+ uint8_t thirdch = 0xff; |
+ // Check whether this is a one byte UTF-8 sequence, or the |
+ // start of a two or three byte sequence. |
+ if ((ch & 0x80) == 0) { |
+ chpair.first = ch; |
+ chpair.second = 0; |
+ } else if ((ch & 0xe0) == 0xc0) { |
+ chpair.first = ch; |
+ chpair.second = input.at(++i); |
+ } else if ((ch & 0xf0) == 0xe0) { |
+ chpair.first = ch; |
+ chpair.second = input.at(++i); |
+ thirdch = input.at(++i); |
+ } |
+ std::map<std::pair<uint8_t,uint8_t>, char>::iterator it; |
+ it = Utf8ToGsm7Map.find(chpair); |
+ if (it != Utf8ToGsm7Map.end()) { |
+ septets.push_back(it->second); |
+ } else { |
+ // not found in the map. search the list of extended characters, |
+ // but first handle one special case for the 3-byte Euro sign |
+ if (chpair.first == 0xe2 && chpair.second == 0x82 && thirdch == 0xac) { |
+ septets.push_back(0x1b); |
+ septets.push_back(0x65); |
+ } else if (chpair.second == 0) { |
+ for (int j = 0; j < 9; ++j) { |
+ if (ExtGsm7ToUtf8Map[j][1] == chpair.first) { |
+ septets.push_back(0x1b); |
+ septets.push_back(ExtGsm7ToUtf8Map[j][0]); |
+ } |
+ } |
+ } |
+ } |
+ // If character wasn't mapped successfully, insert a space |
+ if (septets.size() == num_septets) |
+ septets.push_back(' '); |
+ num_septets = septets.size(); |
+ } |
+ |
+ // Now pack the septets into octets. The |
+ // first byte gives the number of septets. |
+ std::vector<uint8_t> octets; |
+ |
+ octets.push_back(num_septets); |
+ int shift = 0; |
+ for (size_t k = 0; k < num_septets; ++k) { |
+ uint8_t septet = septets.at(k); |
+ uint8_t octet; |
+ if (shift != 7) { |
+ octet = (septet >> shift); |
+ if (k < num_septets - 1) |
+ octet |= septets.at(k+1) << (7-shift); |
+ octets.push_back(octet); |
+ } |
+ if (++shift == 8) |
+ shift = 0; |
+ } |
+ |
+ return octets; |
+} |
+ |
+void DumpHex(const uint8_t* buf, size_t size) { |
+ size_t nlines = (size+15) / 16; |
+ size_t limit; |
+ |
+ for (size_t i = 0; i < nlines; i++) { |
+ std::ostringstream ostr; |
+ ostr << std::hex; |
+ ostr.fill('0'); |
+ ostr.width(8); |
+ if (i*16 + 16 >= size) |
+ limit = size - i*16; |
+ else |
+ limit = 16; |
+ ostr << i*16 << " "; |
+ ostr.fill('0'); |
+ ostr.width(2); |
+ for (size_t j = 0; j < limit; j++) { |
+ uint8_t byte = buf[i*16+j]; |
+ ostr << std::setw(0) << " " << std::setw(2) << std::setfill('0') |
+ << static_cast<unsigned int>(byte); |
+ } |
+ LOG(INFO) << ostr.str(); |
+ } |
+} |
+ |
} // namespace utilities |