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