/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.wave.communication;
import com.google.common.base.Preconditions;
/**
* Trivial encode/decoder of byte arrays and char arrays.
*
* @author hearnden@google.com (David Hearnden)
*/
// The encoding used here can be replaced with any trusted encoding scheme
// (i.e., not 500+ lines of if statements and quirk explanations).
public final class Codec {
private final static char[] digits =
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
private static char toDigit(int b) {
assert 0 <= b && b <= 0xF;
return digits[b];
}
private static int toNumber(char c) {
if ('0' <= c && c <= '9') {
return (c - '0');
} else if ('A' <= c && c <= 'F') {
return (c - 'A' + 0xA);
} else {
throw new IllegalArgumentException("Not a hexadecimal digit: " + c);
}
}
/**
* Encodes an arbitrary byte array as an array of characters.
*/
public static String encode(byte[] decoded) {
char[] encoded = new char[decoded.length * 2];
for (int i = 0; i < decoded.length; i++) {
byte b = decoded[i];
encoded[i * 2 + 0] = toDigit((b >> 4) & 0xF);
encoded[i * 2 + 1] = toDigit((b >> 0) & 0xF);
}
return new String(encoded);
}
/**
* Decodes an {@link #encode(byte[]) encoded} character array to a byte array.
*
* @throws IllegalArgumentException if {@code encoded} is not a valid
* encoding.
*/
public static byte[] decode(String s) {
char [] encoded = s.toCharArray();
Preconditions.checkArgument(encoded.length % 2 == 0);
byte[] decoded = new byte[encoded.length / 2];
for (int i = 0; i < decoded.length; i++) {
char hi = encoded[i * 2 + 0];
char lo = encoded[i * 2 + 1];
decoded[i] = (byte) ((toNumber(hi) << 4) + toNumber(lo));
}
return decoded;
}
}