blob: 3bcdcd25e8226468844ec8f3f5f17b1d4d3676df [file] [log] [blame]
// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This code is based heavily on Robert Harder's <rob@iharder.net>
// public domain Base64 class, version 2.1.
//
package com.google.gerrit.httpd;
/** Base64 encoder which uses a language safe within HTTP cookies. */
class CookieBase64 {
private static final char[] enc;
static {
enc = new char[64];
int o = 0;
o = fill(enc, o, 'a', 'z');
o = fill(enc, o, 'A', 'Z');
o = fill(enc, o, '0', '9');
enc[o++] = '-';
enc[o++] = '.';
}
private static int fill(final char[] out, int o, final char f, final int l) {
for (char c = f; c <= l; c++)
out[o++] = c;
return o;
}
static String encode(final byte[] in) {
final StringBuilder out = new StringBuilder(in.length * 4 / 3);
final int len2 = in.length - 2;
int d = 0;
for (; d < len2; d += 3) {
encode3to4(out, in, d, 3);
}
if (d < in.length) {
encode3to4(out, in, d, in.length - d);
}
return out.toString();
}
private static void encode3to4(final StringBuilder out, final byte[] in,
final int inOffset, final int numSigBytes) {
// 1 2 3
// 01234567890123456789012345678901 Bit position
// --------000000001111111122222222 Array position from threeBytes
// --------| || || || | Six bit groups to index ALPHABET
// >>18 >>12 >> 6 >> 0 Right shift necessary
// 0x3f 0x3f 0x3f Additional AND
// Create buffer with zero-padding if there are only one or two
// significant bytes passed in the array.
// We have to shift left 24 in order to flush out the 1's that appear
// when Java treats a value as negative that is cast from a byte to an int.
//
int inBuff = ( numSigBytes > 0 ? ((in[ inOffset ] << 24) >>> 8) : 0 )
| ( numSigBytes > 1 ? ((in[ inOffset + 1 ] << 24) >>> 16) : 0 )
| ( numSigBytes > 2 ? ((in[ inOffset + 2 ] << 24) >>> 24) : 0 );
switch (numSigBytes) {
case 3:
out.append(enc[(inBuff >>> 18)]);
out.append(enc[(inBuff >>> 12) & 0x3f]);
out.append(enc[(inBuff >>> 6) & 0x3f]);
out.append(enc[(inBuff) & 0x3f]);
break;
case 2:
out.append(enc[(inBuff >>> 18)]);
out.append(enc[(inBuff >>> 12) & 0x3f]);
out.append(enc[(inBuff >>> 6) & 0x3f]);
break;
case 1:
out.append(enc[(inBuff >>> 18)]);
out.append(enc[(inBuff >>> 12) & 0x3f]);
break;
default:
break;
}
}
private CookieBase64() {
}
}