blob: d2546657964a7111cb1f476ea353ffc47e9897d6 [file] [log] [blame]
/*
* Copyright (C) 2019 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 "PasteboardCustomData.h"
#include "SharedBuffer.h"
#include <wtf/URLParser.h>
#include <wtf/persistence/PersistentCoders.h>
#include <wtf/text/StringHash.h>
namespace WebCore {
static Variant<String, Ref<SharedBuffer>> copyPlatformData(const Variant<String, Ref<SharedBuffer>>& other)
{
if (WTF::holds_alternative<String>(other))
return { WTF::get<String>(other) };
if (WTF::holds_alternative<Ref<SharedBuffer>>(other))
return { WTF::get<Ref<SharedBuffer>>(other).copyRef() };
return { };
}
PasteboardCustomData::Entry::Entry(const Entry& entry)
: type(entry.type)
, customData(entry.customData)
, platformData(copyPlatformData(entry.platformData))
{
}
PasteboardCustomData::Entry::Entry(const String& dataType)
: type(dataType)
{
}
PasteboardCustomData::Entry::Entry() = default;
PasteboardCustomData::Entry::Entry(Entry&&) = default;
PasteboardCustomData::Entry& PasteboardCustomData::Entry::operator=(const Entry& entry)
{
type = entry.type;
customData = entry.customData;
platformData = copyPlatformData(entry.platformData);
return *this;
}
PasteboardCustomData::Entry& PasteboardCustomData::Entry::operator=(Entry&&) = default;
PasteboardCustomData::PasteboardCustomData() = default;
PasteboardCustomData::PasteboardCustomData(const PasteboardCustomData&) = default;
PasteboardCustomData::PasteboardCustomData(PasteboardCustomData&&) = default;
PasteboardCustomData::~PasteboardCustomData() = default;
PasteboardCustomData::PasteboardCustomData(String&& origin, Vector<Entry>&& data)
: m_origin(WTFMove(origin))
, m_data(WTFMove(data))
{
}
Ref<SharedBuffer> PasteboardCustomData::createSharedBuffer() const
{
constexpr unsigned currentCustomDataSerializationVersion = 1;
WTF::Persistence::Encoder encoder;
encoder << currentCustomDataSerializationVersion;
encoder << m_origin;
encoder << sameOriginCustomStringData();
encoder << orderedTypes();
return SharedBuffer::create(encoder.buffer(), encoder.bufferSize());
}
PasteboardCustomData PasteboardCustomData::fromSharedBuffer(const SharedBuffer& buffer)
{
constexpr unsigned maxSupportedDataSerializationVersionNumber = 1;
PasteboardCustomData result;
auto decoder = buffer.decoder();
unsigned version;
if (!decoder.decode(version) || version > maxSupportedDataSerializationVersionNumber)
return { };
if (!decoder.decode(result.m_origin))
return { };
HashMap<String, String> sameOriginCustomStringData;
if (!decoder.decode(sameOriginCustomStringData))
return { };
Vector<String> orderedTypes;
if (!decoder.decode(orderedTypes))
return { };
for (auto& type : orderedTypes)
result.writeStringInCustomData(type, sameOriginCustomStringData.get(type));
return result;
}
void PasteboardCustomData::writeString(const String& type, const String& value)
{
addOrMoveEntryToEnd(type).platformData = { value };
}
void PasteboardCustomData::writeData(const String& type, Ref<SharedBuffer>&& data)
{
addOrMoveEntryToEnd(type).platformData = { WTFMove(data) };
}
void PasteboardCustomData::writeStringInCustomData(const String& type, const String& value)
{
addOrMoveEntryToEnd(type).customData = value;
}
PasteboardCustomData::Entry& PasteboardCustomData::addOrMoveEntryToEnd(const String& type)
{
auto index = m_data.findMatching([&] (auto& entry) {
return entry.type == type;
});
auto entry = index == notFound ? Entry(type) : m_data[index];
if (index != notFound)
m_data.remove(index);
m_data.append(WTFMove(entry));
return m_data.last();
}
void PasteboardCustomData::clear()
{
m_data.clear();
}
void PasteboardCustomData::clear(const String& type)
{
m_data.removeFirstMatching([&] (auto& entry) {
return entry.type == type;
});
}
PasteboardCustomData& PasteboardCustomData::operator=(const PasteboardCustomData& other)
{
m_origin = other.origin();
m_data = other.m_data;
return *this;
}
Vector<String> PasteboardCustomData::orderedTypes() const
{
return m_data.map([&] (auto& entry) {
return entry.type;
});
}
bool PasteboardCustomData::hasData() const
{
return !m_data.isEmpty();
}
bool PasteboardCustomData::hasSameOriginCustomData() const
{
return notFound != m_data.findMatching([&] (auto& entry) {
return !entry.customData.isNull();
});
}
HashMap<String, String> PasteboardCustomData::sameOriginCustomStringData() const
{
HashMap<String, String> customData;
for (auto& entry : m_data)
customData.set(entry.type, entry.customData);
return customData;
}
RefPtr<SharedBuffer> PasteboardCustomData::readBuffer(const String& type) const
{
for (auto& entry : m_data) {
if (entry.type != type)
continue;
if (WTF::holds_alternative<Ref<SharedBuffer>>(entry.platformData))
return makeRefPtr(WTF::get<Ref<SharedBuffer>>(entry.platformData).get());
return nullptr;
}
return nullptr;
}
String PasteboardCustomData::readString(const String& type) const
{
for (auto& entry : m_data) {
if (entry.type != type)
continue;
if (WTF::holds_alternative<String>(entry.platformData))
return WTF::get<String>(entry.platformData);
return { };
}
return { };
}
String PasteboardCustomData::readStringInCustomData(const String& type) const
{
for (auto& entry : m_data) {
if (entry.type == type)
return entry.customData;
}
return { };
}
void PasteboardCustomData::forEachType(Function<void(const String&)>&& function) const
{
for (auto& entry : m_data)
function(entry.type);
}
void PasteboardCustomData::forEachPlatformString(Function<void(const String& type, const String& data)>&& function) const
{
for (auto& entry : m_data) {
if (!WTF::holds_alternative<String>(entry.platformData))
continue;
auto string = WTF::get<String>(entry.platformData);
if (!string.isNull())
function(entry.type, string);
}
}
void PasteboardCustomData::forEachCustomString(Function<void(const String& type, const String& data)>&& function) const
{
for (auto& entry : m_data) {
if (!entry.customData.isNull())
function(entry.type, entry.customData);
}
}
void PasteboardCustomData::forEachPlatformStringOrBuffer(Function<void(const String& type, const Variant<String, Ref<SharedBuffer>>& data)>&& function) const
{
for (auto& entry : m_data) {
auto& data = entry.platformData;
if ((WTF::holds_alternative<String>(data) && !WTF::get<String>(data).isNull()) || WTF::holds_alternative<Ref<SharedBuffer>>(data))
function(entry.type, data);
}
}
} // namespace WebCore