1
15 package com.amazonaws.util;
16
17
22 class Base16Codec implements Codec {
23 private static final int OFFSET_OF_a = 'a' - 10;
24 private static final int OFFSET_OF_A = 'A' - 10;
25 private static final int MASK_4BITS = (1 << 4) - 1;
26
27 private static class LazyHolder {
28 private static final byte[] DECODED = decodeTable();
29
30 private static byte[] decodeTable() {
31 final byte[] dest = new byte['f'+1];
32
33 for (int i=0; i <= 'f'; i++)
34 {
35 if (i >= '0' && i <= '9')
36 dest[i] = (byte)(i - '0');
37 else if (i >= 'A' && i <= 'F')
38 dest[i] = (byte)(i - OFFSET_OF_A);
39 else if (i >= 'a' && i <= 'f')
40 dest[i] = (byte)(i - OFFSET_OF_a);
41 else
42 dest[i] = -1;
43 }
44 return dest;
45 }
46 }
47
48 private final byte[] alphabets;
49
50 Base16Codec() {
51 this(true);
52 }
53
54 Base16Codec(boolean upperCase) {
55 this.alphabets = upperCase
56 ? CodecUtils.toBytesDirect("0123456789ABCDEF")
57 : CodecUtils.toBytesDirect("0123456789abcdef");
58 }
59
60 @Override
61 public byte[] encode(byte[] src) {
62 byte[] dest = new byte[src.length * 2];
63 byte p;
64
65 for (int i=0,j=0; i < src.length; i++) {
66 dest[j++] = (byte)alphabets[(p=src[i]) >>> 4 & MASK_4BITS];
67 dest[j++] = (byte)alphabets[p & MASK_4BITS];
68 }
69 return dest;
70 }
71
72 @Override
73 public byte[] decode(byte[] src, final int length)
74 {
75 if (length % 2 != 0) {
76 throw new IllegalArgumentException(
77 "Input is expected to be encoded in multiple of 2 bytes but found: "
78 + length
79 );
80 }
81 final byte[] dest = new byte[length / 2];
82
83 for (int i=0, j=0; j < dest.length; j++)
84 {
85 dest[j] = (byte)
86 (
87 pos(src[i++]) << 4 | pos(src[i++])
88 )
89 ;
90
91 }
92 return dest;
93 }
94
95 protected int pos(byte in) {
96 int pos = LazyHolder.DECODED[in];
97
98 if (pos > -1)
99 return pos;
100 throw new IllegalArgumentException("Invalid base 16 character: \'" + (char)in + "\'");
101 }
102 }
103