blob: bbb9bb8d8df69700203803a588fcbab43d45fb9e [file] [log] [blame]
/*
* Copyright (C) 2008 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.
*/
#ifndef GSMALPHABET_H_
#define GSMALPHABET_H_
#include <cstdint>
#include <string>
#include <map>
#include <memory>
#include <vector>
class GsmAlphabet {
public:
GsmAlphabet();
virtual ~GsmAlphabet();
/**
* This escapes extended characters, and when present indicates that the
* following character should be looked up in the "extended" table.
*
* gsmToChar(GSM_EXTENDED_ESCAPE) returns 0xffff
*/
static constexpr uint8_t GSM_EXTENDED_ESCAPE = 0x1B;
/**
* User data header requires one octet for length. Count as one septet, because
* all combinations of header elements below will have at least one free bit
* when padding to the nearest septet boundary.
*/
static constexpr int UDH_SEPTET_COST_LENGTH = 1;
/**
* Using a non-default language locking shift table OR single shift table
* requires a user data header of 3 octets, or 4 septets, plus UDH length.
*/
static constexpr int UDH_SEPTET_COST_ONE_SHIFT_TABLE = 4;
/**
* Using a non-default language locking shift table AND single shift table
* requires a user data header of 6 octets, or 7 septets, plus UDH length.
*/
static constexpr int UDH_SEPTET_COST_TWO_SHIFT_TABLES = 7;
/**
* Multi-part messages require a user data header of 5 octets, or 6 septets,
* plus UDH length.
*/
static constexpr int UDH_SEPTET_COST_CONCATENATED_MESSAGE = 6;
/**
* For a specific text string, this object describes protocol
* properties of encoding it for transmission as message user
* data.
*/
class TextEncodingDetails {
public:
/**
*The number of SMS's required to encode the text.
*/
int msgCount;
/**
* The number of code units consumed so far, where code units
* are basically characters in the encoding -- for example,
* septets for the standard ASCII and GSM encodings, and 16
* bits for Unicode.
*/
int codeUnitCount;
/**
* How many code units are still available without spilling
* into an additional message.
*/
int codeUnitsRemaining;
/**
* The encoding code unit size (specified using
* android.telephony.SmsMessage ENCODING_*).
*/
int codeUnitSize;
/**
* The GSM national language table to use, or 0 for the default 7-bit alphabet.
*/
int languageTable;
/**
* The GSM national language shift table to use, or 0 for the default 7-bit extension table.
*/
int languageShiftTable;
std::string toString() {
return "TextEncodingDetails { msgCount=" + std::to_string(msgCount)
+ ", codeUnitCount=" + std::to_string(codeUnitCount)
+ ", codeUnitsRemaining=" + std::to_string(codeUnitsRemaining)
+ ", codeUnitSize=" + std::to_string(codeUnitSize)
+ ", languageTable=" + std::to_string(languageTable)
+ ", languageShiftTable=" + std::to_string(languageShiftTable) + " }";
}
};
static std::string gsm7BitPackedToString(std::vector<uint8_t> pdu, int offset,
int lengthSeptets, int numPaddingBits, int languageTable, int shiftTable);
static std::vector<uint8_t> stringToGsm7BitPacked(std::string data, int startingSeptetOffset,
bool throwException, int languageTable, int languageShiftTable);
private:
/** Reverse mapping from Unicode characters to indexes into language tables. */
static const std::vector<std::shared_ptr<std::map<char, int>>> sCharsToGsmTables;
static std::vector<std::shared_ptr<std::map<char, int>>> initCharsToGsmTables();
/** Reverse mapping from Unicode characters to indexes into language shift tables. */
static const std::vector<std::shared_ptr<std::map<char, int>>> sCharsToShiftTables;
static std::vector<std::shared_ptr<std::map<char, int>>> initCharsToShiftTables();
/** OEM configured list of enabled national language single shift tables for encoding. */
static std::vector<int> sEnabledSingleShiftTables;
/** OEM configured list of enabled national language locking shift tables for encoding. */
static std::vector<int> sEnabledLockingShiftTables;
/** Highest language code to include in array of single shift counters. */
static int sHighestEnabledSingleShiftCode;
/** Flag to bypass check for country-specific overlays (for test cases only). */
static bool sDisableCountryEncodingCheck;
/**
* Septet counter for a specific locking shift table and all of
* the single shift tables that it can be paired with.
*/
class LanguagePairCount {
public:
int languageCode;
std::vector<int> septetCounts;
std::vector<int> unencodableCounts;
LanguagePairCount(int code) {
languageCode = code;
int maxSingleShiftCode = sHighestEnabledSingleShiftCode;
septetCounts.assign((maxSingleShiftCode + 1), 0);
unencodableCounts.assign(maxSingleShiftCode + 1, 0);
// set counters for disabled single shift tables to -1
// (GSM default extension table index 0 is always enabled)
for (int i = 1, tableOffset = 0; i <= maxSingleShiftCode; i++) {
if (sEnabledSingleShiftTables[tableOffset] == i) {
tableOffset++;
} else {
septetCounts[i] = -1; // disabled
}
}
// exclude Turkish locking + Turkish single shift table and
// Portuguese locking + Spanish single shift table (these
// combinations will never be optimal for any input).
if (code == 1 && maxSingleShiftCode >= 1) {
septetCounts[1] = -1; // Turkish + Turkish
} else if (code == 3 && maxSingleShiftCode >= 2) {
septetCounts[2] = -1; // Portuguese + Spanish
}
}
};
static std::vector<std::string> sLanguageTables;
static std::vector<std::string> sLanguageShiftTables;
static void packSmsChar(std::vector<uint8_t> packedChars, int bitOffset, int value);
static int countGsmSeptetsUsingTables(std::string s, bool use7bitOnly,int languageTable, int languageShiftTable);
};
#endif /* GSMALPHABET_H_ */