Coverage Report - org.apache.commons.codec.binary.BinaryCodec
 
Classes in this File Line Coverage Branch Coverage Complexity
BinaryCodec
100%
57/57
100%
50/50
4.182
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.commons.codec.binary;
 19  
 
 20  
 import org.apache.commons.codec.BinaryDecoder;
 21  
 import org.apache.commons.codec.BinaryEncoder;
 22  
 import org.apache.commons.codec.DecoderException;
 23  
 import org.apache.commons.codec.EncoderException;
 24  
 
 25  
 /**
 26  
  * Converts between byte arrays and strings of "0"s and "1"s.
 27  
  *
 28  
  * <p>This class is immutable and thread-safe.</p>
 29  
  *
 30  
  * TODO: may want to add more bit vector functions like and/or/xor/nand
 31  
  * TODO: also might be good to generate boolean[] from byte[] et cetera.
 32  
  *
 33  
  * @since 1.3
 34  
  * @version $Id$
 35  
  */
 36  13
 public class BinaryCodec implements BinaryDecoder, BinaryEncoder {
 37  
     /*
 38  
      * tried to avoid using ArrayUtils to minimize dependencies while using these empty arrays - dep is just not worth
 39  
      * it.
 40  
      */
 41  
     /** Empty char array. */
 42  1
     private static final char[] EMPTY_CHAR_ARRAY = new char[0];
 43  
 
 44  
     /** Empty byte array. */
 45  1
     private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 46  
 
 47  
     /** Mask for bit 0 of a byte. */
 48  
     private static final int BIT_0 = 1;
 49  
 
 50  
     /** Mask for bit 1 of a byte. */
 51  
     private static final int BIT_1 = 0x02;
 52  
 
 53  
     /** Mask for bit 2 of a byte. */
 54  
     private static final int BIT_2 = 0x04;
 55  
 
 56  
     /** Mask for bit 3 of a byte. */
 57  
     private static final int BIT_3 = 0x08;
 58  
 
 59  
     /** Mask for bit 4 of a byte. */
 60  
     private static final int BIT_4 = 0x10;
 61  
 
 62  
     /** Mask for bit 5 of a byte. */
 63  
     private static final int BIT_5 = 0x20;
 64  
 
 65  
     /** Mask for bit 6 of a byte. */
 66  
     private static final int BIT_6 = 0x40;
 67  
 
 68  
     /** Mask for bit 7 of a byte. */
 69  
     private static final int BIT_7 = 0x80;
 70  
 
 71  1
     private static final int[] BITS = {BIT_0, BIT_1, BIT_2, BIT_3, BIT_4, BIT_5, BIT_6, BIT_7};
 72  
 
 73  
     /**
 74  
      * Converts an array of raw binary data into an array of ASCII 0 and 1 characters.
 75  
      *
 76  
      * @param raw
 77  
      *                  the raw binary data to convert
 78  
      * @return 0 and 1 ASCII character bytes one for each bit of the argument
 79  
      * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
 80  
      */
 81  
     @Override
 82  
     public byte[] encode(final byte[] raw) {
 83  27
         return toAsciiBytes(raw);
 84  
     }
 85  
 
 86  
     /**
 87  
      * Converts an array of raw binary data into an array of ASCII 0 and 1 chars.
 88  
      *
 89  
      * @param raw
 90  
      *                  the raw binary data to convert
 91  
      * @return 0 and 1 ASCII character chars one for each bit of the argument
 92  
      * @throws EncoderException
 93  
      *                  if the argument is not a byte[]
 94  
      * @see org.apache.commons.codec.Encoder#encode(Object)
 95  
      */
 96  
     @Override
 97  
     public Object encode(final Object raw) throws EncoderException {
 98  28
         if (!(raw instanceof byte[])) {
 99  1
             throw new EncoderException("argument not a byte array");
 100  
         }
 101  27
         return toAsciiChars((byte[]) raw);
 102  
     }
 103  
 
 104  
     /**
 105  
      * Decodes a byte array where each byte represents an ASCII '0' or '1'.
 106  
      *
 107  
      * @param ascii
 108  
      *                  each byte represents an ASCII '0' or '1'
 109  
      * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
 110  
      * @throws DecoderException
 111  
      *                  if argument is not a byte[], char[] or String
 112  
      * @see org.apache.commons.codec.Decoder#decode(Object)
 113  
      */
 114  
     @Override
 115  
     public Object decode(final Object ascii) throws DecoderException {
 116  57
         if (ascii == null) {
 117  2
             return EMPTY_BYTE_ARRAY;
 118  
         }
 119  55
         if (ascii instanceof byte[]) {
 120  18
             return fromAscii((byte[]) ascii);
 121  
         }
 122  37
         if (ascii instanceof char[]) {
 123  18
             return fromAscii((char[]) ascii);
 124  
         }
 125  19
         if (ascii instanceof String) {
 126  18
             return fromAscii(((String) ascii).toCharArray());
 127  
         }
 128  1
         throw new DecoderException("argument not a byte array");
 129  
     }
 130  
 
 131  
     /**
 132  
      * Decodes a byte array where each byte represents an ASCII '0' or '1'.
 133  
      *
 134  
      * @param ascii
 135  
      *                  each byte represents an ASCII '0' or '1'
 136  
      * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
 137  
      * @see org.apache.commons.codec.Decoder#decode(Object)
 138  
      */
 139  
     @Override
 140  
     public byte[] decode(final byte[] ascii) {
 141  19
         return fromAscii(ascii);
 142  
     }
 143  
 
 144  
     /**
 145  
      * Decodes a String where each char of the String represents an ASCII '0' or '1'.
 146  
      *
 147  
      * @param ascii
 148  
      *                  String of '0' and '1' characters
 149  
      * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
 150  
      * @see org.apache.commons.codec.Decoder#decode(Object)
 151  
      */
 152  
     public byte[] toByteArray(final String ascii) {
 153  19
         if (ascii == null) {
 154  1
             return EMPTY_BYTE_ARRAY;
 155  
         }
 156  18
         return fromAscii(ascii.toCharArray());
 157  
     }
 158  
 
 159  
     // ------------------------------------------------------------------------
 160  
     //
 161  
     // static codec operations
 162  
     //
 163  
     // ------------------------------------------------------------------------
 164  
     /**
 165  
      * Decodes a char array where each char represents an ASCII '0' or '1'.
 166  
      *
 167  
      * @param ascii
 168  
      *                  each char represents an ASCII '0' or '1'
 169  
      * @return the raw encoded binary where each bit corresponds to a char in the char array argument
 170  
      */
 171  
     public static byte[] fromAscii(final char[] ascii) {
 172  75
         if (ascii == null || ascii.length == 0) {
 173  3
             return EMPTY_BYTE_ARRAY;
 174  
         }
 175  
         // get length/8 times bytes with 3 bit shifts to the right of the length
 176  72
         final byte[] l_raw = new byte[ascii.length >> 3];
 177  
         /*
 178  
          * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
 179  
          * loop.
 180  
          */
 181  180
         for (int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8) {
 182  972
             for (int bits = 0; bits < BITS.length; ++bits) {
 183  864
                 if (ascii[jj - bits] == '1') {
 184  576
                     l_raw[ii] |= BITS[bits];
 185  
                 }
 186  
             }
 187  
         }
 188  72
         return l_raw;
 189  
     }
 190  
 
 191  
     /**
 192  
      * Decodes a byte array where each byte represents an ASCII '0' or '1'.
 193  
      *
 194  
      * @param ascii
 195  
      *                  each byte represents an ASCII '0' or '1'
 196  
      * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
 197  
      */
 198  
     public static byte[] fromAscii(final byte[] ascii) {
 199  58
         if (isEmpty(ascii)) {
 200  4
             return EMPTY_BYTE_ARRAY;
 201  
         }
 202  
         // get length/8 times bytes with 3 bit shifts to the right of the length
 203  54
         final byte[] l_raw = new byte[ascii.length >> 3];
 204  
         /*
 205  
          * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
 206  
          * loop.
 207  
          */
 208  135
         for (int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8) {
 209  729
             for (int bits = 0; bits < BITS.length; ++bits) {
 210  648
                 if (ascii[jj - bits] == '1') {
 211  432
                     l_raw[ii] |= BITS[bits];
 212  
                 }
 213  
             }
 214  
         }
 215  54
         return l_raw;
 216  
     }
 217  
 
 218  
     /**
 219  
      * Returns {@code true} if the given array is {@code null} or empty (size 0.)
 220  
      *
 221  
      * @param array
 222  
      *            the source array
 223  
      * @return {@code true} if the given array is {@code null} or empty (size 0.)
 224  
      */
 225  
     private static boolean isEmpty(final byte[] array) {
 226  192
         return array == null || array.length == 0;
 227  
     }
 228  
 
 229  
     /**
 230  
      * Converts an array of raw binary data into an array of ASCII 0 and 1 character bytes - each byte is a truncated
 231  
      * char.
 232  
      *
 233  
      * @param raw
 234  
      *                  the raw binary data to convert
 235  
      * @return an array of 0 and 1 character bytes for each bit of the argument
 236  
      * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
 237  
      */
 238  
     public static byte[] toAsciiBytes(final byte[] raw) {
 239  54
         if (isEmpty(raw)) {
 240  2
             return EMPTY_BYTE_ARRAY;
 241  
         }
 242  
         // get 8 times the bytes with 3 bit shifts to the left of the length
 243  52
         final byte[] l_ascii = new byte[raw.length << 3];
 244  
         /*
 245  
          * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
 246  
          * loop.
 247  
          */
 248  138
         for (int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8) {
 249  774
             for (int bits = 0; bits < BITS.length; ++bits) {
 250  688
                 if ((raw[ii] & BITS[bits]) == 0) {
 251  344
                     l_ascii[jj - bits] = '0';
 252  
                 } else {
 253  344
                     l_ascii[jj - bits] = '1';
 254  
                 }
 255  
             }
 256  
         }
 257  52
         return l_ascii;
 258  
     }
 259  
 
 260  
     /**
 261  
      * Converts an array of raw binary data into an array of ASCII 0 and 1 characters.
 262  
      *
 263  
      * @param raw
 264  
      *                  the raw binary data to convert
 265  
      * @return an array of 0 and 1 characters for each bit of the argument
 266  
      * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
 267  
      */
 268  
     public static char[] toAsciiChars(final byte[] raw) {
 269  80
         if (isEmpty(raw)) {
 270  2
             return EMPTY_CHAR_ARRAY;
 271  
         }
 272  
         // get 8 times the bytes with 3 bit shifts to the left of the length
 273  78
         final char[] l_ascii = new char[raw.length << 3];
 274  
         /*
 275  
          * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
 276  
          * loop.
 277  
          */
 278  207
         for (int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8) {
 279  1161
             for (int bits = 0; bits < BITS.length; ++bits) {
 280  1032
                 if ((raw[ii] & BITS[bits]) == 0) {
 281  516
                     l_ascii[jj - bits] = '0';
 282  
                 } else {
 283  516
                     l_ascii[jj - bits] = '1';
 284  
                 }
 285  
             }
 286  
         }
 287  78
         return l_ascii;
 288  
     }
 289  
 
 290  
     /**
 291  
      * Converts an array of raw binary data into a String of ASCII 0 and 1 characters.
 292  
      *
 293  
      * @param raw
 294  
      *                  the raw binary data to convert
 295  
      * @return a String of 0 and 1 characters representing the binary data
 296  
      * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
 297  
      */
 298  
     public static String toAsciiString(final byte[] raw) {
 299  26
         return new String(toAsciiChars(raw));
 300  
     }
 301  
 }