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