/*
 * Copyright (C) 2013 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "BlobRegistrationData.h"

#if ENABLE(BLOB) && ENABLE(NETWORK_PROCESS)

#include "ArgumentCoders.h"
#include "DataReference.h"
#include "WebCoreArgumentCoders.h"
#include <WebCore/BlobData.h>

using namespace WebCore;

namespace WebKit {

BlobRegistrationData::BlobRegistrationData()
{
}

BlobRegistrationData::BlobRegistrationData(PassOwnPtr<BlobData> data)
    : m_data(data)
{
    const BlobDataItemList& items = m_data->items();
    size_t fileCount = 0;
    for (size_t i = 0, count = items.size(); i < count; ++i) {
        // File path can be empty when submitting a form file input without a file, see bug 111778.
        if (items[i].type == BlobDataItem::File && !items[i].path.isEmpty())
            ++fileCount;
    }

    m_sandboxExtensions.allocate(fileCount);
    size_t extensionIndex = 0;
    for (size_t i = 0, count = items.size(); i < count; ++i) {
        const BlobDataItem& item = items[i];
        if (item.type == BlobDataItem::File && !items[i].path.isEmpty())
            SandboxExtension::createHandle(item.path, SandboxExtension::ReadOnly, m_sandboxExtensions[extensionIndex++]);
    }
}

BlobRegistrationData::~BlobRegistrationData()
{
}

PassOwnPtr<BlobData> BlobRegistrationData::releaseData() const
{
    return m_data.release();
}

void BlobRegistrationData::encode(CoreIPC::ArgumentEncoder& encoder) const
{
    encoder << m_data->contentType();
    encoder << m_data->contentDisposition();

    const BlobDataItemList& items = m_data->items();
    encoder << static_cast<uint64_t>(items.size());
    for (size_t i = 0, count = items.size(); i < count; ++i) {
        const BlobDataItem& item = items[i];
        encoder << static_cast<uint32_t>(item.type);
        switch (item.type) {
        case BlobDataItem::Data:
            // There is no way to create a partial data item.
            ASSERT(!item.offset);
            ASSERT(item.length == BlobDataItem::toEndOfFile);
            encoder << CoreIPC::DataReference(reinterpret_cast<const uint8_t*>(item.data->data()), item.data->length());
            break;
        case BlobDataItem::File:
            encoder << item.offset;
            encoder << item.length;
            encoder << item.expectedModificationTime;
            encoder << item.path;
            break;
        case BlobDataItem::Blob:
            encoder << item.offset;
            encoder << item.length;
            encoder << item.url;
            break;
        }
    }

    encoder << m_sandboxExtensions;
}

bool BlobRegistrationData::decode(CoreIPC::ArgumentDecoder& decoder, BlobRegistrationData& result)
{
    ASSERT(!result.m_data);
    result.m_data = BlobData::create();

    String contentType;
    if (!decoder.decode(contentType))
        return false;
    result.m_data->setContentType(contentType);

    String contentDisposition;
    if (!decoder.decode(contentDisposition))
        return false;
    result.m_data->setContentDisposition(contentDisposition);

    uint64_t itemCount;
    if (!decoder.decode(itemCount))
        return false;

    for (uint64_t i = 0; i < itemCount; ++i) {
        uint32_t type;
        if (!decoder.decode(type))
            return false;
        switch (type) {
        case BlobDataItem::Data: {
            CoreIPC::DataReference data;
            if (!decoder.decode(data))
                return false;
            RefPtr<RawData> rawData = RawData::create();
            rawData->mutableData()->append(data.data(), data.size());
            result.m_data->appendData(rawData.release(), 0, BlobDataItem::toEndOfFile);
            break;
        }
        case BlobDataItem::File: {
            long long offset;
            if (!decoder.decode(offset))
                return false;
            long long length;
            if (!decoder.decode(length))
                return false;
            double expectedModificationTime;
            if (!decoder.decode(expectedModificationTime))
                return false;
            String path;
            if (!decoder.decode(path))
                return false;
            result.m_data->appendFile(path, offset, length, expectedModificationTime);
            break;
        }
        case BlobDataItem::Blob: {
            long long offset;
            if (!decoder.decode(offset))
                return false;
            long long length;
            if (!decoder.decode(length))
                return false;
            String url;
            if (!decoder.decode(url))
                return false;
            result.m_data->appendBlob(KURL(KURL(), url), offset, length);
            break;
        }
        default:
            return false;
        }
    }

    if (!decoder.decode(result.m_sandboxExtensions))
        return false;

    return true;
}

}

#endif // ENABLE(BLOB) && ENABLE(NETWORK_PROCESS)
