/*
* Copyright Beijing 58 Information Technology Co.,Ltd.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package com.bj58.spat.gaea.secure;
/**
* BaseNCodec
*
* @author Service Platform Architecture Team (spat@58.com)
*/
public abstract class BaseNCodec{
public static final int MIME_CHUNK_SIZE = 76;
public static final int PEM_CHUNK_SIZE = 64;
private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
private static final int DEFAULT_BUFFER_SIZE = 8192;
protected static final int MASK_8BITS = 0xff;
protected static final byte PAD_DEFAULT = '=';
protected final byte PAD = PAD_DEFAULT;
private final int unencodedBlockSize;
private final int encodedBlockSize;
protected final int lineLength;
private final int chunkSeparatorLength;
protected byte[] buffer;
protected int pos;
private int readPos;
protected boolean eof;
protected int currentLinePos;
protected int modulus;
protected BaseNCodec(int unencodedBlockSize, int encodedBlockSize, int lineLength, int chunkSeparatorLength){
this.unencodedBlockSize = unencodedBlockSize;
this.encodedBlockSize = encodedBlockSize;
this.lineLength = (lineLength > 0 && chunkSeparatorLength > 0) ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
this.chunkSeparatorLength = chunkSeparatorLength;
}
boolean hasData() {
return this.buffer != null;
}
int available() {
return buffer != null ? pos - readPos : 0;
}
protected int getDefaultBufferSize() {
return DEFAULT_BUFFER_SIZE;
}
private void resizeBuffer() {
if (buffer == null) {
buffer = new byte[getDefaultBufferSize()];
pos = 0;
readPos = 0;
} else {
byte[] b = new byte[buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
System.arraycopy(buffer, 0, b, 0, buffer.length);
buffer = b;
}
}
protected void ensureBufferSize(int size){
if ((buffer == null) || (buffer.length < pos + size)){
resizeBuffer();
}
}
int readResults(byte[] b, int bPos, int bAvail) {
if (buffer != null) {
int len = Math.min(available(), bAvail);
System.arraycopy(buffer, readPos, b, bPos, len);
readPos += len;
if (readPos >= pos) {
buffer = null;
}
return len;
}
return eof ? -1 : 0;
}
protected static boolean isWhiteSpace(byte byteToCheck) {
switch (byteToCheck) {
case ' ' :
case '\n' :
case '\r' :
case '\t' :
return true;
default :
return false;
}
}
private void reset() {
buffer = null;
pos = 0;
readPos = 0;
currentLinePos = 0;
modulus = 0;
eof = false;
}
public Object encode(Object pObject) throws Exception {
if (!(pObject instanceof byte[])) {
throw new Exception("Parameter supplied to Base-N encode is not a byte[]");
}
return encode((byte[]) pObject);
}
public String encodeToString(byte[] pArray) {
return StringUtils.newStringUtf8(encode(pArray));
}
public Object decode(Object pObject) throws Exception {
if (pObject instanceof byte[]) {
return decode((byte[]) pObject);
} else if (pObject instanceof String) {
return decode((String) pObject);
} else {
throw new Exception("Parameter supplied to Base-N decode is not a byte[] or a String");
}
}
public byte[] decode(String pArray) {
return decode(StringUtils.getBytesUtf8(pArray));
}
public byte[] decode(byte[] pArray) {
reset();
if (pArray == null || pArray.length == 0) {
return pArray;
}
decode(pArray, 0, pArray.length);
decode(pArray, 0, -1);
byte[] result = new byte[pos];
readResults(result, 0, result.length);
return result;
}
public byte[] encode(byte[] pArray) {
reset();
if (pArray == null || pArray.length == 0) {
return pArray;
}
encode(pArray, 0, pArray.length);
encode(pArray, 0, -1);
byte[] buf = new byte[pos - readPos];
readResults(buf, 0, buf.length);
return buf;
}
public String encodeAsString(byte[] pArray){
return StringUtils.newStringUtf8(encode(pArray));
}
abstract void encode(byte[] pArray, int i, int length);
abstract void decode(byte[] pArray, int i, int length);
protected abstract boolean isInAlphabet(byte value);
public boolean isInAlphabet(byte[] arrayOctet, boolean allowWSPad) {
for (int i = 0; i < arrayOctet.length; i++) {
if (!isInAlphabet(arrayOctet[i]) &&
(!allowWSPad || (arrayOctet[i] != PAD) && !isWhiteSpace(arrayOctet[i]))) {
return false;
}
}
return true;
}
public boolean isInAlphabet(String basen) {
return isInAlphabet(StringUtils.getBytesUtf8(basen), true);
}
protected boolean containsAlphabetOrPad(byte[] arrayOctet) {
if (arrayOctet == null) {
return false;
}
for (int i = 0; i < arrayOctet.length; i++) {
if (PAD == arrayOctet[i] || isInAlphabet(arrayOctet[i])) {
return true;
}
}
return false;
}
public long getEncodedLength(byte[] pArray) {
long len = ((pArray.length + unencodedBlockSize-1) / unencodedBlockSize) * (long) encodedBlockSize;
if (lineLength > 0) {
len += ((len + lineLength-1) / lineLength) * chunkSeparatorLength;
}
return len;
}
}