1. 程式人生 > >中國移動信令XDR TBCD編碼與解碼

中國移動信令XDR TBCD編碼與解碼

最近遇到TBCD解碼、編碼的問題,經過一番查詢。發現其實很簡單。原理其實就是把TBCD的編碼,高4位和第4位互換,然後每4位轉換為十進位制。F為空即可。

例如:

TBCD編碼:  31 55 40 20 79 F9
解碼後原始: 13 55 04 02 97 9
               (號碼隨便敲得,沒有任何含義,如有雷同純屬巧合)

提供一個Java的演算法實現給大家:

// package tbcd;

/**
  * This sample code demonstrates how a character string can be convered to 
  * a TBCD (Telephony Binary Coded Decimal) string and vice versa.
  */

public class TBCDUtil {
    private static String   cTBCDSymbolString = "0123456789*#abc";
    private static char[]   cTBCDSymbols = cTBCDSymbolString.toCharArray();

    public static void main(String[] args) {

        if (args.length == 0)
            return;
       
        byte[] tbcd = parseTBCD(args[0]);

        System.out.println("TBCD as octets: " + dumpBytes(tbcd));
        System.out.println("TBCD octets decoded: " + toTBCD(tbcd));
    }

    /*
	 * This method converts a TBCD string to a character string.
	 */
    public static java.lang.String toTBCD (byte[] tbcd) {

        int size = (tbcd == null ? 0 : tbcd.length);
        StringBuffer buffer = new StringBuffer(2*size);
        for (int i=0; i<size; ++i) {
            int octet = tbcd[i];
            int n2 = (octet >> 4) & 0xF;
            int n1 = octet & 0xF;
            
            if (n1 == 15) {
                    throw new NumberFormatException("Illegal filler in octet n=" + i);
            }
            buffer.append(cTBCDSymbols[n1]);
            
			if (n2 == 15) {
                if (i != size-1)
                    throw new NumberFormatException("Illegal filler in octet n=" + i);
            } else
                buffer.append(cTBCDSymbols[n2]);
        }

        return buffer.toString();
    }

    /*
	 * This method converts a character string to a TBCD string.
	 */
	public static byte[] parseTBCD (java.lang.String tbcd) {
        int length = (tbcd == null ? 0:tbcd.length());
        int size = (length + 1)/2;
        byte[] buffer = new byte[size];

        for (int i=0, i1=0, i2=1; i<size; ++i, i1+=2, i2+=2) {

            char c = tbcd.charAt(i1);
            int n2 = getTBCDNibble(c, i1);
            int octet = 0;
            int n1 = 15;
            if (i2 < length) {
                c = tbcd.charAt(i2);
                n1 = getTBCDNibble(c, i2);
            }
            octet = (n1 << 4) + n2;
            buffer[i] = (byte)(octet & 0xFF);
        }

        return buffer;
    }

    private static int getTBCDNibble(char c, int i1) {

        int n = Character.digit(c, 10);

        if (n < 0 || n > 9) {
            switch (c) {
                case '*':
                    n = 10;
                    break;
                case '#':
                    n = 11;
                    break;
                case 'a':
                    n = 12;
                    break;
                case 'b':
                    n = 13;
                    break;
                case 'c':
                    n = 14;
					break;
                default:
                    throw new NumberFormatException("Bad character '" + c
                            + "' at position " + i1);
            }
        }
        return n;
    }
  /* Hex chars */
  private static final byte[] HEX_CHAR = new byte[]
      { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };


  /*
   * Helper function that dumps an array of bytes in the hexadecimal format.
   */
  public static final String dumpBytes( byte[] buffer )
  {
      if ( buffer == null )
      {
          return "";
      }

      StringBuffer sb = new StringBuffer();

      for ( int i = 0; i < buffer.length; i++ )
      {
          sb.append( "0x" ).append( ( char ) ( HEX_CHAR[( buffer[i] & 0x00F0 ) >> 4] ) ).append(
              ( char ) ( HEX_CHAR[buffer[i] & 0x000F] ) ).append( " " );
      }

      return sb.toString();
  }
}