001    package edu.harvard.deas.hyperenc.util;
002    
003    /**
004     * Converts byte sequences into hex strings.
005     */
006    public class HexCoder
007    {
008      /**
009       * Encodes <code>data</code> as a hex string. <code>data[0]</code> comes first
010       * in the string, followed by the others in order. Each byte is encoded as
011       * specified by {@link java.lang.Integer#toHexString(int)}, except padded with
012       * a leading zero as necessary so that each byte is represented by two
013       * characters. The length of the string is thus exactly
014       * <code>2*data.length</code>.
015       * 
016       * @param data
017       *        An array of bytes. May not be null.
018       * @return The hex encoding of <code>data</code>.
019       */
020      public static String encode(byte[] data) {
021        if (data == null) {
022          throw new IllegalArgumentException("data must not be null");
023        }
024        
025        String str = new String();
026        for(int i = 0; i < data.length; i++) {
027          // Move bytes to unsigned integers and represent as hex
028          // Prepend with 0 if necessary
029          int d = data[i];
030          if (d < 0) d += 256;
031          str += ((d < 16) ? "0" : "") + Integer.toHexString(d);
032        }
033        assert(str.length() % 2 == 0);
034        return str;
035            }
036    
037      /**
038       * Decodes the hex string <code>data</code> and returns the corresponding
039       * bytes. The returned array has size <code>data.length()/2</code>;
040       * <code>data</code> must have even length, and only contain characters 0-9
041       * and a-f.
042       * @param data A hex-encoded string.
043       * @return The byte array encoded by <code>data</code>.
044       * @throws IllegalArgumentException if <code>data</code> does not have even
045       *   length, or if <code>data</code> contains an invalid character (one
046       *   other than 0-9 or a-f)
047       */
048            public static byte[] decode(String data) {
049              if (data.length() % 2 != 0) {
050                throw new IllegalArgumentException(
051                    "data must have even length (length is " + data.length() + ")");
052              }
053              
054        byte [] b = new byte[data.length() / 2];
055        for(int i = 0; i < data.length(); i += 2) {
056          try {
057            int d = Integer.parseInt(data.substring(i, i+2), 16);
058            if (d >= 128) d -= 256;
059            b[i/2] = (byte)d;
060          } catch (NumberFormatException e) {
061            throw new IllegalArgumentException(
062                "data contains an illegal character in byte " + i/2, e);
063          }
064        }
065        return b;
066      }
067    }
068    
069