view org.eclipse.swt.gtk.linux.x86/src/org/eclipse/swt/internal/image/PngLzBlockReader.d @ 120:536e43f63c81

Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661 ===D2=== * added [Try]Immutable/Const/Shared templates to work with differenses in D1/D2 instead of version statements used these templates to work with strict type storage rules of dmd-2.053 * com.ibm.icu now also compilable with D2, but not tested yet * small fixes Snippet288 - shared data is in TLS ===Phobos=== * fixed critical bugs in Phobos implemention completely incorrect segfault prone fromStringz (Linux's port ruthless killer) terrible, incorrect StringBuffer realization (StyledText killer) * fixed small bugs as well Snippet72 - misprint in the snippet * implemented missed functionality for Phobos ByteArrayOutputStream implemented (image loading available) formatting correctly works for all DWT's cases As a result, folowing snippets now works with Phobos (Snippet### - what is fixed): Snippet24, 42, 111, 115, 130, 235, 276 - bad string formatting Snippet48, 282 - crash on image loading Snippet163, 189, 211, 213, 217, 218, 222 - crash on copy/cut in StyledText Snippet244 - hang-up ===Tango=== * few changes for the latest Tango trunc-r5661 * few small performance improvments ===General=== * implMissing-s for only one version changed to implMissingInTango/InPhobos * incorrect calls to Format in toString-s fixed * fixed loading \uXXXX characters in ResourceBundle * added good UTF-8 support for StyledText, TextLayout (Win32) and friends UTF functions revised and tested. It is now in java.nonstandard.*Utf modules StyledText and TextLayout (Win32) modules revised for UTF-8 support * removed small diferences in most identical files in *.swt.* folders *.swt.internal.image, *.swt.events and *.swt.custom are identical in Win32/Linux32 now 179 of 576 (~31%) files in *.swt.* folders are fully identical * Win32: snippets now have right subsystem, pretty icons and native system style controls * small fixes in snippets Snippet44 - it's not Snippet44 Snippet212 - functions work with different images and offsets arrays Win32: Snippet282 - crash on close if the button has an image Snippet293 - setGrayed is commented and others Win32: As a result, folowing snippets now works Snippet68 - color doesn't change Snippet163, 189, 211, 213, 217, 218, 222 - UTF-8 issues (see above) Snippet193 - no tabel headers
author Denis Shelomovskij <verylonglogin.reg@gmail.com>
date Sat, 09 Jul 2011 15:50:20 +0300
parents f713da8bc051
children
line wrap: on
line source

/*******************************************************************************
 * Copyright (c) 2000, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 * Port to the D programming language:
 *     Frank Benoit <benoit@tionex.de>
 *******************************************************************************/
module org.eclipse.swt.internal.image.PngLzBlockReader;

import org.eclipse.swt.internal.image.PngDecodingDataStream;
import org.eclipse.swt.internal.image.PngHuffmanTables;

public class PngLzBlockReader {
    bool isLastBlock;
    byte compressionType;
    int uncompressedBytesRemaining;
    PngDecodingDataStream stream;
    PngHuffmanTables huffmanTables;

    byte[] window;
    int windowIndex;
    int copyIndex;
    int copyBytesRemaining;

    static const int UNCOMPRESSED = 0;
    static const int COMPRESSED_FIXED = 1;
    static const int COMPRESSED_DYNAMIC = 2;

    static const int END_OF_COMPRESSED_BLOCK = 256;
    static const int FIRST_LENGTH_CODE = 257;
    static const int LAST_LENGTH_CODE = 285;
    static const int FIRST_DISTANCE_CODE = 1;
    static const int LAST_DISTANCE_CODE = 29;
    static const int FIRST_CODE_LENGTH_CODE = 4;
    static const int LAST_CODE_LENGTH_CODE = 19;

    static const int[] lengthBases = [
        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27,
        31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
    ];
    static const int[] extraLengthBits = [
        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
    ];
    static const int[] distanceBases = [
        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129,
        193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097,
        6145, 8193, 12289, 16385, 24577,
    ];
    static const int[] extraDistanceBits = [
        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7,  7,
        8,  8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
    ];


this(PngDecodingDataStream stream) {
    this.stream = stream;
    isLastBlock = false;
}

void setWindowSize(int windowSize) {
    window = new byte[windowSize];
}

void readNextBlockHeader()  {
    isLastBlock = stream.getNextIdatBit() !is 0;
    compressionType = cast(byte)(stream.getNextIdatBits(2) & 0xFF);
    if (compressionType > 2) stream.error();

    if (compressionType is UNCOMPRESSED) {
        byte b1 = stream.getNextIdatByte();
        byte b2 = stream.getNextIdatByte();
        byte b3 = stream.getNextIdatByte();
        byte b4 = stream.getNextIdatByte();
        if (b1 !is ~b3 || b2 !is ~b4) stream.error();
        uncompressedBytesRemaining = (b1 & 0xFF) | ((b2 & 0xFF) << 8);
    } else if (compressionType is COMPRESSED_DYNAMIC) {
        huffmanTables = PngHuffmanTables.getDynamicTables(stream);
    } else {
        huffmanTables = PngHuffmanTables.getFixedTables();
    }
}

byte getNextByte()  {
    if (compressionType is UNCOMPRESSED) {
        if (uncompressedBytesRemaining is 0) {
            readNextBlockHeader();
            return getNextByte();
        }
        uncompressedBytesRemaining--;
        return stream.getNextIdatByte();
    } else {
        byte value = getNextCompressedByte();
        if (value is END_OF_COMPRESSED_BLOCK) {
            if (isLastBlock) stream.error();
            readNextBlockHeader();
            return getNextByte();
        } else {
            return value;
        }
    }
}

private void assertBlockAtEnd()  {
    if (compressionType is UNCOMPRESSED) {
        if (uncompressedBytesRemaining > 0) stream.error();
    } else if (copyBytesRemaining > 0 ||
        (huffmanTables.getNextLiteralValue(stream) !is END_OF_COMPRESSED_BLOCK))
    {
        stream.error();
    }
}
void assertCompressedDataAtEnd()  {
    assertBlockAtEnd();
    while (!isLastBlock) {
        readNextBlockHeader();
        assertBlockAtEnd();
    }
}

private byte getNextCompressedByte()  {
    if (copyBytesRemaining > 0) {
        byte value = window[copyIndex];
        window[windowIndex] = value;
        copyBytesRemaining--;

        copyIndex++;
        windowIndex++;
        if (copyIndex is window.length) copyIndex = 0;
        if (windowIndex is window.length) windowIndex = 0;

        return value;
    }

    int value = huffmanTables.getNextLiteralValue(stream);
    if (value < END_OF_COMPRESSED_BLOCK) {
        window[windowIndex] = cast(byte) (value & 0xFF);
        windowIndex++;
        if (windowIndex >= window.length) windowIndex = 0;
        return cast(byte) (value & 0xFF);
    } else if (value is END_OF_COMPRESSED_BLOCK) {
        readNextBlockHeader();
        return getNextByte();
    } else if (value <= LAST_LENGTH_CODE) {
        int extraBits = extraLengthBits[value - FIRST_LENGTH_CODE];
        int length = lengthBases[value - FIRST_LENGTH_CODE];
        if (extraBits > 0) {
            length += stream.getNextIdatBits(extraBits);
        }

        value = huffmanTables.getNextDistanceValue(stream);
        if (value > LAST_DISTANCE_CODE) stream.error();
        extraBits = extraDistanceBits[value];
        int distance = distanceBases[value];
        if (extraBits > 0) {
            distance += stream.getNextIdatBits(extraBits);
        }

        copyIndex = windowIndex - distance;
        if (copyIndex < 0) copyIndex += window.length;

        copyBytesRemaining = length;
        return getNextCompressedByte();
    } else {
        stream.error();
        return 0;
    }
}

}