/*
 *  Copyright (c) 2009 Boudewijn Rempt <boud@valdyas.org>
 *
 *  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.
 */
#include "psd_utils.h"

#include <QIODevice>
#include <QString>

#include <netinet/in.h> // htonl

#include <kis_debug.h>

bool psdwrite(QIODevice* io, quint8 v)
{
    int written = io->write((char*)&v, 1);
    return written == 1;
}

bool psdwrite(QIODevice* io, quint16 v)
{
    quint16 val = htons(v);
    int written = io->write((char*)&val, 2);
    return written == 2;
}

bool psdwrite(QIODevice* io, qint16 v)
{
    qint16 val = htons(v);
    int written = io->write((char*)&val, 2);
    return written == 2;
}

bool psdwrite(QIODevice* io, quint32 v)
{
    quint32 val = htonl(v);
    int written = io->write((char*)&val, 4);
    return written == 4;
}

bool psdpad(QIODevice* io, quint32 padding)
{
    char* pad = new char[padding];
    memset(pad, 0, padding);
    quint32 written = io->write(pad, padding);
    delete [] pad;
    return written == padding;
}

bool psdwrite(QIODevice* io, const QString &s)
{
    int l = s.length();
    QByteArray b = s.toLatin1();
    char* str = b.data();
    int written = io->write(str, l);
    return written == l;
}

bool psdwrite_pascalstring(QIODevice* io, const QString &s)
{
    Q_ASSERT(s.length() < 256);
    Q_ASSERT(s.length() >= 0);
    if (s.length() < 0 || s.length() > 255) return false;

    if (s.isNull()) {
        psdwrite(io, (quint8)0);
        psdwrite(io, (quint8)0);
        return true;
    }
    quint8 length = s.length();
    psdwrite(io, length);

    QByteArray b = s.toLatin1();
    char* str = b.data();
    int written = io->write(str, length);
    if (written != length) return false;

    if ((length & 0x01) != 0) {
        return psdwrite(io, (quint8)0);
    }

    return true;
}

bool psdwrite_pascalstring(QIODevice* io, const QString &s, int padding)
{
    Q_ASSERT(s.length() < 256);
    Q_ASSERT(s.length() >= 0);
    if (s.length() < 0 || s.length() > 255) return false;

    if (s.isNull()) {
        psdwrite(io, (quint8)0);
        psdwrite(io, (quint8)0);
        return true;
    }
    quint8 length = s.length();
    psdwrite(io, length);

    QByteArray b = s.toLatin1();
    char* str = b.data();
    int written = io->write(str, length);
    if (written != length) return false;

    // If the total length (length byte + content) is not a multiple of padding, add zeroes to pad
    length++;
    if ((length % padding) != 0) {
        for (int i = 0; i < (padding - (length %padding)); i++) {
            psdwrite(io, (quint8)0);
        }
    }

    return true;
}


bool psdread(QIODevice *io, quint8 *v)
{
    quint64 read = io->read((char*)v, 1);
    if (read != 1) return false;
    return true;
}

bool psdread(QIODevice* io, quint16* v)
{
    quint16 val;
    quint64 read = io->read((char*)&val, 2);
    if (read != 2) return false;
    *v = ntohs(val);
    return true;
}

bool psdread(QIODevice* io, qint16* v)
{
    qint16 val;
    quint64 read = io->read((char*)&val, 2);
    if (read != 2) return false;
    *v = ntohs(val);
    return true;
}


bool psdread(QIODevice* io, quint32* v)
{
    quint32 val;
    quint64 read = io->read((char*)&val, 4);
    if (read != 4) return false;
    *v = ntohl(val);
    return true;
}


bool psdread(QIODevice* io, qint32* v)
{
    qint32 val;
    quint64 read = io->read((char*)&val, 4);
    if (read != 4) return false;
    *v = ntohl(val);
    return true;
}

bool psdread(QIODevice* io, quint64* v)
{
    quint64 val;
    quint64 read = io->read((char*)&val, 8);
    if (read != 8) return false;
    *v = ntohl(val);
    return true;
}

bool psdread_pascalstring(QIODevice* io, QString& s, int padding)
{
    quint8 length;
    if (!psdread(io, &length)) {
        //dbgFile << 1;
        return false;
    }

    //dbgFile << "psdread_pascalstring length:" << length;

    if (length == 0) {
        // read the padding
        for (int i = 0; i < padding -1; ++i) {
            io->seek(io->pos() + 1);
        }
        //dbgFile << 3 << (length == 0);
        return (length == 0);
    }

    QByteArray chars = io->read(length);
    //dbgFile << "psdread_pascalstring bytes:" << QString::fromLatin1(chars, length) << chars.length();
    if (chars.length() != length) {
        //dbgFile << 4;
        return false;
    }

    // read padding byte
    quint32 paddedLength = length + 1;
    if (padding > 0) {
        while (paddedLength % padding != 0) {
            if (!io->seek(io->pos() + 1)) {
                //dbgFile << 5;
                return false;
            }
            paddedLength++;
        }
    }

    s.append(QString::fromLatin1(chars));
    ////dbgFile << "psdread_pascalstring bytes:" << s;


    return true;
}

