📄 pduparser.java
字号:
package org.ajwcc.pduUtils.gsm3040;
import java.util.*;
import org.ajwcc.pduUtils.gsm3040.ie.*;
//PduUtils Library - A Java library for generating GSM 3040 Protocol Data Units (PDUs)
//
//Copyright (C) 2008, Ateneo Java Wireless Competency Center/Blueblade Technologies, Philippines.
//PduUtils is distributed under the terms of the Apache License version 2.0
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
public class PduParser
{
// ==================================================
// RAW PDU PARSER
// ==================================================
// increments as methods are called
private int position;
private byte[] pduByteArray;
// possible types of data
// BCD digits
// byte
// gsm-septets
// timestamp info
private int readByte()
{
// read 8-bits forward
int retVal = pduByteArray[position] & 0xFF;
position++;
return retVal;
}
private int readSwappedNibbleBCDByte()
{
// read 8-bits forward, swap the nibbles
int data = readByte();
data = PduUtils.swapNibbles((byte) data);
int retVal = 0;
retVal += ((data >>> 4) & 0xF) * 10;
retVal += ((data & 0xF));
return retVal;
}
private Date readTimeStamp()
{
// reads timestamp info
// 7 bytes in semi-octet(BCD) style
int year = readSwappedNibbleBCDByte();
int month = readSwappedNibbleBCDByte();
int day = readSwappedNibbleBCDByte();
int hour = readSwappedNibbleBCDByte();
int minute = readSwappedNibbleBCDByte();
int second = readSwappedNibbleBCDByte();
int timezone = readSwappedNibbleBCDByte();
// time zone computation
TimeZone tz = null;
if (timezone >= 128)
{
// bit 3 of unswapped value represents the sign (1 == negative, 0 == positive)
// when swapped this will now be bit 7 (128)
timezone = timezone - 128;
int totalMinutes = timezone * 15;
int hours = totalMinutes / 60;
int minutes = totalMinutes % 60;
tz = TimeZone.getTimeZone("GMT-" + hours + ":" + (minutes < 10 ? "0" : "") + minutes);
}
else
{
int totalMinutes = timezone * 15;
int hours = totalMinutes / 60;
int minutes = totalMinutes % 60;
tz = TimeZone.getTimeZone("GMT+" + hours + ":" + (minutes < 10 ? "0" : "") + minutes);
}
Calendar cal = Calendar.getInstance(tz);
cal.set(Calendar.YEAR, year + 2000);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.SECOND, second);
return cal.getTime();
}
private String readAddress(int addressLength, int addressType)
{
// NOTE: the max number of octets on an address is 12 octets
// this means that an address field need only be 12 octets long
// what about for 7-bit? This would be 13 chars at 12 octets?
if (addressLength > 0)
{
// length is a semi-octet count
int addressDataOctetLength = addressLength / 2 + ((addressLength % 2 == 1) ? 1 : 0);
// extract data and increment position
byte[] addressData = new byte[addressDataOctetLength];
System.arraycopy(pduByteArray, position, addressData, 0, addressDataOctetLength);
position = position + addressDataOctetLength;
switch (PduUtils.extractAddressType(addressType))
{
case PduUtils.ADDRESS_TYPE_ALPHANUMERIC:
// extract and process encoded bytes
return PduUtils.decode7bitEncoding(addressData);
default:
// process BCD style data any other
return PduUtils.readBCDNumbers(addressLength, addressData);
}
}
return null;
}
private int readValidityPeriodInt()
{
// this will convert the VP to #MINUTES
int validity = readByte();
int minutes = 0;
if ((validity > 0) && (validity <= 143))
{
// groups of 5 min
minutes = (validity + 1) * 5;
}
else if ((validity > 143) && (validity <= 167))
{
// groups of 30 min + 12 hrs
minutes = (12 * 60) + (validity - 143) * 30;
}
else if ((validity > 167) && (validity <= 196))
{
// days
minutes = (validity - 166) * 24 * 60;
}
else if ((validity > 197) && (validity <= 255))
{
// weeks
minutes = (validity - 192) * 7 * 24 * 60;
}
return minutes;
}
public Pdu parsePdu(String rawPdu)
{
// encode pdu to byte[] for easier processing
pduByteArray = PduUtils.pduToBytes(rawPdu);
position = 0;
// parse start and determine what type of pdu it is
Pdu pdu = parseStart();
pdu.setRawPdu(rawPdu);
// parse depending on the pdu type
switch (pdu.getTpMti())
{
case PduUtils.TP_MTI_SMS_DELIVER:
parseSmsDeliverMessage((SmsDeliveryPdu) pdu);
break;
case PduUtils.TP_MTI_SMS_SUBMIT:
parseSmsSubmitMessage((SmsSubmitPdu) pdu);
break;
case PduUtils.TP_MTI_SMS_STATUS_REPORT:
parseSmsStatusReportMessage((SmsStatusReportPdu) pdu);
break;
}
return pdu;
}
private Pdu parseStart()
{
// SMSC info
// length
// address type
// smsc data
int addressLength = readByte();
Pdu pdu = null;
if (addressLength > 0)
{
int addressType = readByte();
String smscAddress = readAddress((addressLength - 1) * 2, addressType);
// first octet - determine how to parse and how to store
int firstOctet = readByte();
pdu = PduFactory.createPdu(firstOctet);
// generic methods
pdu.setSmscAddressType(addressType);
pdu.setSmscAddress(smscAddress);
pdu.setSmscInfoLength(addressLength);
}
else
{
// first octet - determine how to parse and how to store
int firstOctet = readByte();
pdu = PduFactory.createPdu(firstOctet);
}
return pdu;
}
private void parseUserData(Pdu pdu)
{
// ud length
// NOTE: - the udLength value is just stored, it is not used to determine the length
// of the remaining data (it may be a septet length not an octet length)
// - parser just assumes that the remaining PDU data is for the User-Data field
int udLength = readByte();
pdu.setUDLength(udLength);
// user data
// NOTE: UD Data does not contain the length octet
int udOctetLength = pduByteArray.length - position;
byte[] udData = new byte[udOctetLength];
System.arraycopy(pduByteArray, position, udData, 0, udOctetLength);
// save the UD data
pdu.setUDData(udData);
// user data header (if present)
// position is still at the start of the UD
if (pdu.hasTpUdhi())
{
// udh length
int udhLength = readByte();
// udh data (iterate till udh is consumed)
// iei id
// iei data length
// iei data
int endUdh = position + udhLength;
while (position < endUdh)
{
int iei = readByte();
int iedl = readByte();
byte[] ieData = new byte[iedl];
System.arraycopy(pduByteArray, position, ieData, 0, iedl);
InformationElement ie = InformationElementFactory.createInformationElement(iei, ieData);
pdu.addInformationElement(ie);
position = position + iedl;
if (position > endUdh)
{
// at the end, position after adding should be exactly at endUdh
throw new RuntimeException("UDH is shorter than expected endUdh=" + endUdh + ", position=" + position);
}
}
}
}
private void parseSmsDeliverMessage(SmsDeliveryPdu pdu)
{
// originator address info
// address length
// type of address
// address data
int addressLength = readByte();
int addressType = readByte();
String originatorAddress = readAddress(addressLength, addressType);
pdu.setAddressType(addressType);
pdu.setAddress(originatorAddress);
// protocol id
int protocolId = readByte();
pdu.setProtocolIdentifier(protocolId);
// data coding scheme
int dcs = readByte();
pdu.setDataCodingScheme(dcs);
// timestamp
Date timestamp = readTimeStamp();
pdu.setTimestamp(timestamp);
// user data
parseUserData(pdu);
}
private void parseSmsStatusReportMessage(SmsStatusReportPdu pdu)
{
// message reference
int messageReference = readByte();
pdu.setMessageReference(messageReference);
// destination address info
int addressLength = readByte();
int addressType = readByte();
String destinationAddress = readAddress(addressLength, addressType);
pdu.setAddressType(addressType);
pdu.setAddress(destinationAddress);
// timestamp
Date timestamp = readTimeStamp();
pdu.setTimestamp(timestamp);
// discharge time(timestamp)
Date timestamp2 = readTimeStamp();
pdu.setDischargeTime(timestamp2);
// status
int status = readByte();
pdu.setStatus(status);
}
// NOTE: the following is just for validation of the PduGenerator
// - there is no normal scenario where this is used
private void parseSmsSubmitMessage(SmsSubmitPdu pdu)
{
// message reference
int messageReference = readByte();
pdu.setMessageReference(messageReference);
// destination address info
int addressLength = readByte();
int addressType = readByte();
String destinationAddress = readAddress(addressLength, addressType);
pdu.setAddressType(addressType);
pdu.setAddress(destinationAddress);
// protocol id
int protocolId = readByte();
pdu.setProtocolIdentifier(protocolId);
// data coding scheme
int dcs = readByte();
pdu.setDataCodingScheme(dcs);
// validity period
switch (pdu.getTpVpf())
{
case PduUtils.TP_VPF_NONE:
break;
case PduUtils.TP_VPF_INTEGER:
int validityInt = readValidityPeriodInt();
pdu.setValidityPeriod(validityInt / 60); // pdu assumes hours
break;
case PduUtils.TP_VPF_TIMESTAMP:
Date validityDate = readTimeStamp();
pdu.setValidityTimestamp(validityDate);
break;
}
parseUserData(pdu);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -