Mega Code Archive

 
Categories / Java / Internationalization
 

Extends Charset to create Hex Charset

/*  * HexCharset.java  *  * Created on 22 December 2005, 21:56  *  * To change this template, choose Tools | Options and locate the template under  * the Source Creation and Management node. Right-click the template and choose  * Open. You can then make changes to the template in the Source Editor.  */ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; /**  * <p>Codec to translate between hex coding and byte string.</p>  * <p>Hex output is capital if the char set name is given in capitals.</p>  * <p>hex:nn used as a charset name inserts \n after every nnth character.</p>  * @author malcolmm  */ public class HexCharset extends Charset {     private final static String codeHEX = "0123456789ABCDEF";     private final static String codehex = "0123456789abcdef";     private String codes;     private Integer measure;          /** Creates a new instance of HexCharset       * @param caps true for A-F, false for a-f      */     public HexCharset(boolean caps) {         super(caps ? "HEX" : "hex", new String[]{"HEX"});         codes = caps ? codeHEX : codehex;     }          /**      * Construct the charset      * @param caps true for A-F, false for a-f      * @param measure Line width for decoding      */     public HexCharset(boolean caps, int measure) {         super((caps ? "HEX" : "hex") + ":" + measure, new String[]{"HEX"});         codes = caps ? codeHEX : codehex;         this.measure = measure;     }     /**      * Constructs a new encoder for this charset. </p>      *       * @return  A new encoder for this charset      */     public CharsetEncoder newEncoder() {         return new Encoder();     }     /**      * Constructs a new decoder for this charset. </p>      *       * @return  A new decoder for this charset      */     public CharsetDecoder newDecoder() {         return new Decoder();     }     /**      * Tells whether or not this charset contains the given charset.      *       * <p> A charset <i>C</i> is said to <i>contain</i> a charset <i>D</i> if,      * and only if, every character representable in <i>D</i> is also      * representable in <i>C</i>.  If this relationship holds then it is      * guaranteed that every string that can be encoded in <i>D</i> can also be      * encoded in <i>C</i> without performing any replacements.      *       * <p> That <i>C</i> contains <i>D</i> does not imply that each character      * representable in <i>C</i> by a particular byte sequence is represented      * in <i>D</i> by the same byte sequence, although sometimes this is the      * case.      *       * <p> Every charset contains itself.      *       * <p> This method computes an approximation of the containment relation:      * If it returns <tt>true</tt> then the given charset is known to be      * contained by this charset; if it returns <tt>false</tt>, however, then      * it is not necessarily the case that the given charset is not contained      * in this charset.      *       * @return  <tt>true</tt> if, and only if, the given charset      *          is contained in this charset      */     public boolean contains(Charset cs) {         return cs instanceof HexCharset;     }          private class Encoder extends CharsetEncoder {         private boolean unpaired;         private int nyble;         private Encoder() {             super(HexCharset.this, 0.49f, 1f);                      }         /**          * Flushes this encoder.          *           * <p> The default implementation of this method does nothing, and always          * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden          * by encoders that may need to write final bytes to the output buffer          * once the entire input sequence has been read. </p>          *           * @param  out          *         The output byte buffer          *           * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or          *          {@link CoderResult#OVERFLOW}          */         protected java.nio.charset.CoderResult implFlush(java.nio.ByteBuffer out) {             if(!unpaired) {                 implReset();                 return CoderResult.UNDERFLOW;             }             else                 throw new IllegalArgumentException("Hex string must be an even number of digits");         }         /**          * Encodes one or more characters into one or more bytes.          *           * <p> This method encapsulates the basic encoding loop, encoding as many          * characters as possible until it either runs out of input, runs out of room          * in the output buffer, or encounters an encoding error.  This method is          * invoked by the {@link #encode encode} method, which handles result          * interpretation and error recovery.          *           * <p> The buffers are read from, and written to, starting at their current          * positions.  At most {@link Buffer#remaining in.remaining()} characters          * will be read, and at most {@link Buffer#remaining out.remaining()}          * bytes will be written.  The buffers' positions will be advanced to          * reflect the characters read and the bytes written, but their marks and          * limits will not be modified.          *           * <p> This method returns a {@link CoderResult} object to describe its          * reason for termination, in the same manner as the {@link #encode encode}          * method.  Most implementations of this method will handle encoding errors          * by returning an appropriate result object for interpretation by the          * {@link #encode encode} method.  An optimized implementation may instead          * examine the relevant error action and implement that action itself.          *           * <p> An implementation of this method may perform arbitrary lookahead by          * returning {@link CoderResult#UNDERFLOW} until it receives sufficient          * input.  </p>          *           * @param  in          *         The input character buffer          *           * @param  out          *         The output byte buffer          *           * @return  A coder-result object describing the reason for termination          */         public java.nio.charset.CoderResult encodeLoop(java.nio.CharBuffer in, java.nio.ByteBuffer out) {             while(in.remaining() > 0) {                 if(out.remaining() <= 0)                     return CoderResult.OVERFLOW;                 char inch = in.get();                 if(!Character.isWhitespace(inch)) {                     int d = Character.digit(inch, 16);                     if(d < 0)                         throw new IllegalArgumentException("Bad hex character " + inch);                     if(unpaired)                         out.put((byte)(nyble | d));                     else                         nyble = d << 4;                     unpaired = !unpaired;                 }             }             return CoderResult.UNDERFLOW;         }                  /**          * Clear state          */         protected void implReset() {             unpaired = false;             nyble = 0;         }              }          private class Decoder extends CharsetDecoder {         private int charCount;                  private Decoder() {             super(HexCharset.this, 2f, measure == null ? 2f : 2f + (2f / (float)measure));         }         /**          * Decodes one or more bytes into one or more characters.          *           * <p> This method encapsulates the basic decoding loop, decoding as many          * bytes as possible until it either runs out of input, runs out of room          * in the output buffer, or encounters a decoding error.  This method is          * invoked by the {@link #decode decode} method, which handles result          * interpretation and error recovery.          *           * <p> The buffers are read from, and written to, starting at their current          * positions.  At most {@link Buffer#remaining in.remaining()} bytes          * will be read, and at most {@link Buffer#remaining out.remaining()}          * characters will be written.  The buffers' positions will be advanced to          * reflect the bytes read and the characters written, but their marks and          * limits will not be modified.          *           * <p> This method returns a {@link CoderResult} object to describe its          * reason for termination, in the same manner as the {@link #decode decode}          * method.  Most implementations of this method will handle decoding errors          * by returning an appropriate result object for interpretation by the          * {@link #decode decode} method.  An optimized implementation may instead          * examine the relevant error action and implement that action itself.          *           * <p> An implementation of this method may perform arbitrary lookahead by          * returning {@link CoderResult#UNDERFLOW} until it receives sufficient          * input.  </p>          *           * @param  in          *         The input byte buffer          *           * @param  out          *         The output character buffer          *           * @return  A coder-result object describing the reason for termination          */         public java.nio.charset.CoderResult decodeLoop(java.nio.ByteBuffer in, java.nio.CharBuffer out) {             while(in.remaining() > 0) {                 if(measure != null && charCount >= measure) {                     if(out.remaining() == 0)                         return CoderResult.OVERFLOW;                     out.put('\n');                     charCount = 0;                 }                 if(out.remaining() < 2)                     return CoderResult.OVERFLOW;                 int b = in.get() & 0xff;                 out.put(codes.charAt(b >>> 4));                 out.put(codes.charAt(b & 0x0f));                 charCount += 2;             }             return CoderResult.UNDERFLOW;         }         /**          * Resets this decoder, clearing any charset-specific internal state.          *           * <p> The default implementation of this method does nothing.  This method          * should be overridden by decoders that maintain internal state.  </p>          */         protected void implReset() {             charCount = 0;         }              } }