/*
 *      algo0x11.cpp            (C) 2006-2007, Aurélien Croc (AP²C)
 *
 *   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; version 2 of the License.
 *
 *   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.
 *
 *   $Id: algo0x11.cpp 302 2012-02-29 14:18:29Z tillkamppeter $
 */
#include "algo0x11.h"
#include <QtCore/QByteArray>
#include <QtCore/QTextStream>
#include "page.h"
#include "i18n.h"


bool decompress0x11(const QByteArray& input, QByteArray& output, 
    quint16 width, quint16 height, Page* page, QTextStream& err)
{
    quint32 lastOccur, bandSize, idx=4, w=0;
    short occurTable[0x40];
    QByteArray data;

    // Check the size
    if (input.size() < 0x40*2 + 4) {
        err << _("Algo0x11: bad band size") << endl;
        return false;
    }

    // Prepare the band buffer
    bandSize = (width * height + 7) >> 3;
    data.fill(0xff, bandSize);

    // Extract the header data and the occurrence table
    lastOccur = page->read32(input, 0);
    for (unsigned int i=0; i < 0x40; i++)
        occurTable[i] = ~page->read16(input, idx + i*2);
    idx += 0x40 * 2;

    // Extract the first uncompressed data
    if (input.size() <= idx + lastOccur) {
        err << _("Algo0x11: invalid band size") << endl;
        return false;
    }
    for (w=0; w < lastOccur; w++)
        data[w] = page->read8(input, idx + w);
    idx += lastOccur;

    // Decompress the other data
    while (input.size() > idx) {
        quint8 counter = page->read8(input, idx++);

        // Compressed
        if (counter & 0x80) {
            quint8 number = page->read8(input, idx++);
            quint32 toRead, ref;

            toRead = ((number & 0xC0) << 1) + (counter & 0x7F) + 3;
            number = number & ~0xC0;
            ref = w + 1;
            for (unsigned int i=0; i < toRead; i++, w++)
                data[w] = data.at(ref + occurTable[number] + i);

        // Uncompressed
        } else {
            for (unsigned int i = 0; i <= counter; i++, w++)
                data[w] = page->read8(input, idx++);
        }
    }

    // Rotate the data
    output.fill(0, bandSize);
    for (unsigned int i = 0; i < bandSize; i++) {
        uint32_t x, y;

        x = i / height;
        y = i % height;
        output[x + y * (width / 8)] = ~data[i];
    }

    return true;
}

/* vim: set expandtab tabstop=4 shiftwidth=4 smarttab tw=80 cin enc=utf8 : */

