/* * 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; } }