// 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() { } }