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

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

The newest version!
/*
 * Mobius Software LTD
 * Copyright 2019, Mobius Software LTD and individual contributors
 * by the @authors tag.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see 
 */

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

import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CoderMalfunctionError;
import java.nio.charset.CoderResult;

import io.netty.buffer.ByteBuf;

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

    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(GSMCharset cs) {
        this.cs = cs;
    }

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

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

    protected CoderResult decodeLoop(ByteBuf in, StringBuilder out) {

        while (in.readableBytes()>0) {

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

            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.readableBytes()==0) {
                            // 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, StringBuilder out) {

        this.decodedBytes++;
        if (this.encodingData != null) {
            if (this.encodingData.septetCount >= 0 && this.decodedBytes > this.encodingData.septetCount)
                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.append(' ');
        else
            out.append((char) code);
    }
    
    public final String decode(ByteBuf in) throws CharacterCodingException {
    	StringBuilder sb = new StringBuilder();
    	if(encodingData.leadingBitsSkipCount!=0)
    	{
    		int currByte = in.readByte() & 0x0FF;
    		if(encodingData.leadingBitsSkipCount==1)
    		{
    			currByte = (byte) (((currByte & 0xFE)) >>> 1);

                 if (this.encodingData != null && this.encodingData.encodingStyle == Gsm7EncodingStyle.bit7_ussd_style
                         && currByte == '\r' && in.readableBytes()==0) {
                     // case when found '\r' at the byte border if USSD style: skip final '\r' char
                 } else
                     putChar((byte)currByte, sb);
    		}
    		else
    		{
	    		bitpos = 7 - encodingData.leadingBitsSkipCount;
	    		leftOver = (byte) (currByte >>> (7 - bitpos));  
	    		
	    		bitpos++;
	            if (bitpos == 7) {
	            	bitpos = 0;
	            }
    		}
    	}
    	
    	try {
            decodeLoop(in, sb);
        } catch (BufferUnderflowException x) {
            throw new CoderMalfunctionError(x);
        } catch (BufferOverflowException x) {
            throw new CoderMalfunctionError(x);
        }

        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy