Tagged: base16

Hexadecimal Encoding/Decoding with Java


Representing numbers in hexadecimal form, at least in programming, might still be a very difficult problem. There are plenty of googled results for how we do it in any languages.

DatatypeConverter from JAXB

First and foremost way is definitely using one of existing classes and methods in JDK.

Here comes OpenJDK’s implemention of those method.

public byte[] parseHexBinary(String s) {
    final int len = s.length();

    // "111" is not a valid hex encoding.
    if (len % 2 != 0) {
        throw new IllegalArgumentException("hexBinary needs to be even-length: " + s);
    }

    byte[] out = new byte[len / 2];

    for (int i = 0; i < len; i += 2) {
        int h = hexToBin(s.charAt(i));
        int l = hexToBin(s.charAt(i + 1));
        if (h == -1 || l == -1) {
            throw new IllegalArgumentException("contains illegal character for hexBinary: " + s);
        }

        out[i / 2] = (byte) (h * 16 + l);
    }

    return out;
}

private static int hexToBin(char ch) {
    if ('0' <= ch && ch <= '9') {
        return ch - '0';
    }
    if ('A' <= ch && ch <= 'F') {
        return ch - 'A' + 10;
    }
    if ('a' <= ch && ch <= 'f') {
        return ch - 'a' + 10;
    }
    return -1;
}

private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

public String printHexBinary(byte[] data) {
    StringBuilder r = new StringBuilder(data.length * 2);
    for (byte b : data) {
        r.append(hexCode[(b >> 4) & 0xF]);
        r.append(hexCode[(b & 0xF)]);
    }
    return r.toString();
}

half

number (4bit) character (8bit)
0x0 ( 0) 0x30 ('0')
0x1 ( 1) 0x31 ('1')
0x2 ( 2) 0x32 ('2')
0x3 ( 3) 0x33 ('3')
0x4 ( 4) 0x34 ('4')
0x5 ( 5) 0x35 ('5')
0x6 ( 6) 0x36 ('6')
0x7 ( 7) 0x37 ('7')
0x8 ( 8) 0x38 ('8')
0x9 ( 9) 0x39 ('9')
0xA (10) 0x41 ('A')
0xB (11) 0x42 ('B')
0xC (12) 0x43 ('C')
0xA (13) 0x44 ('D')
0xE (14) 0x45 ('E')
0xF (15) 0x46 ('F')
protected static int encodeHalf(final int decoded) {

    if (decoded < 0x0A) {
        return decoded + 0x30;
    } else {
        return decoded + 0x37;
    }
}


protected static int decodeHalf(final int encoded) {

    if (encoded < 0x41) {
        return encoded - 0x30;
    } else {
        return encoded - 0x37;
    }
}

single

number (8bit) character (16bit)
0x00 (  0) 0x30 0x30 ('00')
.... (  .) .... .... ('..')
0x09 (  9) 0x30 0x39 ('09')
0x0A ( 10) 0x30 0x41 ('0A')
.... ( ..) .... .... ('..')
0x0F ( 15) 0x30 0x46 ('0F')
0x10 ( 16) 0x31 0x30 ('10')
.... ( ..) .... .... ('..')
0x63 ( 99) 0x36 0x33 ('63')
0x64 (100) 0x36 0x34 ('64')
0xC7 (199) 0x43 0x37 ('C7')
0xC8 (200) 0x43 0x38 ('C8')
0xC9 (201) 0x43 0x39 ('C9')
.... (...) .... .... ('..')
0xFF (255) 0x46 0x46 ('FF')
protected static byte[] encodeSingle(final int decoded) {

    final byte[] encoded = new byte[2];

    encoded[0] = (byte) encodeHalf(decoded >> 4);
    encoded[1] = (byte) encodeHalf(decoded & 0x0F);

    return encoded;
}


protected static int decodeSingle(final byte[] encoded) {

    final int high = decodeHalf(encoded[0] & 0xFF);
    final int low = decodeHalf(encoded[1] & 0xFF);

    return (high << 4 | low);
}

