/*
* Copyright (C) 2007-2011 Geometer Plus <contact@geometerplus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
package org.geometerplus.fbreader.formats.pdb;
import java.io.*;
public abstract class DocDecompressor {
public static int decompress(InputStream stream, byte[] targetBuffer, int compressedSize) throws IOException {
final byte[] sourceBuffer = new byte[compressedSize];
if (stream.read(sourceBuffer) != compressedSize) {
return 0;
}
int sourceIndex = 0;
int targetIndex = 0;
int count0 = 0;
int count1 = 0;
int count2 = 0;
int count3 = 0;
try {
while (true) {
final byte token = sourceBuffer[sourceIndex++];
switch (token) {
default:
++count0;
targetBuffer[targetIndex++] = token;
break;
case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8:
++count1;
System.arraycopy(sourceBuffer, sourceIndex, targetBuffer, targetIndex, token);
sourceIndex += token;
targetIndex += token;
break;
case -64: case -63: case -62: case -61:
case -60: case -59: case -58: case -57:
case -56: case -55: case -54: case -53:
case -52: case -51: case -50: case -49:
case -48: case -47: case -46: case -45:
case -44: case -43: case -42: case -41:
case -40: case -39: case -38: case -37:
case -36: case -35: case -34: case -33:
case -32: case -31: case -30: case -29:
case -28: case -27: case -26: case -25:
case -24: case -23: case -22: case -21:
case -20: case -19: case -18: case -17:
case -16: case -15: case -14: case -13:
case -12: case -11: case -10: case -9:
case -8: case -7: case -6: case -5:
case -4: case -3: case -2: case -1:
++count2;
targetBuffer[targetIndex++] = ' ';
targetBuffer[targetIndex++] = (byte)(token ^ 0x80);
break;
case -128: case -127: case -126: case -125:
case -124: case -123: case -122: case -121:
case -120: case -119: case -118: case -117:
case -116: case -115: case -114: case -113:
case -112: case -111: case -110: case -109:
case -108: case -107: case -106: case -105:
case -104: case -103: case -102: case -101:
case -100: case -99: case -98: case -97:
case -96: case -95: case -94: case -93:
case -92: case -91: case -90: case -89:
case -88: case -87: case -86: case -85:
case -84: case -83: case -82: case -81:
case -80: case -79: case -78: case -77:
case -76: case -75: case -74: case -73:
case -72: case -71: case -70: case -69:
case -68: case -67: case -66: case -65:
++count3;
final int N = ((token & 0x3F) << 8) + (sourceBuffer[sourceIndex++] & 0xFF);
int copyLength = (N & 7) + 3;
int srcIndex = targetIndex - (N >> 3);
if (targetIndex >= srcIndex + copyLength) {
System.arraycopy(targetBuffer, srcIndex, targetBuffer, targetIndex, copyLength);
targetIndex += copyLength;
} else {
while (copyLength-- > 0) {
targetBuffer[targetIndex++] = targetBuffer[srcIndex++];
}
}
break;
}
}
} catch (Exception e) {
if (targetIndex > targetBuffer.length) {
targetIndex = targetBuffer.length;
}
}
return targetIndex;
}
public static int decompress(byte[] sourceBuffer, byte[] targetBuffer) throws IOException {
int sourceIndex = 0;
int targetIndex = 0;
int count0 = 0;
int count1 = 0;
int count2 = 0;
int count3 = 0;
try {
while (true) {
final byte token = sourceBuffer[sourceIndex++];
switch (token) {
default:
++count0;
targetBuffer[targetIndex++] = token;
break;
case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8:
++count1;
System.arraycopy(sourceBuffer, sourceIndex, targetBuffer, targetIndex, token);
sourceIndex += token;
targetIndex += token;
break;
case -64: case -63: case -62: case -61:
case -60: case -59: case -58: case -57:
case -56: case -55: case -54: case -53:
case -52: case -51: case -50: case -49:
case -48: case -47: case -46: case -45:
case -44: case -43: case -42: case -41:
case -40: case -39: case -38: case -37:
case -36: case -35: case -34: case -33:
case -32: case -31: case -30: case -29:
case -28: case -27: case -26: case -25:
case -24: case -23: case -22: case -21:
case -20: case -19: case -18: case -17:
case -16: case -15: case -14: case -13:
case -12: case -11: case -10: case -9:
case -8: case -7: case -6: case -5:
case -4: case -3: case -2: case -1:
++count2;
targetBuffer[targetIndex++] = ' ';
targetBuffer[targetIndex++] = (byte)(token ^ 0x80);
break;
case -128: case -127: case -126: case -125:
case -124: case -123: case -122: case -121:
case -120: case -119: case -118: case -117:
case -116: case -115: case -114: case -113:
case -112: case -111: case -110: case -109:
case -108: case -107: case -106: case -105:
case -104: case -103: case -102: case -101:
case -100: case -99: case -98: case -97:
case -96: case -95: case -94: case -93:
case -92: case -91: case -90: case -89:
case -88: case -87: case -86: case -85:
case -84: case -83: case -82: case -81:
case -80: case -79: case -78: case -77:
case -76: case -75: case -74: case -73:
case -72: case -71: case -70: case -69:
case -68: case -67: case -66: case -65:
++count3;
final int N = ((token & 0x3F) << 8) + (sourceBuffer[sourceIndex++] & 0xFF);
int copyLength = (N & 7) + 3;//取 N 的后3位 +3
int srcIndex = targetIndex - (N >> 3);//去除 N的后3位
if (targetIndex >= srcIndex + copyLength) {
System.arraycopy(targetBuffer, srcIndex, targetBuffer, targetIndex, copyLength);
targetIndex += copyLength;
} else {
while (copyLength-- > 0) {
targetBuffer[targetIndex++] = targetBuffer[srcIndex++];
}
}
break;
}
}
} catch (Exception e) {
if (targetIndex > targetBuffer.length) {
targetIndex = targetBuffer.length;
}
}
return targetIndex;
}
}