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

Side by Side Diff: sms_message.cc

Issue 6740005: Handle UCS-2 data coding scheme for SMS messsages. (Closed) Base URL: ssh://gitrw.chromium.org:9222/cromo.git@master
Patch Set: Remove redundant comparison operations 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 | « no previous file | 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
1 // Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 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 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 #include "sms_message.h" 5 #include "sms_message.h"
6 6
7 #include <glog/logging.h> 7 #include <glog/logging.h>
8 8
9 #include "utilities.h" 9 #include "utilities.h"
10 10
11 static const uint8_t INTL_E164_NUMBER_FORMAT = 0x91; 11 static const uint8_t kIntlE164NumberFormat = 0x91;
12 static const uint8_t SMSC_TIMESTAMP_LEN = 7; 12 static const uint8_t kAlphaFormat = 0xd0;
13 static const size_t MIN_PDU_LEN = 7 + SMSC_TIMESTAMP_LEN; 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;
14 17
15 static char NibbleToChar(uint8_t nibble) { 18 static char NibbleToChar(uint8_t nibble) {
16 switch (nibble) { 19 switch (nibble) {
17 case 0: return '0'; 20 case 0: return '0';
18 case 1: return '1'; 21 case 1: return '1';
19 case 2: return '2'; 22 case 2: return '2';
20 case 3: return '3'; 23 case 3: return '3';
21 case 4: return '4'; 24 case 4: return '4';
22 case 5: return '5'; 25 case 5: return '5';
23 case 6: return '6'; 26 case 6: return '6';
(...skipping 27 matching lines...) Expand all
51 if (second != '\0') 54 if (second != '\0')
52 bcd += second; 55 bcd += second;
53 } 56 }
54 return bcd; 57 return bcd;
55 } 58 }
56 59
57 SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) { 60 SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) {
58 utilities::DumpHex(pdu, pdu_len); 61 utilities::DumpHex(pdu, pdu_len);
59 62
60 // Make sure the PDU is of a valid size 63 // Make sure the PDU is of a valid size
61 if (pdu_len < MIN_PDU_LEN) { 64 if (pdu_len < kMinPduLen) {
62 LOG(INFO) << "PDU too short: " << pdu_len << " vs. " << MIN_PDU_LEN; 65 LOG(INFO) << "PDU too short: " << pdu_len << " vs. " << kMinPduLen;
63 return NULL; 66 return NULL;
64 } 67 }
65 68
66 // Format of message: 69 // Format of message:
67 // 70 //
68 // 1 octet - length of SMSC information in octets, including type field 71 // 1 octet - length of SMSC information in octets, including type field
69 // 1 octet - type of address of SMSC (value 0x91 is international E.164) 72 // 1 octet - type of address of SMSC (value 0x91 is international E.164)
70 // variable - SMSC address 73 // variable - SMSC address
71 // 1 octet - first octet of SMS-DELIVER (value = 0x04) 74 // 1 octet - first octet of SMS-DELIVER (value = 0x04)
72 // 1 octet - length of sender address in decimal digits (semi-octets) 75 // 1 octet - length of sender address in decimal digits (semi-octets)
73 // 1 octet - type of sender address (value 0x91 is international E.164) 76 // 1 octet - type of sender address (value 0x91 is international E.164)
74 // variable - sender address 77 // variable - sender address
75 // 1 octet - protocol identifier (value = 0) 78 // 1 octet - protocol identifier (value = 0)
76 // 1 octet - data coding scheme (value = 0) 79 // 1 octet - data coding scheme (value 0 is GSM7, 8 is UCS2)
77 // 7 octets - SMSC timestamp 80 // 7 octets - SMSC timestamp
78 // 1 octet - user data length in septets 81 // 1 octet - user data length in septets
79 // variable - user data (body of message) 82 // variable - user data (body of message)
80 83
81 // Do a bunch of validity tests first so we can bail out early 84 // Do a bunch of validity tests first so we can bail out early
82 // if we're not able to handle the PDU. We first check the validity 85 // if we're not able to handle the PDU. We first check the validity
83 // of all length fields and make sure the PDU length is consistent 86 // of all length fields and make sure the PDU length is consistent
84 // with those values. 87 // with those values.
85 88
86 uint8_t smsc_addr_num_octets = pdu[0]; 89 uint8_t smsc_addr_num_octets = pdu[0];
87 uint8_t variable_length_items = smsc_addr_num_octets; 90 uint8_t variable_length_items = smsc_addr_num_octets;
88 91
89 if (pdu_len < variable_length_items + MIN_PDU_LEN) { 92 if (pdu_len < variable_length_items + kMinPduLen) {
90 LOG(INFO) << "PDU too short: " << pdu_len << " vs. " 93 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
91 << variable_length_items + MIN_PDU_LEN; 94 << variable_length_items + kMinPduLen;
92 return NULL; 95 return NULL;
93 } 96 }
94 97
95 // where in the PDU the actual SMS protocol message begins 98 // where in the PDU the actual SMS protocol message begins
96 uint8_t msg_start_offset = 1 + smsc_addr_num_octets; 99 uint8_t msg_start_offset = 1 + smsc_addr_num_octets;
97 uint8_t sender_addr_num_digits = pdu[msg_start_offset + 1]; 100 uint8_t sender_addr_num_digits = pdu[msg_start_offset + 1];
98 // round the sender address length up to an even number of semi-octets, 101 // round the sender address length up to an even number of semi-octets,
99 // and thus an integral number of octets 102 // and thus an integral number of octets
100 uint8_t sender_addr_num_octets = (sender_addr_num_digits + 1) >> 1; 103 uint8_t sender_addr_num_octets = (sender_addr_num_digits + 1) >> 1;
101 variable_length_items += sender_addr_num_octets; 104 variable_length_items += sender_addr_num_octets;
102 if (pdu_len < variable_length_items + MIN_PDU_LEN) { 105 if (pdu_len < variable_length_items + kMinPduLen) {
103 LOG(INFO) << "PDU too short: " << pdu_len << " vs. " 106 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
104 << variable_length_items + MIN_PDU_LEN; 107 << variable_length_items + kMinPduLen;
105 return NULL; 108 return NULL;
106 } 109 }
107 110
108 uint8_t tp_pid_offset = msg_start_offset + 3 + sender_addr_num_octets; 111 uint8_t tp_pid_offset = msg_start_offset + 3 + sender_addr_num_octets;
109 uint8_t user_data_offset = tp_pid_offset + 2 + SMSC_TIMESTAMP_LEN; 112 uint8_t user_data_offset = tp_pid_offset + 2 + kSmscTimestampLen;
110 uint8_t user_data_num_septets = pdu[user_data_offset]; 113 uint8_t user_data_num_septets = pdu[user_data_offset];
111 variable_length_items += (7 * (user_data_num_septets + 1 )) / 8; 114 variable_length_items += (7 * (user_data_num_septets + 1 )) / 8;
112 115
113 if (pdu_len < variable_length_items + MIN_PDU_LEN) { 116 if (pdu_len < variable_length_items + kMinPduLen) {
114 LOG(INFO) << "PDU too short: " << pdu_len << " vs. " 117 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
115 << variable_length_items + MIN_PDU_LEN; 118 << variable_length_items + kMinPduLen;
116 return NULL; 119 return NULL;
117 } 120 }
118 121
119 // wow do some validity checks on the values of several fields in the PDU 122 // now do some validity checks on the values of several fields in the PDU
120 123
121 // smsc number format must be international, E.164 124 // smsc number format must be international, E.164
122 if (pdu[1] != INTL_E164_NUMBER_FORMAT) { 125 if (pdu[1] != kIntlE164NumberFormat) {
123 LOG(INFO) << "Invalid SMSC address format: " << std::hex << (int)pdu[1] 126 LOG(INFO) << "Invalid SMSC address format: " << std::hex << (int)pdu[1]
124 << " vs. " << std::hex << INTL_E164_NUMBER_FORMAT; 127 << " vs. " << std::hex << kIntlE164NumberFormat;
125 return NULL; 128 return NULL;
126 } 129 }
127 // we only handle SMS-DELIVER messages, with more-messages-to-send false 130 // we only handle SMS-DELIVER messages, with more-messages-to-send false
128 if ((pdu[msg_start_offset] & 0x07) != 0x04) { 131 if ((pdu[msg_start_offset] & 0x07) != 0x04) {
129 LOG(INFO) << "Unhandled message type: " << std::hex 132 LOG(INFO) << "Unhandled message type: " << std::hex
130 << (int)pdu[msg_start_offset] << " vs. 0x04"; 133 << (int)pdu[msg_start_offset] << " vs. 0x04";
131 return NULL; 134 return NULL;
132 } 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 }
133 // we only handle the basic protocol identifier 144 // we only handle the basic protocol identifier
134 if (pdu[tp_pid_offset] != 0) { 145 if (pdu[tp_pid_offset] != 0) {
135 LOG(INFO) << "Unhandled protocol identifier: " << std::hex 146 LOG(INFO) << "Unhandled protocol identifier: " << std::hex
136 << (int)pdu[tp_pid_offset] << " vs. 0x00"; 147 << (int)pdu[tp_pid_offset] << " vs. 0x00";
137 return NULL; 148 return NULL;
138 } 149 }
139 // for data coding scheme, we only handle the default alphabet, i.e. GSM7 150 // for data coding scheme, we only handle the default alphabet, i.e. GSM7
140 if (pdu[tp_pid_offset+1] != 0) { 151 uint8_t dcs = pdu[tp_pid_offset+1] & 0x0ec;
152 if (dcs != kDataCodingSchemeGsm7 && dcs != kDataCodingSchemeUcs2) {
141 LOG(INFO) << "Unhandled data coding scheme: " << std::hex 153 LOG(INFO) << "Unhandled data coding scheme: " << std::hex
142 << (int)pdu[tp_pid_offset+1] << " vs. 0x00"; 154 << (int)pdu[tp_pid_offset+1];
143 return NULL; 155 return NULL;
144 } 156 }
145 157
146 std::string smsc_addr = SemiOctetsToBcdString(&pdu[2], 158 std::string smsc_addr = SemiOctetsToBcdString(&pdu[2],
147 smsc_addr_num_octets-1); 159 smsc_addr_num_octets-1);
148 std::string sender_addr = SemiOctetsToBcdString(&pdu[msg_start_offset+3], 160 std::string sender_addr;
149 sender_addr_num_octets); 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
150 std::string sc_timestamp = SemiOctetsToBcdString(&pdu[tp_pid_offset+2], 172 std::string sc_timestamp = SemiOctetsToBcdString(&pdu[tp_pid_offset+2],
151 SMSC_TIMESTAMP_LEN-1); 173 kSmscTimestampLen-1);
152 std::string msg_text = utilities::Gsm7ToUtf8String(&pdu[user_data_offset]); 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]);
153 179
154 // The last two semi-octets of the timestamp indicate an offset from 180 // The last two semi-octets of the timestamp indicate an offset from
155 // GMT, and are handled differently than the first 12 semi-octets. 181 // GMT, and are handled differently than the first 12 semi-octets.
156 uint8_t toff_octet = pdu[tp_pid_offset+1+SMSC_TIMESTAMP_LEN]; 182 uint8_t toff_octet = pdu[tp_pid_offset+1+kSmscTimestampLen];
157 sc_timestamp += (toff_octet & 0x8) ? '-' : '+'; 183 sc_timestamp += (toff_octet & 0x8) ? '-' : '+';
158 uint8_t offset_in_hours = 184 uint8_t offset_in_hours =
159 ((toff_octet & 0x7) << 4 | (toff_octet & 0xf0) >> 4) / 4; 185 ((toff_octet & 0x7) << 4 | (toff_octet & 0xf0) >> 4) / 4;
160 sc_timestamp += (char)((offset_in_hours / 10) + '0'); 186 sc_timestamp += (char)((offset_in_hours / 10) + '0');
161 sc_timestamp += (char)((offset_in_hours % 10) + '0'); 187 sc_timestamp += (char)((offset_in_hours % 10) + '0');
162 188
163 return new SmsMessage(smsc_addr, sender_addr, sc_timestamp, msg_text); 189 return new SmsMessage(smsc_addr, sender_addr, sc_timestamp, msg_text);
164 } 190 }
OLDNEW
« no previous file with comments | « no previous file | sms_message_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698