All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ggasoftware.parso.CharDecompressor Maven / Gradle / Ivy

Go to download

A lightweight library to parse sas7bdat files. Supports 'CHAR' compression.

There is a newer version: 1.2.1
Show newest version
package com.ggasoftware.parso;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Implementation of the CHAR compression algorithm which corresponds to the literal "SASYZCRL". 
 * Refer the documentation for further details.
 * It follows the general contract provided by the interface Decompressor. 
 * 
 * @author dzhelezov
 *
 */
public final class CharDecompressor implements Decompressor {
	private static final Logger logger = LoggerFactory.getLogger(CharDecompressor.class);

	public static final CharDecompressor instance = new CharDecompressor();
	
	private CharDecompressor() {
		//prevent multiple instances
	}
	
	
	
	/**
     * The function to decompress data. Compressed data are an array of bytes with control bytes and data bytes.
     * The project documentation contains descriptions of the decompression algorithm.
     *
     * @param offset the offset of bytes array in {@link SasFileParser#cachedPage} that contains compressed data.
     * @param length the length of bytes array that contains compressed data.
     * @return an array of bytes with decompressed data.
     */
    public byte[] decompressRow(int offset, int length, int resultLength, byte[] page) {
        byte[] resultByteArray = new byte[resultLength];
        int currentResultArrayIndex = 0;
        for (int currentByteIndex = 0; currentByteIndex < length; currentByteIndex++) {
            byte controlByte = (byte) (page[offset+currentByteIndex] & 0xF0);
            byte endOfFirstByte = (byte) (page[offset+currentByteIndex] & 0x0F);
            int countOfBytesToCopy;
            switch (controlByte) {
                case (byte) 0x00:
                    if (currentByteIndex != length - 1) {
                        countOfBytesToCopy = (page[offset+currentByteIndex + 1] & 0xFF) + 64 +
                                                                                                   endOfFirstByte * 256;
                        System.arraycopy(page, offset + currentByteIndex + 2, resultByteArray,
                                         currentResultArrayIndex, countOfBytesToCopy);
                        currentByteIndex += countOfBytesToCopy + 1;
                        currentResultArrayIndex += countOfBytesToCopy;
                    }
                    break;
                case (byte) 0x40:
                    int copyCounter = endOfFirstByte * 16 + (page[offset+currentByteIndex + 1] & 0xFF);
                    for (int i = 0; i < copyCounter + 18; i++) {
                        resultByteArray[currentResultArrayIndex++] = page[offset+currentByteIndex + 2];
                    }
                    currentByteIndex += 2;
                    break;
                case (byte) 0x60:
                    for (int i = 0; i < endOfFirstByte * 256 + (page[offset+currentByteIndex + 1] & 0xFF) + 17;
                                                                                                                  i++) {
                        resultByteArray[currentResultArrayIndex++] = 0x20;
                    }
                    currentByteIndex++;
                    break;
                case (byte) 0x70:
                    for (int i = 0; i < (page[offset+currentByteIndex + 1] & 0xFF) + 17; i++) {
                        resultByteArray[currentResultArrayIndex++] = 0x00;
                    }
                    currentByteIndex++;
                    break;
                case (byte) 0x80:
                    countOfBytesToCopy = Math.min(endOfFirstByte + 1, length - (currentByteIndex + 1));
                    System.arraycopy(page, offset + currentByteIndex + 1, resultByteArray,
                                     currentResultArrayIndex, countOfBytesToCopy);
                    currentByteIndex += countOfBytesToCopy;
                    currentResultArrayIndex += countOfBytesToCopy;
                    break;
                case (byte) 0x90:
                    countOfBytesToCopy = Math.min(endOfFirstByte + 17, length - (currentByteIndex + 1));
                    System.arraycopy(page, offset + currentByteIndex + 1, resultByteArray,
                                     currentResultArrayIndex, countOfBytesToCopy);
                    currentByteIndex += countOfBytesToCopy;
                    currentResultArrayIndex += countOfBytesToCopy;
                    break;
                case (byte) 0xA0:
                    countOfBytesToCopy = Math.min(endOfFirstByte + 33, length - (currentByteIndex + 1));
                    System.arraycopy(page, offset + currentByteIndex + 1, resultByteArray,
                                     currentResultArrayIndex, countOfBytesToCopy);
                    currentByteIndex += countOfBytesToCopy;
                    currentResultArrayIndex += countOfBytesToCopy;
                    break;
                case (byte) 0xB0:
                    countOfBytesToCopy = Math.min(endOfFirstByte + 49, length - (currentByteIndex + 1));
                    System.arraycopy(page, offset + currentByteIndex + 1, resultByteArray,
                                     currentResultArrayIndex, countOfBytesToCopy);
                    currentByteIndex += countOfBytesToCopy;
                    currentResultArrayIndex += countOfBytesToCopy;
                    break;
                case (byte) 0xC0:
                    for (int i = 0; i < endOfFirstByte + 3; i++) {
                        resultByteArray[currentResultArrayIndex++] = page[offset+currentByteIndex + 1];
                    }
                    currentByteIndex++;
                    break;
                case (byte) 0xD0:
                    for (int i = 0; i < endOfFirstByte + 2; i++) {
                        resultByteArray[currentResultArrayIndex++] = 0x40;
                    }
                    break;
                case (byte) 0xE0:
                    for (int i = 0; i < endOfFirstByte + 2; i++) {
                        resultByteArray[currentResultArrayIndex++] = 0x20;
                    }
                    break;
                case (byte) 0xF0:
                    for (int i = 0; i < endOfFirstByte + 2; i++) {
                        resultByteArray[currentResultArrayIndex++] = 0x00;
                    }
                    break;
                default:
                    logger.error("Error control byte: {}", controlByte);
                    break;
            }
        }

        return resultByteArray;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy