All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.restcomm.protocols.ss7.map.datacoding.GSMCharsetDecoder Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.restcomm.protocols.ss7.map.datacoding;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;

/**
 *
 * @author amit bhayani
 * @author sergey vetyutnev
 *
 */
public class GSMCharsetDecoder extends CharsetDecoder {

    private byte[] mask = new byte[] { 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 };

    private int bitpos = 0;
    private int decodedBytes = 0;
    private byte leftOver;
    private GSMCharset cs;
    private boolean escape;
    private GSMCharsetDecodingData encodingData;

    /**
     * Constructs a Decoder.
     */
    protected GSMCharsetDecoder(Charset cs, float averageCharsPerByte, float maxCharsPerByte) {
        super(cs, averageCharsPerByte, maxCharsPerByte);
        implReset();
        this.cs = (GSMCharset) cs;
    }

    public void setGSMCharsetDecodingData(GSMCharsetDecodingData encodingData) {
        this.encodingData = encodingData;
    }

    public GSMCharsetDecodingData getGSMCharsetDecodingData() {
        return this.encodingData;
    }

    @Override
    protected void implReset() {
        bitpos = 0;
        decodedBytes = 0;
        leftOver = 0;
        escape = false;
    }

    // TODO is this ok?
    @Override
    protected CoderResult implFlush(CharBuffer out) {
        return CoderResult.UNDERFLOW;
    }

    @Override
    protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {

        while (in.hasRemaining()) {

            // If CharBuffer doesnt have anything remaining, lets send OVERFLOW.
            // But ideally this should never happen as size of out is calculated
            // using the available bytes in in parameter
            if (!out.hasRemaining()) {
                return CoderResult.OVERFLOW;
            }

            // Read the first byte
            byte data = in.get();

            if (this.encodingData != null && this.encodingData.encodingStyle == Gsm7EncodingStyle.bit8_smpp_style) {
                putChar(data, out);
            } else {
                // take back-up of byte
                byte tempData = data;

                // System.out.println("data = "+ Integer.toBinaryString(data));

                // the rest of bits that we don't need now but for next iteration
                byte tempCurrHol = (byte) ((data & 0xFF) >>> (7 - bitpos));

                // System.out.println("Current = "+
                // Integer.toBinaryString(current));

                // The bits that will be consumed for formation of current char
                data = (byte) (data & mask[bitpos]);

                if (bitpos != 0) {
                    // we don't have enough bits to form char, we need to use the
                    // bits
                    // from previous iteration

                    // Move the curent bits read to left and append the previous
                    // bits
                    data = (byte) (data << bitpos);
                    data = (byte) (data | leftOver);

                    // We have 7 bits now to form char
                    putChar(data, out);

                    // This means we not only used previous 6 bits and 1 bit from
                    // current byte to form char, but now we also have 7 bits left
                    // over from current byte and hence we can get another char
                    if (bitpos == 6) {
                        data = (byte) (((tempData & 0xFE)) >>> 1);

                        if (this.encodingData != null && this.encodingData.encodingStyle == Gsm7EncodingStyle.bit7_ussd_style
                                && data == '\r' && !in.hasRemaining()) {
                            // case when found '\r' at the byte border if USSD style: skip final '\r' char
                        } else
                            putChar(data, out);
                    }
                } else {
                    // For this iteration we have all 7 bits to form the char
                    // from byte that we read
                    putChar(data, out);
                }

                // assign the left over bits
                leftOver = tempCurrHol;

                bitpos++;
                if (bitpos == 7) {
                    bitpos = 0;
                }
            }
        }

        return CoderResult.UNDERFLOW;
    }

    private void putChar(byte data, CharBuffer out) {

        this.decodedBytes++;
        if (this.encodingData != null) {
            if (this.decodedBytes <= this.encodingData.leadingSeptetSkipCount)
                return;
            if (this.encodingData.totalSeptetCount >= 0 && this.decodedBytes > this.encodingData.totalSeptetCount)
                return;
        }

        int code = 0;
        if (data >= 0 && data < 128) {
            if (escape) {
                escape = false;
                if (this.cs.extensionTable != null)
                    code = this.cs.extensionTable[data];
            } else {
                if (data == GSMCharset.ESCAPE) {
                    escape = true;
                    return;
                } else {
                    code = this.cs.mainTable[data];
                }
            }
        }

        if (code == 0)
            out.put(' ');
        else
            out.put((char) code);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy