Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: sms_message.cc

Issue 6822060: Handle UCS-2 data coding scheme for SMS messsages. (Closed) Base URL: ssh://gitrw.chromium.org:9222/cromo.git@11.1.241.B
Patch Set: Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sms_message.h ('k') | sms_message_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sms_message.h"
6
7 #include <glog/logging.h>
8
9 #include "utilities.h"
10
11 static const uint8_t kIntlE164NumberFormat = 0x91;
12 static const uint8_t kAlphaFormat = 0xd0;
13 static const uint8_t kDataCodingSchemeGsm7 = 0;
14 static const uint8_t kDataCodingSchemeUcs2 = 8;
15 static const uint8_t kSmscTimestampLen = 7;
16 static const size_t kMinPduLen = 7 + kSmscTimestampLen;
17
18 static char NibbleToChar(uint8_t nibble) {
19 switch (nibble) {
20 case 0: return '0';
21 case 1: return '1';
22 case 2: return '2';
23 case 3: return '3';
24 case 4: return '4';
25 case 5: return '5';
26 case 6: return '6';
27 case 7: return '7';
28 case 8: return '8';
29 case 9: return '9';
30 case 10: return '*';
31 case 11: return '#';
32 case 12: return 'a';
33 case 13: return 'b';
34 case 14: return 'c';
35 case 0xff: return '\0'; // padding nibble
36 }
37 return '\0';
38 }
39
40 // Convert an array of octets into a BCD string. Each octet consists
41 // of two nibbles which are converted to hex characters. Those hex
42 // characters are the digits of the BCD string. The lower nibble is
43 // the more significant digit.
44 static std::string SemiOctetsToBcdString(const uint8_t* octets,
45 int num_octets) {
46 std::string bcd;
47
48 for (int i = 0; i < num_octets; ++i) {
49 char first = NibbleToChar(octets[i] & 0xf);
50 char second = NibbleToChar((octets[i] >> 4) & 0xf);
51
52 if (first != '\0')
53 bcd += first;
54 if (second != '\0')
55 bcd += second;
56 }
57 return bcd;
58 }
59
60 SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) {
61 utilities::DumpHex(pdu, pdu_len);
62
63 // Make sure the PDU is of a valid size
64 if (pdu_len < kMinPduLen) {
65 LOG(INFO) << "PDU too short: " << pdu_len << " vs. " << kMinPduLen;
66 return NULL;
67 }
68
69 // Format of message:
70 //
71 // 1 octet - length of SMSC information in octets, including type field
72 // 1 octet - type of address of SMSC (value 0x91 is international E.164)
73 // variable - SMSC address
74 // 1 octet - first octet of SMS-DELIVER (value = 0x04)
75 // 1 octet - length of sender address in decimal digits (semi-octets)
76 // 1 octet - type of sender address (value 0x91 is international E.164)
77 // variable - sender address
78 // 1 octet - protocol identifier (value = 0)
79 // 1 octet - data coding scheme (value 0 is GSM7, 8 is UCS2)
80 // 7 octets - SMSC timestamp
81 // 1 octet - user data length in septets
82 // variable - user data (body of message)
83
84 // Do a bunch of validity tests first so we can bail out early
85 // if we're not able to handle the PDU. We first check the validity
86 // of all length fields and make sure the PDU length is consistent
87 // with those values.
88
89 uint8_t smsc_addr_num_octets = pdu[0];
90 uint8_t variable_length_items = smsc_addr_num_octets;
91
92 if (pdu_len < variable_length_items + kMinPduLen) {
93 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
94 << variable_length_items + kMinPduLen;
95 return NULL;
96 }
97
98 // where in the PDU the actual SMS protocol message begins
99 uint8_t msg_start_offset = 1 + smsc_addr_num_octets;
100 uint8_t sender_addr_num_digits = pdu[msg_start_offset + 1];
101 // round the sender address length up to an even number of semi-octets,
102 // and thus an integral number of octets
103 uint8_t sender_addr_num_octets = (sender_addr_num_digits + 1) >> 1;
104 variable_length_items += sender_addr_num_octets;
105 if (pdu_len < variable_length_items + kMinPduLen) {
106 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
107 << variable_length_items + kMinPduLen;
108 return NULL;
109 }
110
111 uint8_t tp_pid_offset = msg_start_offset + 3 + sender_addr_num_octets;
112 uint8_t user_data_offset = tp_pid_offset + 2 + kSmscTimestampLen;
113 uint8_t user_data_num_septets = pdu[user_data_offset];
114 variable_length_items += (7 * (user_data_num_septets + 1 )) / 8;
115
116 if (pdu_len < variable_length_items + kMinPduLen) {
117 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
118 << variable_length_items + kMinPduLen;
119 return NULL;
120 }
121
122 // now do some validity checks on the values of several fields in the PDU
123
124 // smsc number format must be international, E.164
125 if (pdu[1] != kIntlE164NumberFormat) {
126 LOG(INFO) << "Invalid SMSC address format: " << std::hex << (int)pdu[1]
127 << " vs. " << std::hex << kIntlE164NumberFormat;
128 return NULL;
129 }
130 // we only handle SMS-DELIVER messages, with more-messages-to-send false
131 if ((pdu[msg_start_offset] & 0x07) != 0x04) {
132 LOG(INFO) << "Unhandled message type: " << std::hex
133 << (int)pdu[msg_start_offset] << " vs. 0x04";
134 return NULL;
135 }
136 // we only handle E164 and ALPHA sender address formats
137 uint8_t sender_addr_type = pdu[msg_start_offset + 2];
138 if (sender_addr_type != kIntlE164NumberFormat &&
139 sender_addr_type != kAlphaFormat) {
140 LOG(INFO) << "Unhandled sender address format: " << std::hex <<
141 sender_addr_type;
142 return NULL;
143 }
144 // we only handle the basic protocol identifier
145 if (pdu[tp_pid_offset] != 0) {
146 LOG(INFO) << "Unhandled protocol identifier: " << std::hex
147 << (int)pdu[tp_pid_offset] << " vs. 0x00";
148 return NULL;
149 }
150 // for data coding scheme, we only handle the default alphabet, i.e. GSM7
151 uint8_t dcs = pdu[tp_pid_offset+1] & 0x0ec;
152 if (dcs != kDataCodingSchemeGsm7 && dcs != kDataCodingSchemeUcs2) {
153 LOG(INFO) << "Unhandled data coding scheme: " << std::hex
154 << (int)pdu[tp_pid_offset+1];
155 return NULL;
156 }
157
158 std::string smsc_addr = SemiOctetsToBcdString(&pdu[2],
159 smsc_addr_num_octets-1);
160 std::string sender_addr;
161 if (sender_addr_type == kIntlE164NumberFormat)
162 sender_addr = SemiOctetsToBcdString(&pdu[msg_start_offset+3],
163 sender_addr_num_octets);
164 else {
165 uint8_t *bytes = new uint8_t[sender_addr_num_octets+1];
166 bytes[0] = (sender_addr_num_digits * 4) / 7;
167 memcpy(&bytes[1], &pdu[msg_start_offset+3], sender_addr_num_octets);
168 sender_addr = utilities::Gsm7ToUtf8String(bytes);
169 delete [] bytes;
170 }
171
172 std::string sc_timestamp = SemiOctetsToBcdString(&pdu[tp_pid_offset+2],
173 kSmscTimestampLen-1);
174 std::string msg_text;
175 if (dcs == kDataCodingSchemeGsm7)
176 msg_text = utilities::Gsm7ToUtf8String(&pdu[user_data_offset]);
177 else
178 msg_text = utilities::Ucs2ToUtf8String(&pdu[user_data_offset]);
179
180 // The last two semi-octets of the timestamp indicate an offset from
181 // GMT, and are handled differently than the first 12 semi-octets.
182 uint8_t toff_octet = pdu[tp_pid_offset+1+kSmscTimestampLen];
183 sc_timestamp += (toff_octet & 0x8) ? '-' : '+';
184 uint8_t offset_in_hours =
185 ((toff_octet & 0x7) << 4 | (toff_octet & 0xf0) >> 4) / 4;
186 sc_timestamp += (char)((offset_in_hours / 10) + '0');
187 sc_timestamp += (char)((offset_in_hours % 10) + '0');
188
189 return new SmsMessage(smsc_addr, sender_addr, sc_timestamp, msg_text);
190 }
OLDNEW
« no previous file with comments | « sms_message.h ('k') | sms_message_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698