PduParser 类是 package com.android.internal.telephony.gsm; 下 public class SmsMessage extends SmsMessageBase 的嵌套类。
简单的说, 就是 PduParser 是 SmsMessage 类中所嵌套的类。 而 SmsMessage 又是 SmsMessageBase 的一个 派生类。
private static class PduParser {
byte pdu[];
int cur;
SmsHeader userDataHeader;
byte[] userData;
int mUserDataSeptetPadding;
int mUserDataSize;
PduParser(byte[] pdu) { // 构造函数
this.pdu = pdu; // 这个是至关重要的,构造函数做的作重要的事情就是 保存了PDU ,而这个类的其他函数都会使用这个pdu来解析出相关的信息。
cur = 0;
mUserDataSeptetPadding = 0;
}
/**
* Parse and return the SC address prepended to SMS messages coming via
* the TS 27.005 / AT interface. Returns null on invalid address
*/
String getSCAddress() { //获取 发送者的地址。// 对于这个函数,我们延续这篇文章来讲解: “http://blog.csdn.net/duanlove/article/details/9386359”
int len;
String ret;
// length of SC Address
len = getByte(); // 获取PDU第一个字节的数据(只取低八位)。
if (len == 0) {
// no SC address // 如果为 0 就说明 ,没有发送者的地址。
ret = null;
} else {
// SC address
try { //否则,就通过PhoneNumberUtils.calledPartyBCDToString 解析获取PDU中包含的 发送者的地址。
ret = PhoneNumberUtils.calledPartyBCDToString(pdu, cur, len); //如果我们想知道 发送者的地址在PDU中是怎么被编码的,就必须去了解calledPartyBCDToString 的详细实现了。 可以查看这篇文章了解详情:“http://blog.csdn.net/duanlove/article/details/9475347”
} catch (RuntimeException tr) {
Log.d(LOG_TAG, "invalid SC address: ", tr);
ret = null;
}
}
cur += len; // 调整当前指针。记录读取数据的位置
return ret;
}
/**
* returns non-sign-extended byte value
*/
int getByte() {
return pdu[cur++] & 0xff;
}
/**
* Any address except the SC address (eg, originating address) See TS
* 23.040 9.1.2.5
*/
GsmSmsAddress getAddress() {
GsmSmsAddress ret;
// "The Address-Length field is an integer representation of
// the number field, i.e. excludes any semi-octet containing only
// fill bits."
// The TOA field is not included as part of this
int addressLength = pdu[cur] & 0xff;
int lengthBytes = 2 + (addressLength + 1) / 2;
try {
ret = new GsmSmsAddress(pdu, cur, lengthBytes);
} catch (ParseException e) {
Log.e(LOG_TAG, e.getMessage());
ret = null;
}
cur += lengthBytes;
return ret;
}
/**
* Parses an SC timestamp and returns a currentTimeMillis()-style
* timestamp
*/
long getSCTimestampMillis() {
// TP-Service-Centre-Time-Stamp
int year = IccUtils.gsmBcdByteToInt(pdu[cur++]);
int month = IccUtils.gsmBcdByteToInt(pdu[cur++]);
int day = IccUtils.gsmBcdByteToInt(pdu[cur++]);
int hour = IccUtils.gsmBcdByteToInt(pdu[cur++]);
int minute = IccUtils.gsmBcdByteToInt(pdu[cur++]);
int second = IccUtils.gsmBcdByteToInt(pdu[cur++]);
// For the timezone, the most significant bit of the
// least significant nibble is the sign byte
// (meaning the max range of this field is 79 quarter-hours,
// which is more than enough)
byte tzByte = pdu[cur++];
// Mask out sign bit.
int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
Time time = new Time(Time.TIMEZONE_UTC);
// It's 2006. Should I really support years < 2000?
time.year = year >= 90 ? year + 1900 : year + 2000;
time.month = month - 1;
time.monthDay = day;
time.hour = hour;
time.minute = minute;
time.second = second;
// Timezone offset is in quarter hours.
return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000);
}
/**
* Pulls the user data out of the PDU, and separates the payload from
* the header if there is one.
*
* @param hasUserDataHeader true if there is a user data header
* @param dataInSeptets true if the data payload is in septets instead
* of octets
* @return the number of septets or octets in the user data payload
*/
int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) {
int offset = cur;
int userDataLength = pdu[offset++] & 0xff;
int headerSeptets = 0;
int userDataHeaderLength = 0;
if (hasUserDataHeader) {
userDataHeaderLength = pdu[offset++] & 0xff;
byte[] udh = new byte[userDataHeaderLength];
System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength);
userDataHeader = SmsHeader.fromByteArray(udh);
offset += userDataHeaderLength;
int headerBits = (userDataHeaderLength + 1) * 8;
headerSeptets = headerBits / 7;
headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
mUserDataSeptetPadding = (headerSeptets * 7) - headerBits;
}
int bufferLen;
if (dataInSeptets) {
/*
* Here we just create the user data length to be the remainder of
* the pdu minus the user data header, since userDataLength means
* the number of uncompressed septets.
*/
bufferLen = pdu.length - offset;
} else {
/*
* userDataLength is the count of octets, so just subtract the
* user data header.
*/
bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0);
if (bufferLen < 0) {
bufferLen = 0;
}
}
userData = new byte[bufferLen];
System.arraycopy(pdu, offset, userData, 0, userData.length);
cur = offset;
if (dataInSeptets) {
// Return the number of septets
int count = userDataLength - headerSeptets;
// If count < 0, return 0 (means UDL was probably incorrect)
return count < 0 ? 0 : count;
} else {
// Return the number of octets
return userData.length;
}
}
/**
* Returns the user data payload, not including the headers
*
* @return the user data payload, not including the headers
*/
byte[] getUserData() {
return userData;
}
/**
* Returns the number of padding bits at the beginning of the user data
* array before the start of the septets.
*
* @return the number of padding bits at the beginning of the user data
* array before the start of the septets
*/
int getUserDataSeptetPadding() {
return mUserDataSeptetPadding;
}
/**
* Returns an object representing the user data headers
*
* {@hide}
*/
SmsHeader getUserDataHeader() {
return userDataHeader;
}
/**
* Interprets the user data payload as packed GSM 7bit characters, and
* decodes them into a String.
*
* @param septetCount the number of septets in the user data payload
* @return a String with the decoded characters
*/
String getUserDataGSM7Bit(int septetCount, int languageTable,
int languageShiftTable) {
String ret;
ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount,
mUserDataSeptetPadding, languageTable, languageShiftTable);
cur += (septetCount * 7) / 8;
return ret;
}
/**
* Interprets the user data payload as UCS2 characters, and
* decodes them into a String.
*
* @param byteCount the number of bytes in the user data payload
* @return a String with the decoded characters
*/
String getUserDataUCS2(int byteCount) {
String ret;
try {
ret = new String(pdu, cur, byteCount, "utf-16");
} catch (UnsupportedEncodingException ex) {
ret = "";
Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
}
cur += byteCount;
return ret;
}
/**
* Interprets the user data payload as KSC-5601 characters, and
* decodes them into a String.
*
* @param byteCount the number of bytes in the user data payload
* @return a String with the decoded characters
*/
String getUserDataKSC5601(int byteCount) {
String ret;
try {
ret = new String(pdu, cur, byteCount, "KSC5601");
} catch (UnsupportedEncodingException ex) {
ret = "";
Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
}
cur += byteCount;
return ret;
}
boolean moreDataPresent() {
return (pdu.length > cur);
}
}