Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package at.tuwien.mnsa.smssender; import java.util.BitSet; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Logger; import javax.xml.bind.DatatypeConverter; import org.apache.commons.lang3.ArrayUtils; /** * * @author Thomas */ public class SMSPDUConverter { //Alphabets private final Map<String, Byte> GSM_3GPP_TS_23_038 = new HashMap<>(); private final Map<String, Byte> GSM_3GPP_TS_23_038_EXTENSION = new HashMap<>(); private static SMSPDUConverter instance; private SMSPDUConverter() { loadAlphabets(); //Logger.getGlobal().setLevel(Level.ALL); } public static SMSPDUConverter getInstance() { if (instance == null) { instance = new SMSPDUConverter(); } return instance; } /** * Get the PDU encoding for the given message * @param message * @return */ public SMSPDUConversionResult getContent(String message) { return this.getContent(message, 0); } /** * Get the PDU encoding for the given message * @param message * @param rightshift of the content for concatination * @return */ public SMSPDUConversionResult getContent(String message, int rightshift) { List<Byte> finalized = new LinkedList<>(); BitSet currentWorkingBS = new BitSet(16); int currentShiftpos = 0; boolean currentlyExtended = false; int len = 0; //repeat while there are characters left while (message.length() > 0) { String c = message.substring(0, 1); message = message.substring(1); byte value; //loook up current character if (this.GSM_3GPP_TS_23_038.containsKey(c)) { value = this.GSM_3GPP_TS_23_038.get(c); } else { if (this.GSM_3GPP_TS_23_038_EXTENSION.containsKey(c)) { if (!currentlyExtended) { //extension -> now do the escape character! //do the "new" character the other round message = c + message; currentlyExtended = true; value = this.GSM_3GPP_TS_23_038.get("\u001B"); } else { //we just did the ecsape character, now do the char from //the extended alphabet value = this.GSM_3GPP_TS_23_038_EXTENSION.get(c); currentlyExtended = false; } } else { throw new RuntimeException("Not found: " + c); } } //start at 0x0 if (currentShiftpos == 0) { //add current char beginning at pos 0 addByteToBitset(value, currentWorkingBS, 0, 1, 7); } else { //else start at second byte and do flipping //make place for the right bits of the current char in the front currentWorkingBS = rightShiftBitset(currentWorkingBS, currentShiftpos); //add last X bits in front of the bitset addByteToBitset(value, currentWorkingBS, 0, 8 - currentShiftpos, currentShiftpos); //add the first X bits at the end of the bitset if any if (currentShiftpos < 7) { addByteToBitset(value, currentWorkingBS, 8, 1, 7 - currentShiftpos); } //the first byte of the bitset is now complete! :) byte finalByte = currentWorkingBS.toByteArray()[0]; finalByte = swapEndianFormat(finalByte); finalized.add(finalByte); //shift bitset left by 8 bits since we just finished and exported a byte currentWorkingBS = leftShiftBitset(currentWorkingBS, 8); } currentShiftpos = (currentShiftpos + 1) % 8; len++; //for first character -> just add to the bitset //addByteToBitset(value, bitset, i*7); /*//exchange characters for (int j=0;j<((i%8)*8-(i%8)*7);j++) { boolean cBit = content.get() }*/ } //add last byte (swap back our eagerly shifted byte) if (currentShiftpos == 7) { byte finalByte = 0x00; finalized.add(finalByte); } else if (currentShiftpos != 0) { byte finalByte = (currentWorkingBS.isEmpty()) ? 0x0 : currentWorkingBS.toByteArray()[0]; finalByte = swapEndianFormat(finalByte); //I don't really know why, //but java fills right shifts with 1s //so we have to manually set all new (left) bits to zero for (int i = 0; i < currentShiftpos; i++) { finalByte = (byte) (finalByte >> 1); finalByte = (byte) (finalByte & 0x7F); //unset first bit } //finalByte = (byte) (finalByte & 0x3F); finalized.add(finalByte); } byte[] finalM = ArrayUtils.toPrimitive(finalized.toArray(new Byte[finalized.size()])); Logger.getGlobal().info("1: " + DatatypeConverter.printHexBinary(finalM)); //in case of rightshift for concatenation -> right shift the whole array if (rightshift > 0) { BitSet bs = BitSet.valueOf(finalM); bs = rightShiftBitset(bs, rightshift); finalM = bs.toByteArray(); Logger.getGlobal().info("2: " + DatatypeConverter.printHexBinary(finalM)); } SMSPDUConversionResult res = new SMSPDUConversionResult(finalM, len); return res; } /** * Class representing the PDU result of a message */ public class SMSPDUConversionResult { public final byte[] message; public final int len; private SMSPDUConversionResult(byte[] message, int len) { this.message = message; this.len = len; } @Override public String toString() { return "len: " + len + ", message: " + DatatypeConverter.printHexBinary(message); } } /** * Swap endian format * from http://stackoverflow.com/questions/3842828/converting-little-endian-to-big-endian * @param b * @return byte with swapped endian format */ private static byte swapEndianFormat(byte b) { int converted = 0x00; converted ^= (b & 0b1000_0000) >> 7; converted ^= (b & 0b0100_0000) >> 5; converted ^= (b & 0b0010_0000) >> 3; converted ^= (b & 0b0001_0000) >> 1; converted ^= (b & 0b0000_1000) << 1; converted ^= (b & 0b0000_0100) << 3; converted ^= (b & 0b0000_0010) << 5; converted ^= (b & 0b0000_0001) << 7; return (byte) (converted & 0xFF); } private BitSet leftShiftBitset(BitSet bitset, int positions) { return bitset.get(positions, Math.max(positions, bitset.length())); } /** * Right shift a bitset * @param bitset * @param positions * @return */ private BitSet rightShiftBitset(BitSet bitset, int positions) { for (int j = 0; j < positions; j++) { for (int i = bitset.length(); i > 0; i--) { bitset.set(i, bitset.get(i - 1)); } bitset.set(j, false); } return bitset; } /** * Add a byte to a bitset * @param b the byte * @param bitset the bitset * @param startpositionBitset where to start inserting in the bitset * @param startpositionByte where to start inserting from the byte * @param len how many bits of the byte have to be inserted */ private void addByteToBitset(byte b, BitSet bitset, int startpositionBitset, int startpositionByte, int len) { b = (byte) (b << startpositionByte); for (int i = startpositionByte; i < (startpositionByte + len); i++) { boolean bit = (b & 0x80) != 0; bitset.set(startpositionBitset + (i - startpositionByte), bit); //set the most significant bit of the byte; 0x80 == 1000.000 b = (byte) (b << 1); } } private void loadAlphabets() { GSM_3GPP_TS_23_038.put("@", (byte) 0x0); GSM_3GPP_TS_23_038.put("?", (byte) 0x10); GSM_3GPP_TS_23_038.put(" ", (byte) 0x20); GSM_3GPP_TS_23_038.put("0", (byte) 0x30); GSM_3GPP_TS_23_038.put("", (byte) 0x40); GSM_3GPP_TS_23_038.put("P", (byte) 0x50); GSM_3GPP_TS_23_038.put("", (byte) 0x60); GSM_3GPP_TS_23_038.put("p", (byte) 0x70); GSM_3GPP_TS_23_038.put("", (byte) 0x1); GSM_3GPP_TS_23_038.put("_", (byte) 0x11); GSM_3GPP_TS_23_038.put("!", (byte) 0x21); GSM_3GPP_TS_23_038.put("1", (byte) 0x31); GSM_3GPP_TS_23_038.put("A", (byte) 0x41); GSM_3GPP_TS_23_038.put("Q", (byte) 0x51); GSM_3GPP_TS_23_038.put("a", (byte) 0x61); GSM_3GPP_TS_23_038.put("q", (byte) 0x71); GSM_3GPP_TS_23_038.put("$", (byte) 0x2); GSM_3GPP_TS_23_038.put("F", (byte) 0x12); GSM_3GPP_TS_23_038.put("\"", (byte) 0x22); GSM_3GPP_TS_23_038.put("2", (byte) 0x32); GSM_3GPP_TS_23_038.put("B", (byte) 0x42); GSM_3GPP_TS_23_038.put("R", (byte) 0x52); GSM_3GPP_TS_23_038.put("b", (byte) 0x62); GSM_3GPP_TS_23_038.put("r", (byte) 0x72); GSM_3GPP_TS_23_038.put("", (byte) 0x3); GSM_3GPP_TS_23_038.put("G", (byte) 0x13); GSM_3GPP_TS_23_038.put("#", (byte) 0x23); GSM_3GPP_TS_23_038.put("3", (byte) 0x33); GSM_3GPP_TS_23_038.put("C", (byte) 0x43); GSM_3GPP_TS_23_038.put("S", (byte) 0x53); GSM_3GPP_TS_23_038.put("c", (byte) 0x63); GSM_3GPP_TS_23_038.put("s", (byte) 0x73); GSM_3GPP_TS_23_038.put("", (byte) 0x4); GSM_3GPP_TS_23_038.put("?", (byte) 0x14); GSM_3GPP_TS_23_038.put("", (byte) 0x24); GSM_3GPP_TS_23_038.put("4", (byte) 0x34); GSM_3GPP_TS_23_038.put("D", (byte) 0x44); GSM_3GPP_TS_23_038.put("T", (byte) 0x54); GSM_3GPP_TS_23_038.put("d", (byte) 0x64); GSM_3GPP_TS_23_038.put("t", (byte) 0x74); GSM_3GPP_TS_23_038.put("", (byte) 0x5); GSM_3GPP_TS_23_038.put("O", (byte) 0x15); GSM_3GPP_TS_23_038.put("%", (byte) 0x25); GSM_3GPP_TS_23_038.put("5", (byte) 0x35); GSM_3GPP_TS_23_038.put("E", (byte) 0x45); GSM_3GPP_TS_23_038.put("U", (byte) 0x55); GSM_3GPP_TS_23_038.put("e", (byte) 0x65); GSM_3GPP_TS_23_038.put("u", (byte) 0x75); GSM_3GPP_TS_23_038.put("", (byte) 0x6); GSM_3GPP_TS_23_038.put("?", (byte) 0x16); GSM_3GPP_TS_23_038.put("&", (byte) 0x26); GSM_3GPP_TS_23_038.put("6", (byte) 0x36); GSM_3GPP_TS_23_038.put("F", (byte) 0x46); GSM_3GPP_TS_23_038.put("V", (byte) 0x56); GSM_3GPP_TS_23_038.put("f", (byte) 0x66); GSM_3GPP_TS_23_038.put("v", (byte) 0x76); GSM_3GPP_TS_23_038.put("", (byte) 0x7); GSM_3GPP_TS_23_038.put("?", (byte) 0x17); GSM_3GPP_TS_23_038.put("'", (byte) 0x27); GSM_3GPP_TS_23_038.put("7", (byte) 0x37); GSM_3GPP_TS_23_038.put("G", (byte) 0x47); GSM_3GPP_TS_23_038.put("W", (byte) 0x57); GSM_3GPP_TS_23_038.put("g", (byte) 0x67); GSM_3GPP_TS_23_038.put("w", (byte) 0x77); GSM_3GPP_TS_23_038.put("", (byte) 0x8); GSM_3GPP_TS_23_038.put("", (byte) 0x18); GSM_3GPP_TS_23_038.put("(", (byte) 0x28); GSM_3GPP_TS_23_038.put("8", (byte) 0x38); GSM_3GPP_TS_23_038.put("H", (byte) 0x48); GSM_3GPP_TS_23_038.put("X", (byte) 0x58); GSM_3GPP_TS_23_038.put("h", (byte) 0x68); GSM_3GPP_TS_23_038.put("x", (byte) 0x78); GSM_3GPP_TS_23_038.put("", (byte) 0x9); GSM_3GPP_TS_23_038.put("", (byte) 0x19); GSM_3GPP_TS_23_038.put(")", (byte) 0x29); GSM_3GPP_TS_23_038.put("9", (byte) 0x39); GSM_3GPP_TS_23_038.put("I", (byte) 0x49); GSM_3GPP_TS_23_038.put("Y", (byte) 0x59); GSM_3GPP_TS_23_038.put("i", (byte) 0x69); GSM_3GPP_TS_23_038.put("y", (byte) 0x79); GSM_3GPP_TS_23_038.put("\n", (byte) 0xA); GSM_3GPP_TS_23_038.put("?", (byte) 0x1A); GSM_3GPP_TS_23_038.put("*", (byte) 0x2A); GSM_3GPP_TS_23_038.put(":", (byte) 0x3A); GSM_3GPP_TS_23_038.put("J", (byte) 0x4A); GSM_3GPP_TS_23_038.put("Z", (byte) 0x5A); GSM_3GPP_TS_23_038.put("j", (byte) 0x6A); GSM_3GPP_TS_23_038.put("z", (byte) 0x7A); GSM_3GPP_TS_23_038.put("", (byte) 0xB); GSM_3GPP_TS_23_038.put("\u001B", (byte) 0x1B); GSM_3GPP_TS_23_038.put("+", (byte) 0x2B); GSM_3GPP_TS_23_038.put(";", (byte) 0x3B); GSM_3GPP_TS_23_038.put("K", (byte) 0x4B); GSM_3GPP_TS_23_038.put("", (byte) 0x5B); GSM_3GPP_TS_23_038.put("k", (byte) 0x6B); GSM_3GPP_TS_23_038.put("", (byte) 0x7B); GSM_3GPP_TS_23_038.put("", (byte) 0xC); GSM_3GPP_TS_23_038.put("", (byte) 0x1C); GSM_3GPP_TS_23_038.put(",", (byte) 0x2C); GSM_3GPP_TS_23_038.put("<", (byte) 0x3C); GSM_3GPP_TS_23_038.put("L", (byte) 0x4C); GSM_3GPP_TS_23_038.put("", (byte) 0x5C); GSM_3GPP_TS_23_038.put("l", (byte) 0x6C); GSM_3GPP_TS_23_038.put("", (byte) 0x7C); GSM_3GPP_TS_23_038.put("\r", (byte) 0xD); GSM_3GPP_TS_23_038.put("", (byte) 0x1D); GSM_3GPP_TS_23_038.put("-", (byte) 0x2D); GSM_3GPP_TS_23_038.put("=", (byte) 0x3D); GSM_3GPP_TS_23_038.put("M", (byte) 0x4D); GSM_3GPP_TS_23_038.put("", (byte) 0x5D); GSM_3GPP_TS_23_038.put("m", (byte) 0x6D); GSM_3GPP_TS_23_038.put("", (byte) 0x7D); GSM_3GPP_TS_23_038.put("", (byte) 0xE); GSM_3GPP_TS_23_038.put("", (byte) 0x1E); GSM_3GPP_TS_23_038.put(".", (byte) 0x2E); GSM_3GPP_TS_23_038.put(">", (byte) 0x3E); GSM_3GPP_TS_23_038.put("N", (byte) 0x4E); GSM_3GPP_TS_23_038.put("", (byte) 0x5E); GSM_3GPP_TS_23_038.put("n", (byte) 0x6E); GSM_3GPP_TS_23_038.put("", (byte) 0x7E); GSM_3GPP_TS_23_038.put("", (byte) 0xF); GSM_3GPP_TS_23_038.put("", (byte) 0x1F); GSM_3GPP_TS_23_038.put("/", (byte) 0x2F); GSM_3GPP_TS_23_038.put("?", (byte) 0x3F); GSM_3GPP_TS_23_038.put("O", (byte) 0x4F); GSM_3GPP_TS_23_038.put("", (byte) 0x5F); GSM_3GPP_TS_23_038.put("o", (byte) 0x6F); GSM_3GPP_TS_23_038.put("", (byte) 0x7F); GSM_3GPP_TS_23_038_EXTENSION.put("|", (byte) 0x40); GSM_3GPP_TS_23_038_EXTENSION.put("^", (byte) 0x14); GSM_3GPP_TS_23_038_EXTENSION.put("", (byte) 0x65); GSM_3GPP_TS_23_038_EXTENSION.put("{", (byte) 0x28); GSM_3GPP_TS_23_038_EXTENSION.put("}", (byte) 0x29); GSM_3GPP_TS_23_038_EXTENSION.put("[", (byte) 0x3C); GSM_3GPP_TS_23_038_EXTENSION.put("]", (byte) 0x3E); GSM_3GPP_TS_23_038_EXTENSION.put("~", (byte) 0x3D); GSM_3GPP_TS_23_038_EXTENSION.put("\\", (byte) 0x2F); } }