at.tuwien.mnsa.smssender.SMSPDUConverter.java Source code

Java tutorial

Introduction

Here is the source code for at.tuwien.mnsa.smssender.SMSPDUConverter.java

Source

/*
 * 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);
    }
}