multiple

protected static void encodeSingle(final int decoded, final byte[] encoded, final int offset);

protected static int decodeSingle(final byte[] encoded, final int offset);

protected static byte[] encodeMultiple(final byte[] decoded);

protected static byte[] decodeMultiple(final byte[] encoded);

sources

$ svn co http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/ hex-codec

RFC 4648 The Base16, Base32, and Base64 Data Encodings


RFC 4648 The Base16, Base32, and Base64 Data Encodings

name bits/char bytes/word chars/word pad notes
base16 (hex) 4 1 2 N/A
base32 5 5 8 YES
base32hex 5 5 8 YES
base64 6 3 4 YES
base64url 6 3 4 NO

Base.java
Base16.java
Base32.java
Base32Hex.java
Base64.java
Base64Url.java

import java.io.IOException;
import java.util.Arrays;

import jinahya.rfc4648.*;

public class Test {

    private static final PrintStream UTF8;

    static {
        try {
            UTF8 = new PrintStream(System.out, true, "UTF-8");
        } catch (UnsupportedEncodingException uee) {
            throw new InstantiationError(
                "What can I do to make you love me?");
        }
    }
    private static final String[] WELCOMES = {
        "Salaam", "Dobrodošli", "歡迎", "欢迎", "歡迎",
        "Vítáme tĕ", "Velkommen", "Welkom", "Bienvenue", "Wolkom",
        "Willkommen", "Καλώς ορίσατε", "Aloha", "Shalom", "Benvenuto",
        "ようこそ", "환영합니다", "Тавтай морилогтун", "Bem-vindo",
        "Bem-vinda", "Bienvenido", "Välkommen", "Mabuhay", "Swaagatham",
        "Suswaagatham", "Merhaba"};

    public static void main(String[] args) throws IOException {
        if (args.length == 0) {
            test(WELCOMES);
        } else {
            test(args);
        }
    }

    private static void test(final String[] strings) throws IOException {
        for (String string : strings) {
            System.out.printf("%1$5s: %2$s\n", "input", string);
            final byte[] original = string.getBytes("UTF-8");
            System.out.printf("%1$5s: ", "UTF-8");
            for (byte b : original) {
                System.out.printf("%1$s", Integer.toHexString(b & 0xFF));
            }
            System.out.printf("\n");
            test("base64", new Base64(), original);
            test("base64url", new Base64URL(), original);
            test("base32", new Base32(), original);
            test("base32hex", new Base32HEX(), original);
            test("base16", new Base16(), original);
        }
    }

    private static void test(final String name, final Base base,
                             final byte[] original)
        throws IOException {
        final char[] encoded = base.encode(original);
        System.out.printf("\t%1$10s: %2$s\n", name, new String(encoded));
        final byte[] decoded = base.decode(encoded);
        assert Arrays.equals(decoded, original) : "fail";
    }
}
input: Salaam
UTF-8: 53616c61616d
	    base64: U2FsYWFt
	 base64url: U2FsYWFt
	    base32: KNQWYYLBNU======
	 base32hex: ADGMOOB1DK======
	    base16: 53616C61616D
input: Dobrodošli
UTF-8: 446f62726f646fc5a16c69
	    base64: RG9icm9kb8WhbGk=
	 base64url: RG9icm9kb8WhbGk
	    base32: IRXWE4TPMRX4LILMNE======
	 base32hex: 8HNM4SJFCHNSB8BCD4======
	    base16: 446F62726F646FC5A16C69
input: 歡迎
UTF-8: e6ada1e8bf8e
	    base64: 5q2h6L+O
	 base64url: 5q2h6L-O
	    base32: 42W2D2F7RY======
	 base32hex: SQMQ3Q5VHO======
	    base16: E6ADA1E8BF8E
input: 欢迎
UTF-8: e6aca2e8bf8e
	    base64: 5qyi6L+O
	 base64url: 5qyi6L-O
	    base32: 42WKF2F7RY======
	 base32hex: SQMA5Q5VHO======
	    base16: E6ACA2E8BF8E
input: 歡迎
UTF-8: e6ada1e8bf8e
	    base64: 5q2h6L+O
	 base64url: 5q2h6L-O
	    base32: 42W2D2F7RY======
	 base32hex: SQMQ3Q5VHO======
	    base16: E6ADA1E8BF8E
input: Vítáme tĕ
UTF-8: 56c3ad74c3a16d652074c495
	    base64: VsOtdMOhbWUgdMSV
	 base64url: VsOtdMOhbWUgdMSV
	    base32: K3B225GDUFWWKIDUYSKQ====
	 base32hex: AR1QQT63K5MMA83KOIAG====
	    base16: 56C3AD74C3A16D652074C495
input: Velkommen
UTF-8: 56656c6b6f6d6d656e
	    base64: VmVsa29tbWVu
	 base64url: VmVsa29tbWVu
	    base32: KZSWY23PNVWWK3Q=
	 base32hex: APIMOQRFDLMMARG=
	    base16: 56656C6B6F6D6D656E
input: Welkom
UTF-8: 57656c6b6f6d
	    base64: V2Vsa29t
	 base64url: V2Vsa29t
	    base32: K5SWY23PNU======
	 base32hex: ATIMOQRFDK======
	    base16: 57656C6B6F6D
input: Bienvenue
UTF-8: 4269656e76656e7565
	    base64: QmllbnZlbnVl
	 base64url: QmllbnZlbnVl
	    base32: IJUWK3TWMVXHKZI=
	 base32hex: 89KMARJMCLN7AP8=
	    base16: 4269656E76656E7565
input: Wolkom
UTF-8: 576f6c6b6f6d
	    base64: V29sa29t
	 base64url: V29sa29t
	    base32: K5XWY23PNU======
	 base32hex: ATNMOQRFDK======
	    base16: 576F6C6B6F6D
input: Willkommen
UTF-8: 57696c6c6b6f6d6d656e
	    base64: V2lsbGtvbW1lbg==
	 base64url: V2lsbGtvbW1lbg
	    base32: K5UWY3DLN5WW2ZLO
	 base32hex: ATKMOR3BDTMMQPBE
	    base16: 57696C6C6B6F6D6D656E
input: Καλώς ορίσατε
UTF-8: ce9aceb1cebbcf8ecf8220cebfcf81ceafcf83ceb1cf84ceb5
	    base64: zprOsc67z47PgiDOv8+Bzq/Pg86xz4TOtQ==
	 base64url: zprOsc67z47PgiDOv8-Bzq_Pg86xz4TOtQ
	    base32: Z2NM5MOOXPHY5T4CEDHL7T4BZ2X47A6OWHHYJTVV
	 base32hex: PQDCTCEENF7OTJS2437BVJS1PQNSV0UEM77O9JLL
	    base16: CE9ACEB1CEBBCF8ECF8220CEBFCF81CEAFCF83CEB1CF84CEB5
input: Aloha
UTF-8: 416c6f6861
	    base64: QWxvaGE=
	 base64url: QWxvaGE
	    base32: IFWG62DB
	 base32hex: 85M6UQ31
	    base16: 416C6F6861
input: Shalom
UTF-8: 5368616c6f6d
	    base64: U2hhbG9t
	 base64url: U2hhbG9t
	    base32: KNUGC3DPNU======
	 base32hex: ADK62R3FDK======
	    base16: 5368616C6F6D
input: Benvenuto
UTF-8: 42656e76656e75746f
	    base64: QmVudmVudXRv
	 base64url: QmVudmVudXRv
	    base32: IJSW45TFNZ2XI3Y=
	 base32hex: 89IMSTJ5DPQN8RO=
	    base16: 42656E76656E75746F
input: ようこそ
UTF-8: e38288e38186e38193e3819d
	    base64: 44KI44GG44GT44Gd
	 base64url: 44KI44GG44GT44Gd
	    base32: 4OBIRY4BQ3RYDE7DQGOQ====
	 base32hex: SE18HOS1GRHO34V3G6EG====
	    base16: E38288E38186E38193E3819D
