001/** 002 * Java Web Archive Toolkit - Software to read and validate ARC, WARC 003 * and GZip files. (http://jwat.org/) 004 * Copyright 2011-2012 Netarkivet.dk (http://netarkivet.dk/) 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * 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, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.jwat.common; 019 020import java.io.ByteArrayOutputStream; 021import java.util.Arrays; 022 023/** 024 * Base32 encoder/decoder implementation based on the specifications in 025 * rfc3548. 026 * 027 * @author nicl 028 */ 029public class Base32 { 030 031 /** Ascii table used to encode. */ 032 public static String encodeTab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; 033 034 /** Table used to decode. */ 035 public static byte[] decodeTab = new byte[ 256 ]; 036 037 /** Populate decode table. */ 038 static { 039 Arrays.fill( decodeTab, (byte)0xff ); 040 for ( int i=0; i<encodeTab.length(); ++i ) { 041 decodeTab[ Character.toUpperCase( encodeTab.charAt( i ) ) ] = (byte)i; 042 decodeTab[ Character.toLowerCase( encodeTab.charAt( i ) ) ] = (byte)i; 043 } 044 } 045 046 /** 047 * Static class. 048 */ 049 protected Base32() { 050 } 051 052 /** 053 * Decodes an encoded string. 054 * @param in encoded string. 055 * @param bStrict if true checks for the correct number of trailing "=" 056 * @return decoded string or null 057 */ 058 public static String decodeToString(String in, boolean bStrict) { 059 if (in == null) { 060 return null; 061 } 062 if (in.length() == 0) { 063 return ""; 064 } 065 066 StringBuffer out = new StringBuffer( 256 ); 067 068 boolean b = true; 069 int idx = 0; 070 char cin; 071 int mod = 0; 072 int cIdx; 073 int cout = 0; 074 075 /* 076 * Loop. 077 */ 078 079 while ( b ) { 080 if ( idx < in.length() ) { 081 cin = in.charAt( idx ); 082 if ( cin == '=' ) { 083 b = false; 084 } 085 else { 086 ++idx; 087 cIdx = decodeTab[ cin ]; 088 if ( cIdx != -1 ) { 089 switch ( mod ) { 090 case 0: 091 cout = cIdx << 3; 092 break; 093 case 1: 094 cout |= (cIdx >> 2); 095 out.append( (char)cout ); 096 cout = (cIdx << 6) & 255; 097 break; 098 case 2: 099 cout |= (cIdx << 1); 100 break; 101 case 3: 102 cout |= (cIdx >> 4); 103 out.append( (char)cout ); 104 cout = (cIdx << 4) & 255; 105 break; 106 case 4: 107 cout |= (cIdx >> 1); 108 out.append( (char)cout ); 109 cout = (cIdx << 7) & 255; 110 break; 111 case 5: 112 cout |= cIdx << 2; 113 break; 114 case 6: 115 cout |= (cIdx >> 3); 116 out.append( (char)cout ); 117 cout = (cIdx << 5) & 255; 118 break; 119 case 7: 120 cout |= cIdx; 121 out.append( (char)cout ); 122 break; 123 } 124 mod = ( mod + 1 ) % 8; 125 } 126 else { 127 return null; 128 } 129 } 130 } 131 else { 132 b = false; 133 } 134 } 135 136 /* 137 * Padding. 138 */ 139 140 switch ( mod ) { 141 case 1: 142 // In state 1 only 5 bits of the next 40 bit has been decoded. 143 case 3: 144 // In state 3 1 bit must have also been written in the next byte. 145 case 6: 146 // In state 6 2 bits must have also been written in the next byte. 147 return null; 148 default: 149 if ( bStrict ) { 150 while ( mod != 0 && idx < in.length() && in.charAt( idx ) == '=' ) { 151 ++idx; 152 mod = ( mod + 1 ) % 8; 153 } 154 if (mod != 0 || idx < in.length() ) { 155 return null; 156 } 157 } 158 break; 159 } 160 return out.toString(); 161 } 162 163 /** 164 * Decodes an encoded string. 165 * @param in encoded string. 166 * @param bStrict if true checks for the correct number of trailing "=" 167 * @return decoded byte array or null 168 */ 169 public static byte[] decodeToArray(String in, boolean bStrict) { 170 if (in == null) { 171 return null; 172 } 173 if (in.length() == 0) { 174 return new byte[0]; 175 } 176 177 ByteArrayOutputStream out = new ByteArrayOutputStream(); 178 179 boolean b = true; 180 int idx = 0; 181 char cin; 182 int mod = 0; 183 int cIdx; 184 int cout = 0; 185 186 /* 187 * Loop. 188 */ 189 190 while ( b ) { 191 if ( idx < in.length() ) { 192 cin = in.charAt( idx ); 193 if ( cin == '=' ) { 194 b = false; 195 } 196 else { 197 ++idx; 198 cIdx = decodeTab[ cin ]; 199 if ( cIdx != -1 ) { 200 switch ( mod ) { 201 case 0: 202 cout = cIdx << 3; 203 break; 204 case 1: 205 cout |= (cIdx >> 2); 206 out.write( cout ); 207 cout = (cIdx << 6) & 255; 208 break; 209 case 2: 210 cout |= (cIdx << 1); 211 break; 212 case 3: 213 cout |= (cIdx >> 4); 214 out.write( cout ); 215 cout = (cIdx << 4) & 255; 216 break; 217 case 4: 218 cout |= (cIdx >> 1); 219 out.write( cout ); 220 cout = (cIdx << 7) & 255; 221 break; 222 case 5: 223 cout |= cIdx << 2; 224 break; 225 case 6: 226 cout |= (cIdx >> 3); 227 out.write( cout ); 228 cout = (cIdx << 5) & 255; 229 break; 230 case 7: 231 cout |= cIdx; 232 out.write( cout ); 233 break; 234 } 235 mod = ( mod + 1 ) % 8; 236 } 237 else { 238 return null; 239 } 240 } 241 } 242 else { 243 b = false; 244 } 245 } 246 247 /* 248 * Padding. 249 */ 250 251 switch ( mod ) { 252 case 1: 253 // In state 1 only 5 bits of the next 40 bit has been decoded. 254 case 3: 255 // In state 3 1 bit must have also been written in the next byte. 256 case 6: 257 // In state 6 2 bits must have also been written in the next byte. 258 return null; 259 default: 260 if ( bStrict ) { 261 while ( mod != 0 && idx < in.length() && in.charAt( idx ) == '=' ) { 262 ++idx; 263 mod = ( mod + 1 ) % 8; 264 } 265 if (mod != 0 || idx < in.length() ) { 266 return null; 267 } 268 } 269 break; 270 } 271 return out.toByteArray(); 272 } 273 274 /** 275 * Encodes a string. 276 * @param in unencoded text string. 277 * @return encoded string or null 278 */ 279 public static String encodeString(String in) { 280 if (in == null) { 281 return null; 282 } 283 if (in.length() == 0) { 284 return ""; 285 } 286 287 StringBuffer out = new StringBuffer( 256 ); 288 289 boolean b = true; 290 int idx = 0; 291 int cin; 292 int cout = 0; 293 int mod = 0; 294 295 /* 296 * Loop. 297 */ 298 299 while ( b ) { 300 if ( idx < in.length() ) { 301 cin = in.charAt( idx++ ); 302 if ( cin < 256 ) { 303 switch ( mod ) { 304 case 0: 305 cout = ( cin >> 3 ) & 31; 306 out.append( encodeTab.charAt( cout ) ); 307 cout = ( cin << 2 ) & 31; 308 break; 309 case 1: 310 cout |= ( cin >> 6 ) & 31; 311 out.append( encodeTab.charAt( cout ) ); 312 cout = ( cin >> 1 ) & 31; 313 out.append( encodeTab.charAt( cout ) ); 314 cout = ( cin << 4 ) & 31; 315 break; 316 case 2: 317 cout |= ( cin >> 4 ) & 31; 318 out.append( encodeTab.charAt( cout ) ); 319 cout = ( cin << 1 ) & 31; 320 break; 321 case 3: 322 cout |= ( cin >> 7 ) & 31; 323 out.append( encodeTab.charAt( cout ) ); 324 cout = ( cin >> 2 ) & 31; 325 out.append( encodeTab.charAt( cout ) ); 326 cout = ( cin << 3 ) & 31; 327 break; 328 case 4: 329 cout |= ( cin >> 5 ) & 31; 330 out.append( encodeTab.charAt( cout ) ); 331 cout = cin & 31; 332 out.append( encodeTab.charAt( cout ) ); 333 break; 334 } 335 mod = ( mod + 1 ) % 5; 336 } 337 else { 338 return null; 339 } 340 } 341 else { 342 b = false; 343 } 344 } 345 346 /* 347 * Padding. 348 */ 349 350 switch( mod ) { 351 case 0: 352 break; 353 case 1: 354 out.append( encodeTab.charAt( cout ) ); 355 out.append( "======" ); 356 break; 357 case 2: 358 out.append( encodeTab.charAt( cout ) ); 359 out.append( "====" ); 360 break; 361 case 3: 362 out.append( encodeTab.charAt( cout ) ); 363 out.append( "===" ); 364 break; 365 case 4: 366 out.append( encodeTab.charAt( cout ) ); 367 out.append( "=" ); 368 break; 369 } 370 371 return out.toString(); 372 } 373 374 /** 375 * Encodes a byte array. 376 * @param in byte array. 377 * @return encoded string or null 378 */ 379 public static String encodeArray(byte[] in) { 380 if (in == null) { 381 return null; 382 } 383 if (in.length == 0) { 384 return ""; 385 } 386 387 StringBuffer out = new StringBuffer( 256 ); 388 389 boolean b = true; 390 int idx = 0; 391 int cin; 392 int cout = 0; 393 int mod = 0; 394 395 /* 396 * Loop. 397 */ 398 399 while ( b ) { 400 if ( idx < in.length ) { 401 cin = in[ idx++ ] & 255; 402 switch ( mod ) { 403 case 0: 404 cout = ( cin >> 3 ) & 31; 405 out.append( encodeTab.charAt( cout ) ); 406 cout = ( cin << 2 ) & 31; 407 break; 408 case 1: 409 cout |= ( cin >> 6 ) & 31; 410 out.append( encodeTab.charAt( cout ) ); 411 cout = ( cin >> 1 ) & 31; 412 out.append( encodeTab.charAt( cout ) ); 413 cout = ( cin << 4 ) & 31; 414 break; 415 case 2: 416 cout |= ( cin >> 4 ) & 31; 417 out.append( encodeTab.charAt( cout ) ); 418 cout = ( cin << 1 ) & 31; 419 break; 420 case 3: 421 cout |= ( cin >> 7 ) & 31; 422 out.append( encodeTab.charAt( cout ) ); 423 cout = ( cin >> 2 ) & 31; 424 out.append( encodeTab.charAt( cout ) ); 425 cout = ( cin << 3 ) & 31; 426 break; 427 case 4: 428 cout |= ( cin >> 5 ) & 31; 429 out.append( encodeTab.charAt( cout ) ); 430 cout = cin & 31; 431 out.append( encodeTab.charAt( cout ) ); 432 break; 433 } 434 mod = ( mod + 1 ) % 5; 435 } 436 else { 437 b = false; 438 } 439 } 440 441 /* 442 * Padding. 443 */ 444 445 switch( mod ) { 446 case 0: 447 break; 448 case 1: 449 out.append( encodeTab.charAt( cout ) ); 450 out.append( "======" ); 451 break; 452 case 2: 453 out.append( encodeTab.charAt( cout ) ); 454 out.append( "====" ); 455 break; 456 case 3: 457 out.append( encodeTab.charAt( cout ) ); 458 out.append( "===" ); 459 break; 460 case 4: 461 out.append( encodeTab.charAt( cout ) ); 462 out.append( "=" ); 463 break; 464 } 465 466 return out.toString(); 467 } 468 469}