diff options
Diffstat (limited to 'android/bluetooth/client/map/BluetoothMapBmessageParser.java')
-rw-r--r-- | android/bluetooth/client/map/BluetoothMapBmessageParser.java | 459 |
1 files changed, 0 insertions, 459 deletions
diff --git a/android/bluetooth/client/map/BluetoothMapBmessageParser.java b/android/bluetooth/client/map/BluetoothMapBmessageParser.java deleted file mode 100644 index ea9bc7f8..00000000 --- a/android/bluetooth/client/map/BluetoothMapBmessageParser.java +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2014 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 android.bluetooth.client.map; - -import android.util.Log; - -import com.android.vcard.VCardEntry; -import com.android.vcard.VCardEntryConstructor; -import com.android.vcard.VCardEntryHandler; -import com.android.vcard.VCardParser; -import com.android.vcard.VCardParser_V21; -import com.android.vcard.VCardParser_V30; -import com.android.vcard.exception.VCardException; -import com.android.vcard.exception.VCardVersionException; -import android.bluetooth.client.map.BluetoothMapBmessage.Status; -import android.bluetooth.client.map.BluetoothMapBmessage.Type; -import android.bluetooth.client.map.utils.BmsgTokenizer; -import android.bluetooth.client.map.utils.BmsgTokenizer.Property; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.text.ParseException; - -class BluetoothMapBmessageParser { - - private final static String TAG = "BluetoothMapBmessageParser"; - private final static boolean DBG = false; - - private final static String CRLF = "\r\n"; - - private final static Property BEGIN_BMSG = new Property("BEGIN", "BMSG"); - private final static Property END_BMSG = new Property("END", "BMSG"); - - private final static Property BEGIN_VCARD = new Property("BEGIN", "VCARD"); - private final static Property END_VCARD = new Property("END", "VCARD"); - - private final static Property BEGIN_BENV = new Property("BEGIN", "BENV"); - private final static Property END_BENV = new Property("END", "BENV"); - - private final static Property BEGIN_BBODY = new Property("BEGIN", "BBODY"); - private final static Property END_BBODY = new Property("END", "BBODY"); - - private final static Property BEGIN_MSG = new Property("BEGIN", "MSG"); - private final static Property END_MSG = new Property("END", "MSG"); - - private final static int CRLF_LEN = 2; - - /* - * length of "container" for 'message' in bmessage-body-content: - * BEGIN:MSG<CRLF> + <CRLF> + END:MSG<CRFL> - */ - private final static int MSG_CONTAINER_LEN = 22; - - private BmsgTokenizer mParser; - - private final BluetoothMapBmessage mBmsg; - - private BluetoothMapBmessageParser() { - mBmsg = new BluetoothMapBmessage(); - } - - static public BluetoothMapBmessage createBmessage(String str) { - BluetoothMapBmessageParser p = new BluetoothMapBmessageParser(); - - if (DBG) { - Log.d(TAG, "actual wired contents: " + str); - } - - try { - p.parse(str); - } catch (IOException e) { - Log.e(TAG, "I/O exception when parsing bMessage", e); - return null; - } catch (ParseException e) { - Log.e(TAG, "Cannot parse bMessage", e); - return null; - } - - return p.mBmsg; - } - - private ParseException expected(Property... props) { - boolean first = true; - StringBuilder sb = new StringBuilder(); - - for (Property prop : props) { - if (!first) { - sb.append(" or "); - } - sb.append(prop); - first = false; - } - - return new ParseException("Expected: " + sb.toString(), mParser.pos()); - } - - private void parse(String str) throws IOException, ParseException { - - Property prop; - - /* - * <bmessage-object>::= { "BEGIN:BMSG" <CRLF> <bmessage-property> - * [<bmessage-originator>]* <bmessage-envelope> "END:BMSG" <CRLF> } - */ - - mParser = new BmsgTokenizer(str + CRLF); - - prop = mParser.next(); - if (!prop.equals(BEGIN_BMSG)) { - throw expected(BEGIN_BMSG); - } - - prop = parseProperties(); - - while (prop.equals(BEGIN_VCARD)) { - - /* <bmessage-originator>::= <vcard> <CRLF> */ - - StringBuilder vcard = new StringBuilder(); - prop = extractVcard(vcard); - - VCardEntry entry = parseVcard(vcard.toString()); - mBmsg.mOriginators.add(entry); - } - - if (!prop.equals(BEGIN_BENV)) { - throw expected(BEGIN_BENV); - } - - prop = parseEnvelope(1); - - if (!prop.equals(END_BMSG)) { - throw expected(END_BENV); - } - - /* - * there should be no meaningful data left in stream here so we just - * ignore whatever is left - */ - - mParser = null; - } - - private Property parseProperties() throws ParseException { - - Property prop; - - /* - * <bmessage-property>::=<bmessage-version-property> - * <bmessage-readstatus-property> <bmessage-type-property> - * <bmessage-folder-property> <bmessage-version-property>::="VERSION:" - * <common-digit>*"."<common-digit>* <CRLF> - * <bmessage-readstatus-property>::="STATUS:" 'readstatus' <CRLF> - * <bmessage-type-property>::="TYPE:" 'type' <CRLF> - * <bmessage-folder-property>::="FOLDER:" 'foldername' <CRLF> - */ - - do { - prop = mParser.next(); - - if (prop.name.equals("VERSION")) { - mBmsg.mBmsgVersion = prop.value; - - } else if (prop.name.equals("STATUS")) { - for (Status s : Status.values()) { - if (prop.value.equals(s.toString())) { - mBmsg.mBmsgStatus = s; - break; - } - } - - } else if (prop.name.equals("TYPE")) { - for (Type t : Type.values()) { - if (prop.value.equals(t.toString())) { - mBmsg.mBmsgType = t; - break; - } - } - - } else if (prop.name.equals("FOLDER")) { - mBmsg.mBmsgFolder = prop.value; - - } - - } while (!prop.equals(BEGIN_VCARD) && !prop.equals(BEGIN_BENV)); - - return prop; - } - - private Property parseEnvelope(int level) throws IOException, ParseException { - - Property prop; - - /* - * we can support as many nesting level as we want, but MAP spec clearly - * defines that there should be no more than 3 levels. so we verify it - * here. - */ - - if (level > 3) { - throw new ParseException("bEnvelope is nested more than 3 times", mParser.pos()); - } - - /* - * <bmessage-envelope> ::= { "BEGIN:BENV" <CRLF> [<bmessage-recipient>]* - * <bmessage-envelope> | <bmessage-content> "END:BENV" <CRLF> } - */ - - prop = mParser.next(); - - while (prop.equals(BEGIN_VCARD)) { - - /* <bmessage-originator>::= <vcard> <CRLF> */ - - StringBuilder vcard = new StringBuilder(); - prop = extractVcard(vcard); - - if (level == 1) { - VCardEntry entry = parseVcard(vcard.toString()); - mBmsg.mRecipients.add(entry); - } - } - - if (prop.equals(BEGIN_BENV)) { - prop = parseEnvelope(level + 1); - - } else if (prop.equals(BEGIN_BBODY)) { - prop = parseBody(); - - } else { - throw expected(BEGIN_BENV, BEGIN_BBODY); - } - - if (!prop.equals(END_BENV)) { - throw expected(END_BENV); - } - - return mParser.next(); - } - - private Property parseBody() throws IOException, ParseException { - - Property prop; - - /* - * <bmessage-content>::= { "BEGIN:BBODY"<CRLF> [<bmessage-body-part-ID> - * <CRLF>] <bmessage-body-property> <bmessage-body-content>* <CRLF> - * "END:BBODY"<CRLF> } <bmessage-body-part-ID>::="PARTID:" 'Part-ID' - * <bmessage-body-property>::=[<bmessage-body-encoding-property>] - * [<bmessage-body-charset-property>] - * [<bmessage-body-language-property>] - * <bmessage-body-content-length-property> - * <bmessage-body-encoding-property>::="ENCODING:"'encoding' <CRLF> - * <bmessage-body-charset-property>::="CHARSET:"'charset' <CRLF> - * <bmessage-body-language-property>::="LANGUAGE:"'language' <CRLF> - * <bmessage-body-content-length-property>::= "LENGTH:" <common-digit>* - * <CRLF> - */ - - do { - prop = mParser.next(); - - if (prop.name.equals("PARTID")) { - } else if (prop.name.equals("ENCODING")) { - mBmsg.mBbodyEncoding = prop.value; - - } else if (prop.name.equals("CHARSET")) { - mBmsg.mBbodyCharset = prop.value; - - } else if (prop.name.equals("LANGUAGE")) { - mBmsg.mBbodyLanguage = prop.value; - - } else if (prop.name.equals("LENGTH")) { - try { - mBmsg.mBbodyLength = Integer.parseInt(prop.value); - } catch (NumberFormatException e) { - throw new ParseException("Invalid LENGTH value", mParser.pos()); - } - - } - - } while (!prop.equals(BEGIN_MSG)); - - /* - * check that the charset is always set to UTF-8. We expect only text transfer (in lieu with - * the MAPv12 specifying only RFC2822 (text only) for MMS/EMAIL and SMS do not support - * non-text content. If the charset is not set to UTF-8, it is safe to set the message as - * empty. We force the getMessage (see BluetoothMasClient) to only call getMessage with - * UTF-8 as the MCE is not obliged to support native charset. - */ - if (!mBmsg.mBbodyCharset.equals("UTF-8")) { - Log.e(TAG, "The charset was not set to charset UTF-8: " + mBmsg.mBbodyCharset); - } - - /* - * <bmessage-body-content>::={ "BEGIN:MSG"<CRLF> 'message'<CRLF> - * "END:MSG"<CRLF> } - */ - - int messageLen = mBmsg.mBbodyLength - MSG_CONTAINER_LEN; - int offset = messageLen + CRLF_LEN; - int restartPos = mParser.pos() + offset; - - /* - * length is specified in bytes so we need to convert from unicode - * string back to bytes array - */ - - String remng = mParser.remaining(); - byte[] data = remng.getBytes(); - - /* restart parsing from after 'message'<CRLF> */ - mParser = new BmsgTokenizer(new String(data, offset, data.length - offset), restartPos); - - prop = mParser.next(true); - - if (prop != null) { - if (prop.equals(END_MSG)) { - if (mBmsg.mBbodyCharset.equals("UTF-8")) { - mBmsg.mMessage = new String(data, 0, messageLen, StandardCharsets.UTF_8); - } else { - mBmsg.mMessage = null; - } - } else { - /* Handle possible exception for incorrect LENGTH value - * from MSE while parsing GET Message response */ - Log.e(TAG, "Prop Invalid: "+ prop.toString()); - Log.e(TAG, "Possible Invalid LENGTH value"); - throw expected(END_MSG); - } - } else { - - data = null; - - /* - * now we check if bMessage can be parsed if LENGTH is handled as - * number of characters instead of number of bytes - */ - if (offset < 0 || offset > remng.length()) { - /* Handle possible exception for incorrect LENGTH value - * from MSE while parsing GET Message response */ - throw new ParseException("Invalid LENGTH value", mParser.pos()); - } - - Log.w(TAG, "byte LENGTH seems to be invalid, trying with char length"); - - mParser = new BmsgTokenizer(remng.substring(offset)); - - prop = mParser.next(); - - if (!prop.equals(END_MSG)) { - throw expected(END_MSG); - } - - if (mBmsg.mBbodyCharset.equals("UTF-8")) { - mBmsg.mMessage = remng.substring(0, messageLen); - } else { - mBmsg.mMessage = null; - } - } - - prop = mParser.next(); - - if (!prop.equals(END_BBODY)) { - throw expected(END_BBODY); - } - - return mParser.next(); - } - - private Property extractVcard(StringBuilder out) throws IOException, ParseException { - Property prop; - - out.append(BEGIN_VCARD).append(CRLF); - - do { - prop = mParser.next(); - out.append(prop).append(CRLF); - } while (!prop.equals(END_VCARD)); - - return mParser.next(); - } - - private class VcardHandler implements VCardEntryHandler { - - VCardEntry vcard; - - @Override - public void onStart() { - } - - @Override - public void onEntryCreated(VCardEntry entry) { - vcard = entry; - } - - @Override - public void onEnd() { - } - }; - - private VCardEntry parseVcard(String str) throws IOException, ParseException { - VCardEntry vcard = null; - - try { - VCardParser p = new VCardParser_V21(); - VCardEntryConstructor c = new VCardEntryConstructor(); - VcardHandler handler = new VcardHandler(); - c.addEntryHandler(handler); - p.addInterpreter(c); - p.parse(new ByteArrayInputStream(str.getBytes())); - - vcard = handler.vcard; - - } catch (VCardVersionException e1) { - - try { - VCardParser p = new VCardParser_V30(); - VCardEntryConstructor c = new VCardEntryConstructor(); - VcardHandler handler = new VcardHandler(); - c.addEntryHandler(handler); - p.addInterpreter(c); - p.parse(new ByteArrayInputStream(str.getBytes())); - - vcard = handler.vcard; - - } catch (VCardVersionException e2) { - // will throw below - } catch (VCardException e2) { - // will throw below - } - - } catch (VCardException e1) { - // will throw below - } - - if (vcard == null) { - throw new ParseException("Cannot parse vCard object (neither 2.1 nor 3.0?)", - mParser.pos()); - } - - return vcard; - } -} |