input: 환영합니다
UTF-8: ed9998ec9881ed95a9eb8b88eb8ba4
	    base64: 7ZmY7JiB7ZWp64uI64uk
	 base64url: 7ZmY7JiB7ZWp64uI64uk
	    base32: 5WMZR3EYQHWZLKPLROEOXC5E
	 base32hex: TMCPHR4OG7MPBAFBHE4EN2T4
	    base16: ED9998EC9881ED95A9EB8B88EB8BA4
input: Тавтай морилогтун
UTF-8: d0a2d0b0d0b2d182d0b0d0b920d0bcd0bed180d0b8d0bbd0bed0b3d182d183d0bd
	    base64: 0KLQsNCy0YLQsNC5INC80L7RgNC40LvQvtCz0YLRg9C9
	 base64url: 0KLQsNCy0YLQsNC5INC80L7RgNC40LvQvtCz0YLRg9C9
	    base32: 2CRNBMGQWLIYFUFQ2C4SBUF42C7NDAGQXDILXUF62CZ5DAWRQPIL2===
	 base32hex: Q2HD1C6GMB8O5K5GQ2SI1K5SQ2VD306GN38BNK5UQ2PT30MHGF8BQ===
	    base16: D0A2D0B0D0B2D182D0B0D0B920D0BCD0BED180D0B8D0BBD0BED0B3D182D183D0BD
input: Bem-vindo
UTF-8: 42656d2d76696e646f
	    base64: QmVtLXZpbmRv
	 base64url: QmVtLXZpbmRv
	    base32: IJSW2LLWNFXGI3Y=
	 base32hex: 89IMQBBMD5N68RO=
	    base16: 42656D2D76696E646F
input: Bem-vinda
UTF-8: 42656d2d76696e6461
	    base64: QmVtLXZpbmRh
	 base64url: QmVtLXZpbmRh
	    base32: IJSW2LLWNFXGIYI=
	 base32hex: 89IMQBBMD5N68O8=
	    base16: 42656D2D76696E6461
input: Bienvenido
UTF-8: 4269656e76656e69646f
	    base64: QmllbnZlbmlkbw==
	 base64url: QmllbnZlbmlkbw
	    base32: IJUWK3TWMVXGSZDP
	 base32hex: 89KMARJMCLN6IP3F
	    base16: 4269656E76656E69646F
input: Välkommen
UTF-8: 56c3a46c6b6f6d6d656e
	    base64: VsOkbGtvbW1lbg==
	 base64url: VsOkbGtvbW1lbg
	    base32: K3B2I3DLN5WW2ZLO
	 base32hex: AR1Q8R3BDTMMQPBE
	    base16: 56C3A46C6B6F6D6D656E
input: Mabuhay
UTF-8: 4d616275686179
	    base64: TWFidWhheQ==
	 base64url: TWFidWhheQ
	    base32: JVQWE5LIMF4Q====
	 base32hex: 9LGM4TB8C5SG====
	    base16: 4D616275686179
input: Swaagatham
UTF-8: 5377616167617468616d
	    base64: U3dhYWdhdGhhbQ==
	 base64url: U3dhYWdhdGhhbQ
	    base32: KN3WCYLHMF2GQYLN
	 base32hex: ADRM2OB7C5Q6GOBD
	    base16: 5377616167617468616D
input: Suswaagatham
UTF-8: 53757377616167617468616d
	    base64: U3Vzd2FhZ2F0aGFt
	 base64url: U3Vzd2FhZ2F0aGFt
	    base32: KN2XG53BMFTWC5DIMFWQ====
	 base32hex: ADQN6TR1C5JM2T38C5MG====
	    base16: 53757377616167617468616D
input: Merhaba
UTF-8: 4d657268616261
	    base64: TWVyaGFiYQ==
	 base64url: TWVyaGFiYQ
	    base32: JVSXE2DBMJQQ====
	 base32hex: 9LIN4Q31C9GG====
	    base16: 4D657268616261