001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020
021 package org.apache.directory.shared.asn1.codec.binary;
022
023
024 import org.apache.directory.shared.asn1.codec.BinaryDecoder;
025 import org.apache.directory.shared.asn1.codec.BinaryEncoder;
026 import org.apache.directory.shared.asn1.codec.DecoderException;
027 import org.apache.directory.shared.asn1.codec.EncoderException;
028
029
030 /**
031 * Translates between byte arrays and strings of "0"s and "1"s.
032 *
033 * @todo may want to add more bit vector functions like and/or/xor/nand
034 * @todo also might be good to generate boolean[] from byte[] et. cetera.
035 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
036 * @since 1.3
037 * @version $Id $
038 */
039 public class BinaryCodec implements BinaryDecoder, BinaryEncoder
040 {
041 /*
042 * tried to avoid using ArrayUtils to minimize dependencies while using
043 * these empty arrays - dep is just not worth it.
044 */
045 /** Empty char array. */
046 private static final char[] EMPTY_CHAR_ARRAY = new char[0];
047
048 /** Empty byte array. */
049 private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
050
051 /** Mask for bit 0 of a byte. */
052 private static final int BIT_0 = 1;
053
054 /** Mask for bit 1 of a byte. */
055 private static final int BIT_1 = 0x02;
056
057 /** Mask for bit 2 of a byte. */
058 private static final int BIT_2 = 0x04;
059
060 /** Mask for bit 3 of a byte. */
061 private static final int BIT_3 = 0x08;
062
063 /** Mask for bit 4 of a byte. */
064 private static final int BIT_4 = 0x10;
065
066 /** Mask for bit 5 of a byte. */
067 private static final int BIT_5 = 0x20;
068
069 /** Mask for bit 6 of a byte. */
070 private static final int BIT_6 = 0x40;
071
072 /** Mask for bit 7 of a byte. */
073 private static final int BIT_7 = 0x80;
074
075 private static final int[] BITS =
076 { BIT_0, BIT_1, BIT_2, BIT_3, BIT_4, BIT_5, BIT_6, BIT_7 };
077
078
079 /**
080 * Converts an array of raw binary data into an array of ascii 0 and 1
081 * characters.
082 *
083 * @param raw
084 * the raw binary data to convert
085 * @return 0 and 1 ascii character bytes one for each bit of the argument
086 * @see org.apache.directory.shared.asn1.codec.BinaryEncoder#encode(byte[])
087 */
088 public byte[] encode( byte[] raw )
089 {
090 return toAsciiBytes( raw );
091 }
092
093
094 /**
095 * Converts an array of raw binary data into an array of ascii 0 and 1
096 * chars.
097 *
098 * @param raw
099 * the raw binary data to convert
100 * @return 0 and 1 ascii character chars one for each bit of the argument
101 * @throws EncoderException
102 * if the argument is not a byte[]
103 * @see org.apache.directory.shared.asn1.codec.Encoder#encode(java.lang.Object)
104 */
105 public Object encode( Object raw ) throws EncoderException
106 {
107 if ( !( raw instanceof byte[] ) )
108 {
109 throw new EncoderException( "argument not a byte array" );
110 }
111 return toAsciiChars( ( byte[] ) raw );
112 }
113
114
115 /**
116 * Decodes a byte array where each byte represents an ascii '0' or '1'.
117 *
118 * @param ascii
119 * each byte represents an ascii '0' or '1'
120 * @return the raw encoded binary where each bit corresponds to a byte in
121 * the byte array argument
122 * @throws DecoderException
123 * if argument is not a byte[], char[] or String
124 * @see org.apache.directory.shared.asn1.codec.Decoder#decode(java.lang.Object)
125 */
126 public Object decode( Object ascii ) throws DecoderException
127 {
128 if ( ascii == null )
129 {
130 return EMPTY_BYTE_ARRAY;
131 }
132 if ( ascii instanceof byte[] )
133 {
134 return fromAscii( ( byte[] ) ascii );
135 }
136 if ( ascii instanceof char[] )
137 {
138 return fromAscii( ( char[] ) ascii );
139 }
140 if ( ascii instanceof String )
141 {
142 return fromAscii( ( ( String ) ascii ).toCharArray() );
143 }
144 throw new DecoderException( "argument not a byte array" );
145 }
146
147
148 /**
149 * Decodes a byte array where each byte represents an ascii '0' or '1'.
150 *
151 * @param ascii
152 * each byte represents an ascii '0' or '1'
153 * @return the raw encoded binary where each bit corresponds to a byte in
154 * the byte array argument
155 * @see org.apache.directory.shared.asn1.codec.Decoder#decode(Object)
156 */
157 public byte[] decode( byte[] ascii )
158 {
159 return fromAscii( ascii );
160 }
161
162
163 /**
164 * Decodes a String where each char of the String represents an ascii '0' or
165 * '1'.
166 *
167 * @param ascii
168 * String of '0' and '1' characters
169 * @return the raw encoded binary where each bit corresponds to a byte in
170 * the byte array argument
171 * @see org.apache.directory.shared.asn1.codec.Decoder#decode(Object)
172 */
173 public byte[] toByteArray( String ascii )
174 {
175 if ( ascii == null )
176 {
177 return EMPTY_BYTE_ARRAY;
178 }
179 return fromAscii( ascii.toCharArray() );
180 }
181
182
183 // ------------------------------------------------------------------------
184 //
185 // static codec operations
186 //
187 // ------------------------------------------------------------------------
188 /**
189 * Decodes a byte array where each char represents an ascii '0' or '1'.
190 *
191 * @param ascii
192 * each char represents an ascii '0' or '1'
193 * @return the raw encoded binary where each bit corresponds to a char in
194 * the char array argument
195 */
196 public static byte[] fromAscii( char[] ascii )
197 {
198 if ( ascii == null || ascii.length == 0 )
199 {
200 return EMPTY_BYTE_ARRAY;
201 }
202 // get length/8 times bytes with 3 bit shifts to the right of the length
203 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
206 * multiplication every time inside the loop.
207 */
208 for ( int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8 )
209 {
210 for ( int bits = 0; bits < BITS.length; ++bits )
211 {
212 if ( ascii[jj - bits] == '1' )
213 {
214 l_raw[ii] |= BITS[bits];
215 }
216 }
217 }
218 return l_raw;
219 }
220
221
222 /**
223 * Decodes a byte array where each byte represents an ascii '0' or '1'.
224 *
225 * @param ascii
226 * each byte represents an ascii '0' or '1'
227 * @return the raw encoded binary where each bit corresponds to a byte in
228 * the byte array argument
229 */
230 public static byte[] fromAscii( byte[] ascii )
231 {
232 if ( ascii == null || ascii.length == 0 )
233 {
234 return EMPTY_BYTE_ARRAY;
235 }
236 // get length/8 times bytes with 3 bit shifts to the right of the length
237 byte[] l_raw = new byte[ascii.length >> 3];
238 /*
239 * We decr index jj by 8 as we go along to not recompute indices using
240 * multiplication every time inside the loop.
241 */
242 for ( int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8 )
243 {
244 for ( int bits = 0; bits < BITS.length; ++bits )
245 {
246 if ( ascii[jj - bits] == '1' )
247 {
248 l_raw[ii] |= BITS[bits];
249 }
250 }
251 }
252 return l_raw;
253 }
254
255
256 /**
257 * Converts an array of raw binary data into an array of ascii 0 and 1
258 * character bytes - each byte is a truncated char.
259 *
260 * @param raw
261 * the raw binary data to convert
262 * @return an array of 0 and 1 character bytes for each bit of the argument
263 * @see org.apache.directory.shared.asn1.codec.BinaryEncoder#encode(byte[])
264 */
265 public static byte[] toAsciiBytes( byte[] raw )
266 {
267 if ( raw == null || raw.length == 0 )
268 {
269 return EMPTY_BYTE_ARRAY;
270 }
271 // get 8 times the bytes with 3 bit shifts to the left of the length
272 byte[] l_ascii = new byte[raw.length << 3];
273 /*
274 * We decr index jj by 8 as we go along to not recompute indices using
275 * multiplication every time inside the loop.
276 */
277 for ( int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8 )
278 {
279 for ( int bits = 0; bits < BITS.length; ++bits )
280 {
281 if ( ( raw[ii] & BITS[bits] ) == 0 )
282 {
283 l_ascii[jj - bits] = '0';
284 }
285 else
286 {
287 l_ascii[jj - bits] = '1';
288 }
289 }
290 }
291 return l_ascii;
292 }
293
294
295 /**
296 * Converts an array of raw binary data into an array of ascii 0 and 1
297 * characters.
298 *
299 * @param raw
300 * the raw binary data to convert
301 * @return an array of 0 and 1 characters for each bit of the argument
302 * @see org.apache.directory.shared.asn1.codec.BinaryEncoder#encode(byte[])
303 */
304 public static char[] toAsciiChars( byte[] raw )
305 {
306 if ( raw == null || raw.length == 0 )
307 {
308 return EMPTY_CHAR_ARRAY;
309 }
310 // get 8 times the bytes with 3 bit shifts to the left of the length
311 char[] l_ascii = new char[raw.length << 3];
312 /*
313 * We decr index jj by 8 as we go along to not recompute indices using
314 * multiplication every time inside the loop.
315 */
316 for ( int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8 )
317 {
318 for ( int bits = 0; bits < BITS.length; ++bits )
319 {
320 if ( ( raw[ii] & BITS[bits] ) == 0 )
321 {
322 l_ascii[jj - bits] = '0';
323 }
324 else
325 {
326 l_ascii[jj - bits] = '1';
327 }
328 }
329 }
330 return l_ascii;
331 }
332
333
334 /**
335 * Converts an array of raw binary data into a String of ascii 0 and 1
336 * characters.
337 *
338 * @param raw
339 * the raw binary data to convert
340 * @return a String of 0 and 1 characters representing the binary data
341 * @see org.apache.directory.shared.asn1.codec.BinaryEncoder#encode(byte[])
342 */
343 public static String toAsciiString( byte[] raw )
344 {
345 return new String( toAsciiChars( raw ) );
346 }
347 }