PtsPrimitiveParser.java
上传用户:szyujian
上传日期:2016-09-20
资源大小:320k
文件大小:23k
- /*
- * Copyright (C) 2007 Esmertec AG.
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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.
- */
- package com.android.im.imps;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Map.Entry;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import com.android.im.imps.Primitive.TransactionMode;
- /**
- * PTS/SMS encoded IMPS messages parser. Only response transactions and
- * server initiated requests are supported.
- */
- public class PtsPrimitiveParser implements PrimitiveParser {
- // WVaaBBcccDD <parameters>
- // aa - version number; 12 for 1.2, 13 for 1.3; "XX" for version discovery
- // BB - message type, case insensitive
- // ccc - transaction id in range 0-999 without preceding zero
- // DD - multiple SMSes identifier
- private static final Pattern sPreamplePattern =
- Pattern.compile("\AWV(\d{2})(\p{Alpha}{2})(\d{1,3})(\p{Alpha}{2})?(\z| .*)");
- private char mReadBuf[] = new char[256];
- private StringBuilder mStringBuf = new StringBuilder();
- private int mPos;
- private static int UNCERTAIN_GROUP_SIZE = -1;
- public Primitive parse(InputStream in) throws ParserException, IOException {
- // assuming PTS data is always short
- BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
- mStringBuf.setLength(0);
- mPos = 0;
- int len;
- while ((len = reader.read(mReadBuf)) != -1) {
- mStringBuf.append(mReadBuf, 0, len);
- }
- return parsePrim();
- }
- private Primitive parsePrim() throws ParserException
- {
- Matcher m = sPreamplePattern.matcher(mStringBuf);
- if (!m.matches()) {
- throw new ParserException("Invalid PTS encoded message");
- }
- Primitive p = new Primitive();
- // TODO: handle WV version in m.group(1)
- String type = m.group(2).toUpperCase();
- String transactionType = PtsCodes.getTransaction(type);
- if (transactionType == null) {
- throw new ParserException("Unrecognized transaction code " + type);
- }
- p.setContentElement(transactionType);
- if (PtsCodes.isServerRequestCode(type)) {
- p.setTransactionMode(TransactionMode.Request);
- } else {
- p.setTransactionMode(TransactionMode.Response);
- }
- p.setTransactionId(m.group(3));
- mPos = m.start(5);
- if (mPos < mStringBuf.length()) {
- match(' ');
- HashMap<String, ParamValue> params = parseParams();
- for (Entry<String, ParamValue> param : params.entrySet()) {
- translateParam(p, param.getKey(), param.getValue());
- }
- }
- return p;
- }
- private static HashMap<String, Integer> sInfoElemTypeMap;
- private static final int ELEM_OTHER_SIMPLE = 0;
- private static final int ELEM_SESSION_ID = 1;
- private static final int ELEM_RESULT = 2;
- private static final int ELEM_ALL_FUNCTIONS = 3;
- private static final int ELEM_NOT_AVAIL_FUNCS = 4;
- private static final int ELEM_CAPABILITY_LIST = 5;
- private static final int ELEM_CONTACT_LIST = 6;
- private static final int ELEM_DEFAULT_CONTACT_LIST = 7;
- private static final int ELEM_USER_NICK_LIST = 8;
- private static final int ELEM_CONTACT_LIST_PROPS = 9;
- private static final int ELEM_PRESENCE = 10;
- /*
- private static final int ELEM_RESULT_CLIST = 3;
- private static final int ELEM_RESULT_DOMAIN = 4;
- private static final int ELEM_RESULT_GROUP = 5;
- private static final int ELEM_RESULT_MSGID = 6;
- private static final int ELEM_RESULT_SCRNAME = 7;
- private static final int ELEM_RESULT_USER = 8;
- */
- static {
- sInfoElemTypeMap = new HashMap<String, Integer>();
- sInfoElemTypeMap.put(PtsCodes.SessionID, ELEM_SESSION_ID);
- sInfoElemTypeMap.put(PtsCodes.Status, ELEM_RESULT);
- sInfoElemTypeMap.put(PtsCodes.NotAvailableFunctions, ELEM_NOT_AVAIL_FUNCS);
- sInfoElemTypeMap.put(PtsCodes.AllFunctions, ELEM_ALL_FUNCTIONS);
- sInfoElemTypeMap.put(PtsCodes.AgreedCapabilityList, ELEM_CAPABILITY_LIST);
- sInfoElemTypeMap.put(PtsCodes.ContactList, ELEM_CONTACT_LIST);
- sInfoElemTypeMap.put(PtsCodes.DefaultContactList, ELEM_DEFAULT_CONTACT_LIST);
- sInfoElemTypeMap.put(PtsCodes.UserNickList, ELEM_USER_NICK_LIST);
- sInfoElemTypeMap.put(PtsCodes.ContactListProps, ELEM_CONTACT_LIST_PROPS);
- sInfoElemTypeMap.put(PtsCodes.Presence, ELEM_PRESENCE);
- }
- private static void translateParam(Primitive p, String elemCode,
- ParamValue elemValue) throws ParserException {
- int type;
- elemCode = elemCode.toUpperCase();
- // FIXME: Should be refactored when we had concrete situation of the null value case
- if (elemValue == null) {
- throw new ParserException("Parameter " + elemCode + " must have value.");
- }
- if (sInfoElemTypeMap.containsKey(elemCode)) {
- type = sInfoElemTypeMap.get(elemCode);
- /*
- if (type == ELEM_RESULT_CLIST && p.getType().equals(ImpsTags.Login_Response)) {
- // Fix up DigestSchema which shares a same code with
- // ContactListID. It appears only in Login_Response.
- type = ELEM_OTHER_SIMPLE;
- }
- */
- } else {
- type = ELEM_OTHER_SIMPLE;
- }
- switch (type) {
- case ELEM_SESSION_ID:
- if (elemValue.mStrValue == null) {
- throw new ParserException("Element SessionID must have string value!");
- }
- if (p.getType().equals(ImpsTags.Login_Response)) {
- p.addElement(ImpsTags.SessionID, elemValue.mStrValue);
- } else {
- p.setSession(elemValue.mStrValue);
- }
- break;
- case ELEM_RESULT:
- // ST=<StatusCode>
- // ST=(<StatusCode>,<Description>)
- PrimitiveElement result = p.addElement(ImpsTags.Result);
- if (elemValue.mStrValue != null) {
- result.addChild(ImpsTags.Code, elemValue.mStrValue);
- } else {
- checkGroupValue(elemValue.mValueGroup, 2);
- result.addChild(ImpsTags.Code, elemValue.mValueGroup.get(0).mStrValue);
- result.addChild(ImpsTags.Description, elemValue.mValueGroup.get(1).mStrValue);
- }
- break;
- case ELEM_ALL_FUNCTIONS:
- case ELEM_NOT_AVAIL_FUNCS:
- p.addElement(translateServiceTree(elemCode, elemValue));
- break;
- case ELEM_CAPABILITY_LIST:
- p.addElement(translateCapabilityList(elemValue));
- break;
- case ELEM_CONTACT_LIST:
- if (elemValue.mStrValue != null) {
- p.addElement(ImpsTags.ContactList, elemValue.mStrValue);
- } else {
- checkGroupValue(elemValue.mValueGroup, UNCERTAIN_GROUP_SIZE);
- for (ParamValue value : elemValue.mValueGroup) {
- p.addElement(ImpsTags.ContactList, value.mStrValue);
- }
- }
- break;
- case ELEM_DEFAULT_CONTACT_LIST:
- if (elemValue.mStrValue == null) {
- throw new ParserException("Deafult Contact List must have string value!");
- }
- p.addElement(ImpsTags.DefaultContactList, elemValue.mStrValue);
- break;
- case ELEM_USER_NICK_LIST:
- {
- checkGroupValue(elemValue.mValueGroup, UNCERTAIN_GROUP_SIZE);
- PrimitiveElement nicklistElem = p.addElement(ImpsTags.NickList);
- int groupSize = elemValue.mValueGroup.size();
- for (int i = 0; i < groupSize; i++) {
- ArrayList<ParamValue> valueGroup = elemValue.mValueGroup.get(i).mValueGroup;
- checkGroupValue(valueGroup, 2);
- String nickname = valueGroup.get(0).mStrValue;
- String address = valueGroup.get(1).mStrValue;
- if (nickname == null || address == null) {
- throw new ParserException("Null value found for NickName: " + nickname
- + "-" + address);
- }
- PrimitiveElement nicknameElem = nicklistElem.addChild(ImpsTags.NickName);
- nicknameElem.addChild(ImpsTags.Name, "".equals(nickname) ? null : nickname);
- nicknameElem.addChild(ImpsTags.UserID, address);
- }
- }
- break;
- case ELEM_CONTACT_LIST_PROPS:
- {
- checkGroupValue(elemValue.mValueGroup, UNCERTAIN_GROUP_SIZE);
- PrimitiveElement propertiesElem = p.addElement(ImpsTags.ContactListProperties);
- int groupSize = elemValue.mValueGroup.size();
- for (int i = 0; i < groupSize; i++) {
- ArrayList<ParamValue> valueGroup = elemValue.mValueGroup.get(i).mValueGroup;
- checkGroupValue(valueGroup, 2);
- String name = valueGroup.get(0).mStrValue;
- String value = valueGroup.get(1).mStrValue;
- if (name == null || value == null) {
- throw new ParserException("Null value found for property: " + name + "-" + value);
- }
- if (PtsCodes.DisplayName.equals(name)) {
- name = ImpsConstants.DisplayName;
- } else if (PtsCodes.Default.equals(name)) {
- name = ImpsConstants.Default;
- } else {
- throw new ParserException("Unrecognized property " + name);
- }
- PrimitiveElement propertyElem = propertiesElem.addChild(ImpsTags.Property);
- propertyElem.addChild(ImpsTags.Name, name);
- propertyElem.addChild(ImpsTags.Value, value);
- }
- }
- break;
- case ELEM_PRESENCE:
- //PR=(<UserID>[,<PresenceSubList>])
- //PR=((<UserID>[,<PresenceSubList>]),(<UserID>[,<PresenceSubList>]))
- checkGroupValue(elemValue.mValueGroup, UNCERTAIN_GROUP_SIZE);
- if (elemValue.mValueGroup.size() == 1) {
- // PR=(<UserID>)
- ParamValue value = elemValue.mValueGroup.get(0);
- if (value.mStrValue != null) {
- p.addElement(ImpsTags.Presence).addChild(ImpsTags.UserID, value.mStrValue);
- } else {
- // workaround for OZ server
- p.addElement(translatePresence(value.mValueGroup));
- }
- } else {
- if (elemValue.mValueGroup.get(0).mStrValue == null) {
- // PR=((<UserID>[,<PresenceSubList>]),(<UserID>[,<PresenceSubList>]))
- int groupSize = elemValue.mValueGroup.size();
- for (int i = 0; i < groupSize; i++) {
- ParamValue value = elemValue.mValueGroup.get(i);
- if (value.mStrValue != null) {
- p.addElement(ImpsTags.Presence).addChild(ImpsTags.UserID, value.mStrValue);
- } else {
- p.addElement(translatePresence(value.mValueGroup));
- }
- }
- } else {
- // PR=(<UserID>,<PresenceSubList>)
- p.addElement(translatePresence(elemValue.mValueGroup));
- }
- }
- break;
- case ELEM_OTHER_SIMPLE:
- p.addElement(translateSimpleElem(elemCode, elemValue));
- break;
- default:
- throw new ParserException("Unsupported element " + elemValue);
- }
- }
- private static PrimitiveElement translatePresence(ArrayList<ParamValue> valueGroup)
- throws ParserException {
- checkGroupValue(valueGroup, UNCERTAIN_GROUP_SIZE);
- PrimitiveElement presence = new PrimitiveElement(ImpsTags.Presence);
- if (valueGroup.get(0).mStrValue == null) {
- throw new ParserException("UserID must have string value!");
- }
- presence.addChild(ImpsTags.UserID, valueGroup.get(0).mStrValue);
- if (valueGroup.size() > 1) {
- // has presence sub list
- presence.addChild(translatePresenceSubList(valueGroup.get(1)));
- }
- return presence;
- }
- private static PrimitiveElement translatePresenceSubList(ParamValue value)
- throws ParserException {
- checkGroupValue(value.mValueGroup, UNCERTAIN_GROUP_SIZE);
- PrimitiveElement presenceSubList = new PrimitiveElement(ImpsTags.PresenceSubList);
- int groupSize = value.mValueGroup.size();
- for (int i = 0; i < groupSize; i++) {
- ParamValue v = value.mValueGroup.get(i);
- if (v.mStrValue != null) {
- throw new ParserException("Unexpected string value for presence attribute");
- }
- presenceSubList.addChild(translatePresenceAttribute(v.mValueGroup));
- }
- return presenceSubList;
- }
- // <attribute>[,<qualifier>][,<value>]
- // <attribute>[,<qualifier>,<sub-attribute>]
- private static PrimitiveElement translatePresenceAttribute(
- ArrayList<ParamValue> valueGroup) throws ParserException {
- String type = valueGroup.get(0).mStrValue;
- if (type == null) {
- return null;
- }
- String tag = PtsCodes.getPresenceAttributeElement(type);
- if (tag == null) {
- return null;
- }
- PrimitiveElement paElem = new PrimitiveElement(tag);
- if (valueGroup.size() == 2) {
- // no qualifier
- translateAttributeValue(paElem, valueGroup.get(1), false);
- }else if (valueGroup.size() == 3) {
- // has qualifier, and it should has no group value
- ParamValue qualifierValue = valueGroup.get(1);
- if (qualifierValue.mStrValue == null) {
- throw new ParserException("Qualifier value can't be group value!");
- }
- if (!"".equals(qualifierValue.mStrValue)) {
- paElem.addChild(ImpsTags.Qualifier, qualifierValue.mStrValue);
- }
- translateAttributeValue(paElem, valueGroup.get(2), true);
- } else {
- return null;
- }
- return paElem;
- }
- private static void translateAttributeValue(PrimitiveElement paElem,
- ParamValue v, boolean hasQualifier) throws ParserException {
- if (v.mStrValue == null) {
- // sub-attribute as value
- checkGroupValue(v.mValueGroup, UNCERTAIN_GROUP_SIZE);
- if (v.mValueGroup.get(0).mStrValue != null) {
- paElem.addChild(translatePresenceAttribute(v.mValueGroup));
- } else {
- int groupSize = v.mValueGroup.size();
- for (int i = 0; i < groupSize; i++) {
- ParamValue value = v.mValueGroup.get(i);
- if (value.mStrValue != null) {
- throw new ParserException("Presence Attribute value error!");
- }
- checkGroupValue(value.mValueGroup, UNCERTAIN_GROUP_SIZE);
- paElem.addChild(translatePresenceAttribute(value.mValueGroup));
- }
- }
- } else {
- // single simple value
- if (hasQualifier) {
- paElem.addChild(ImpsTags.PresenceValue, PtsCodes.getPAValue(v.mStrValue));
- } else {
- paElem.setContents(PtsCodes.getPAValue(v.mStrValue));
- }
- }
- }
- private static void checkGroupValue(ArrayList<ParamValue> valueGroup,
- int expectedGroupSize) throws ParserException {
- if (valueGroup == null
- || (expectedGroupSize != UNCERTAIN_GROUP_SIZE
- && valueGroup.size() != expectedGroupSize)) {
- throw new ParserException("Invalid group value!");
- }
- int groupSize = valueGroup.size();
- for (int i = 0; i < groupSize; i++) {
- if (valueGroup.get(i) == null) {
- throw new ParserException("Invalid group value!");
- }
- }
- }
- private static PrimitiveElement translateCapabilityList(ParamValue elemValue)
- throws ParserException {
- PrimitiveElement elem = new PrimitiveElement(ImpsTags.AgreedCapabilityList);
- ArrayList<ParamValue> params = elemValue.mValueGroup;
- if (params != null) {
- checkGroupValue(params, UNCERTAIN_GROUP_SIZE);
- int paramsSize = params.size();
- for (int i = 0; i < paramsSize; i++) {
- ArrayList<ParamValue> capElemGroup = params.get(i).mValueGroup;
- checkGroupValue(capElemGroup, 2);
- String capElemCode = capElemGroup.get(0).mStrValue;
- String capElemName;
- if (capElemCode == null
- || (capElemName = PtsCodes.getCapElement(capElemCode)) == null) {
- throw new ParserException("Unknown capability element "
- + capElemCode);
- }
- String capElemValue = capElemGroup.get(1).mStrValue;
- if (capElemValue == null) {
- throw new ParserException("Illegal capability value for "
- + capElemCode);
- }
- capElemValue = PtsCodes.getCapValue(capElemValue);
- elem.addChild(capElemName, capElemValue);
- }
- }
- return elem;
- }
- private static PrimitiveElement translateServiceTree(String elemCode,
- ParamValue elemValue) throws ParserException {
- String elemName = PtsCodes.getElement(elemCode);
- PrimitiveElement elem = new PrimitiveElement(elemName);
- // TODO: translate the service tree.
- return elem;
- }
- private static PrimitiveElement translateSimpleElem(String elemCode, ParamValue value)
- throws ParserException {
- String elemName = PtsCodes.getElement(elemCode);
- if (elemName == null) {
- throw new ParserException("Unrecognized parameter " + elemCode);
- }
- PrimitiveElement elem = new PrimitiveElement(elemName);
- if (value.mStrValue != null) {
- elem.setContents(value.mStrValue);
- } else {
- throw new ParserException("Don't know how to handle parameters for "
- + elemName);
- }
- return elem;
- }
- private HashMap<String, ParamValue> parseParams() throws ParserException {
- int pos = mPos;
- StringBuilder buf = mStringBuf;
- int len = buf.length();
- HashMap<String, ParamValue> ret = new HashMap<String, ParamValue>();
- String paramName;
- ParamValue paramValue;
- while (pos < len) {
- int nameStart = pos;
- while (pos < len) {
- char ch = buf.charAt(pos);
- if (ch == ' ' || ch == '=') {
- break;
- }
- pos++;
- }
- if (nameStart == pos) {
- throw new ParserException("Missing parameter name near " + pos);
- }
- paramName = buf.substring(nameStart, pos);
- if (pos < len && buf.charAt(pos) == '=') {
- pos++;
- mPos = pos;
- paramValue = parseParamValue();
- pos = mPos;
- } else {
- paramValue = null;
- }
- ret.put(paramName, paramValue);
- if (pos < len) {
- // more parameters ahead
- match(' ');
- pos = mPos;
- }
- }
- return ret;
- }
- private ParamValue parseParamValue() throws ParserException {
- int pos = mPos;
- StringBuilder buf = mStringBuf;
- int len = buf.length();
- if (pos == len) {
- throw new ParserException("Missing parameter value near " + pos);
- }
- ParamValue value = new ParamValue();
- char ch = buf.charAt(pos);
- if (ch == '(') {
- // value list
- pos++;
- ArrayList<ParamValue> valueGroup = new ArrayList<ParamValue>();
- while (pos < len) {
- mPos = pos;
- valueGroup.add(parseParamValue());
- pos = mPos;
- if (pos == len) {
- throw new ParserException("Unexpected parameter end");
- }
- if (buf.charAt(pos) != ',') {
- break;
- }
- pos++;
- }
- mPos = pos;
- match(')');
- if (valueGroup.isEmpty()) {
- throw new ParserException("Empty value group near " + mPos);
- }
- value.mValueGroup = valueGroup;
- } else {
- // single value
- if (ch == '"') {
- // quoted value
- pos++;
- StringBuilder escapedValue = new StringBuilder();
- boolean quotedEnd = false;
- while (pos < len) {
- ch = buf.charAt(pos);
- pos++;
- if (ch == '"') {
- if (pos < len && buf.charAt(pos) == '"') {
- // "doubled" quote
- pos++;
- } else {
- quotedEnd = true;
- break;
- }
- }
- escapedValue.append(ch);
- }
- if (!quotedEnd) {
- throw new ParserException("Unexpected quoted parameter end");
- }
- value.mStrValue = escapedValue.toString();
- } else {
- int valueStart = pos;
- while (pos < len) {
- ch = buf.charAt(pos);
- if (ch == ',' || ch == ')' || ch == ' ') {
- break;
- }
- if (""(=&".indexOf(ch) != -1) {
- throw new ParserException("Special character " + ch
- + " must be quoted");
- }
- pos++;
- }
- value.mStrValue = buf.substring(valueStart, pos);
- }
- mPos = pos;
- }
- return value;
- }
- private void match(char c) throws ParserException {
- if (mStringBuf.charAt(mPos) != c) {
- throw new ParserException("Expected " + c + " at pos " + mPos);
- }
- mPos++;
- }
- /**
- * Detect if this short message is a PTS encoded WV-primitive.
- */
- public static boolean isPtsPrimitive(CharSequence msg)
- {
- if (msg == null) {
- return false;
- }
- Matcher m = sPreamplePattern.matcher(msg);
- return m.matches();
- }
- static final class ParamValue {
- public String mStrValue;
- public ArrayList<ParamValue> mValueGroup;
- }
- }