blob: a360c646de5c18adb31112315576e8a6e510528e [file] [log] [blame]
/*
* 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 com.android.internal.telephony;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.telephony.Rlog;
import android.util.SparseIntArray;
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.XmlUtils;
public class Sms7BitEncodingTranslator {
private static final String TAG = "Sms7BitEncodingTranslator";
private static final boolean DBG = Build.IS_DEBUGGABLE ;
private static boolean mIs7BitTranslationTableLoaded = false;
private static SparseIntArray mTranslationTable = null;
private static SparseIntArray mTranslationTableCommon = null;
private static SparseIntArray mTranslationTableGSM = null;
private static SparseIntArray mTranslationTableCDMA = null;
// Parser variables
private static final String XML_START_TAG = "SmsEnforce7BitTranslationTable";
private static final String XML_TRANSLATION_TYPE_TAG = "TranslationType";
private static final String XML_CHARACTOR_TAG = "Character";
private static final String XML_FROM_TAG = "from";
private static final String XML_TO_TAG = "to";
/**
* Translates each message character that is not supported by GSM 7bit alphabet into a supported
* one.
*
* @param message message to be translated.
* @param isCdmaFormat true if cdma format should be used.
* @return translated message or null if some error occur.
*/
public static String translate(CharSequence message, boolean isCdmaFormat) {
if (message == null) {
Rlog.w(TAG, "Null message can not be translated");
return null;
}
int size = message.length();
if (size <= 0) {
return "";
}
if (!mIs7BitTranslationTableLoaded) {
mTranslationTableCommon = new SparseIntArray();
mTranslationTableGSM = new SparseIntArray();
mTranslationTableCDMA = new SparseIntArray();
load7BitTranslationTableFromXml();
mIs7BitTranslationTableLoaded = true;
}
if ((mTranslationTableCommon != null && mTranslationTableCommon.size() > 0) ||
(mTranslationTableGSM != null && mTranslationTableGSM.size() > 0) ||
(mTranslationTableCDMA != null && mTranslationTableCDMA.size() > 0)) {
char[] output = new char[size];
for (int i = 0; i < size; i++) {
output[i] = translateIfNeeded(message.charAt(i), isCdmaFormat);
}
return String.valueOf(output);
}
return null;
}
/**
* Translates a single character into its corresponding acceptable one, if
* needed, based on GSM 7-bit alphabet
*
* @param c
* character to be translated
* @return original character, if it's present on GSM 7-bit alphabet; a
* corresponding character, based on the translation table or white
* space, if no mapping is found in the translation table for such
* character
*/
private static char translateIfNeeded(char c, boolean isCdmaFormat) {
if (noTranslationNeeded(c, isCdmaFormat)) {
if (DBG) {
Rlog.v(TAG, "No translation needed for " + Integer.toHexString(c));
}
return c;
}
/*
* Trying to translate unicode to Gsm 7-bit alphabet; If c is not
* present on translation table, c does not belong to Unicode Latin-1
* (Basic + Supplement), so we don't know how to translate it to a Gsm
* 7-bit character! We replace c for an empty space and advises the user
* about it.
*/
int translation = -1;
if (mTranslationTableCommon != null) {
translation = mTranslationTableCommon.get(c, -1);
}
if (translation == -1) {
if (isCdmaFormat) {
if (mTranslationTableCDMA != null) {
translation = mTranslationTableCDMA.get(c, -1);
}
} else {
if (mTranslationTableGSM != null) {
translation = mTranslationTableGSM.get(c, -1);
}
}
}
if (translation != -1) {
if (DBG) {
Rlog.v(TAG, Integer.toHexString(c) + " (" + c + ")" + " translated to "
+ Integer.toHexString(translation) + " (" + (char) translation + ")");
}
return (char) translation;
} else {
if (DBG) {
Rlog.w(TAG, "No translation found for " + Integer.toHexString(c)
+ "! Replacing for empty space");
}
return ' ';
}
}
private static boolean noTranslationNeeded(char c, boolean isCdmaFormat) {
if (isCdmaFormat) {
return GsmAlphabet.isGsmSeptets(c) && UserData.charToAscii.get(c, -1) != -1;
}
else {
return GsmAlphabet.isGsmSeptets(c);
}
}
/**
* Load the whole translation table file from the framework resource
* encoded in XML.
*/
private static void load7BitTranslationTableFromXml() {
XmlResourceParser parser = null;
Resources r = Resources.getSystem();
if (parser == null) {
if (DBG) Rlog.d(TAG, "load7BitTranslationTableFromXml: open normal file");
parser = r.getXml(com.android.internal.R.xml.sms_7bit_translation_table);
}
try {
XmlUtils.beginDocument(parser, XML_START_TAG);
while (true) {
XmlUtils.nextElement(parser);
String tag = parser.getName();
if (DBG) {
Rlog.d(TAG, "tag: " + tag);
}
if (XML_TRANSLATION_TYPE_TAG.equals(tag)) {
String type = parser.getAttributeValue(null, "Type");
if (DBG) {
Rlog.d(TAG, "type: " + type);
}
if (type.equals("common")) {
mTranslationTable = mTranslationTableCommon;
} else if (type.equals("gsm")) {
mTranslationTable = mTranslationTableGSM;
} else if (type.equals("cdma")) {
mTranslationTable = mTranslationTableCDMA;
} else {
Rlog.e(TAG, "Error Parsing 7BitTranslationTable: found incorrect type" + type);
}
} else if (XML_CHARACTOR_TAG.equals(tag) && mTranslationTable != null) {
int from = parser.getAttributeUnsignedIntValue(null,
XML_FROM_TAG, -1);
int to = parser.getAttributeUnsignedIntValue(null,
XML_TO_TAG, -1);
if ((from != -1) && (to != -1)) {
if (DBG) {
Rlog.d(TAG, "Loading mapping " + Integer.toHexString(from)
.toUpperCase() + " -> " + Integer.toHexString(to)
.toUpperCase());
}
mTranslationTable.put (from, to);
} else {
Rlog.d(TAG, "Invalid translation table file format");
}
} else {
break;
}
}
if (DBG) Rlog.d(TAG, "load7BitTranslationTableFromXml: parsing successful, file loaded");
} catch (Exception e) {
Rlog.e(TAG, "Got exception while loading 7BitTranslationTable file.", e);
} finally {
if (parser instanceof XmlResourceParser) {
((XmlResourceParser)parser).close();
}
}
}
}