Code Pretty Print Script

Wednesday, November 13, 2013

It's all in the punctuation‽ #SaveTheDay

Following up from my earlier post about a Hex codec and in honor (or honour) of the upcoming Doctor Who 50th anniversary (ten days and counting), I proudly present a Dalek codec.
Exterminate! Don't talk to me about exterminate!


/*
 * Copyright © 2013 - Elliott Frisch
 * 
 * THIS SOFTWARE IS PROVIDED UNDER THE CREATIVE COMMONS
 * LICENSE 3.0 "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
 * A PARTICULAR PURPOSE.
 * 
 * To use this software you must agree to the complete
 * license terms available at:
 * http://creativecommons.org/licenses/by/3.0/us/deed.en_US
 * 
 * It is the intent of the author(s) that you may use or
 * modify this software for any purpose (including your own
 * commercial gain) provided that this notice remains in its
 * entirety.
 * 
 * Created by Elliott Frisch - www.frischcode.com
 */
package com.frischcode.util;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.StringTokenizer;

/**
 * <b>Rationale:</b> An encoder decoder for any Doctor Who
 * nerd<sup><b>1</b></sup> and a follow-up for an <a href=
 * "http://tinyurl.com/lmmfo8k" >earlier post</a>.
 * 
 * @author <sup><b>1</b></sup>Elliott Frisch
 */
public class DalekCodec implements Codec {
  private static final int findArrayPosition(
      String[] arr, String in) {
    if (in != null && arr != null) {
      for (int i = 0; i < arr.length; ++i) {
        if (in.equals(arr[i])) {
          return i;
        }
      }
    }
    return -1;
  }

  private static final String[] top = new String[] {
      "EXTERMINATE.", "EXTERMINATE\u203d",
      "EXTERMINATE!", "CONQUER!", "CONQUER.",
      "WHO\u203d", "EXPLAIN!", "DESTROY!",
      "CONQUER\u203d", "ANNIHILATE!", "ANNIHILATE.",
      "ANNIHILATE\u203d", "DOCTOR\u203d", "EXPLAIN?",
      "EXPLAIN\u203d", "EXTERMINATE?" };
  private static final String[] bottom;
  static {
    bottom = new String[top.length];
    for (int i = 0; i < top.length; ++i) {
      bottom[i] = top[i].charAt(0)
          + top[i].substring(1).toLowerCase();
    }
  }

  /**
   * @see com.frischcode.util.Codec#encode(byte[])
   */
  @Override
  public String encode(byte[] in) {
    final int len = (in != null) ? in.length : 0;
    StringBuilder sb = new StringBuilder();
    if (len > 0) {
      for (int i = 0; i < len; ++i) {
        if (i != 0) {
          sb.append(' ');
        }
        int val = in[i] - Byte.MIN_VALUE;
        sb.append(top[(val & 0xF0) >> 4]).append(
            bottom[val & 0x0F]);
      }
    }
    return sb.toString();
  }

  /**
   * @see com.frischcode.util.Codec#decode(java.lang.String)
   */
  @Override
  public byte[] decode(String in) {
    if (in != null) {
      in = in.trim();
      List<Byte> bytes = new ArrayList<Byte>();
      StringTokenizer st = new StringTokenizer(in);
      EnumerationIterator<Object> iter = new EnumerationIterator<Object>(
          st);
      while (iter.hasNext()) {
        String token = iter.next().toString();

        int pos = 0;
        for (; pos < token.length(); ++pos) {
          if (Character.isLowerCase(token.charAt(pos))) {
            pos--;
            break;
          }
        }
        if (pos != -1) {
          int t = findArrayPosition(top,
              token.substring(0, pos));
          int b = findArrayPosition(bottom,
              token.substring(pos));
          if (t >= 0 && b >= 0) {
            int val = Byte.MIN_VALUE + ((t << 4) + b);
            bytes.add((byte) val);
          }
        }
      }
      byte[] out = new byte[bytes.size()];
      for (int i = 0; i < bytes.size(); ++i) {
        out[i] = bytes.get(i);
      }
      return out;
    }

    return null;
  }

  public static void main(String[] args) {
    Codec codec = new DalekCodec();
    byte b = Byte.MIN_VALUE;

    // Test every byte once.
    for (;;) {
      String encoded = codec.encode(new byte[] { b });
      if (codec.decode(encoded)[0] == b) {
        System.out.println(encoded);
      }
      if (b + 1 > Byte.MAX_VALUE) {
        break;
      }
      ++b;
    }
    // Test a random array of 2 megabytes.
    byte[] toTest = new byte[2 * 1024 * 1024];
    Random rand = new SecureRandom();
    rand.nextBytes(toTest);
    String encoded = codec.encode(toTest);
    System.out.println("The random array contains "
        + encoded.length() + " encoded characters!");
    byte[] decoded = codec.decode(encoded);
    boolean pass = true;
    if (decoded.length == toTest.length) {
      for (int i = 0; i < toTest.length; ++i) {
        if (toTest[i] != decoded[i]) {
          pass = false;
          break;
        }
      }
      if (pass) {
        System.out.println("Random test passed.");
        System.exit(0);
      }
    }
    System.out.println("Random test failed.");
    System.exit(1);
  }
}
I for one, cannot wait!
Sincerely,
DOCTOR‽Who‽ DOCTOR‽Doctor‽ EXPLAIN‽Doctor‽ EXPLAIN‽Annihilate! DOCTOR‽Exterminate? EXPLAIN?Conquer. EXTERMINATE?Conquer. DOCTOR‽Exterminate. DOCTOR‽Explain! EXPLAIN?Exterminate! DOCTOR‽Annihilate! EXPLAIN?Conquer! DOCTOR‽Conquer! DOCTOR‽Conquer‽ EXPLAIN‽Conquer! EXPLAIN‽Exterminate? DOCTOR‽Conquer. EXPLAIN‽Who‽ ANNIHILATE.Explain‽ EXPLAIN‽Conquer! DOCTOR‽Exterminate? DOCTOR‽Explain?