/* * Copyright (C) 2006-2021 Apple Inc. All rights reserved. * Copyright (C) Research In Motion Limited 2009-2010. 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. ``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 * 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. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #if USE(CF) #include #endif #if USE(GLIB) #include typedef struct _GBytes GBytes; #endif #if USE(GSTREAMER) #include "GStreamerCommon.h" #endif #if USE(FOUNDATION) OBJC_CLASS NSArray; OBJC_CLASS NSData; typedef struct OpaqueCMBlockBuffer *CMBlockBufferRef; #endif namespace WTF { namespace Persistence { class Decoder; } } namespace WebCore { class SharedBuffer; class SharedBufferDataView; // Data wrapped by a DataSegment should be immutable because it can be referenced by other objects. // To modify or combine the data, allocate a new DataSegment. class DataSegment : public ThreadSafeRefCounted { public: WEBCORE_EXPORT const uint8_t *data() const; WEBCORE_EXPORT size_t size() const; WEBCORE_EXPORT static Ref create(Vector &&); #if USE(CF) WEBCORE_EXPORT static Ref create(RetainPtr &&); #endif #if USE(GLIB) WEBCORE_EXPORT static Ref create(GRefPtr &&); #endif #if USE(GSTREAMER) WEBCORE_EXPORT static Ref create(RefPtr &&); #endif WEBCORE_EXPORT static Ref create(FileSystem::MappedFileData &&); struct Provider { Function data; Function size; }; WEBCORE_EXPORT static Ref create(Provider &&); #if USE(FOUNDATION) WEBCORE_EXPORT RetainPtr createNSData() const; #endif WEBCORE_EXPORT bool containsMappedFileData() const; private: void iterate(const Function &)> &apply) const; #if USE(FOUNDATION) void iterate(CFDataRef, const Function &)> &apply) const; #endif explicit DataSegment(Vector &&data) : m_immutableData(WTFMove(data)) { } #if USE(CF) explicit DataSegment(RetainPtr &&data) : m_immutableData(WTFMove(data)) { } #endif #if USE(GLIB) explicit DataSegment(GRefPtr &&data) : m_immutableData(WTFMove(data)) { } #endif #if USE(GSTREAMER) explicit DataSegment(RefPtr &&data) : m_immutableData(WTFMove(data)) { } #endif explicit DataSegment(FileSystem::MappedFileData &&data) : m_immutableData(WTFMove(data)) { } explicit DataSegment(Provider &&provider) : m_immutableData(WTFMove(provider)) { } std::variant, #if USE(CF) RetainPtr, #endif #if USE(GLIB) GRefPtr, #endif #if USE(GSTREAMER) RefPtr, #endif FileSystem::MappedFileData, Provider> m_immutableData; friend class FragmentedSharedBuffer; friend class SharedBuffer; // For createCFData }; class FragmentedSharedBuffer : public ThreadSafeRefCounted { public: WEBCORE_EXPORT static Ref create(); WEBCORE_EXPORT static Ref create(const uint8_t *, size_t); static Ref create(const char *data, size_t size) { return create(reinterpret_cast(data), size); } WEBCORE_EXPORT static Ref create(FileSystem::MappedFileData &&); WEBCORE_EXPORT static Ref create(Ref &&); WEBCORE_EXPORT static Ref create(Vector &&); WEBCORE_EXPORT static Ref create(DataSegment::Provider &&); #if USE(FOUNDATION) WEBCORE_EXPORT RetainPtr createNSDataArray() const; WEBCORE_EXPORT static Ref create(NSData *); WEBCORE_EXPORT RetainPtr createCMBlockBuffer() const; #endif #if USE(CF) WEBCORE_EXPORT static Ref create(CFDataRef); #endif #if USE(GLIB) WEBCORE_EXPORT static Ref create(GBytes *); #endif #if USE(GSTREAMER) WEBCORE_EXPORT static Ref create(GstMappedOwnedBuffer &); #endif WEBCORE_EXPORT Vector copyData() const; WEBCORE_EXPORT Vector read(size_t offset, size_t length) const; // Similar to copyData() but avoids copying and will take the data instead when it is safe (The FragmentedSharedBuffer is not shared). Vector extractData(); WEBCORE_EXPORT RefPtr tryCreateArrayBuffer() const; size_t size() const { return m_size; } bool isEmpty() const { return !size(); } bool isContiguous() const { return m_contiguous; } WEBCORE_EXPORT Ref copy() const; WEBCORE_EXPORT void copyTo(void *destination, size_t length) const; WEBCORE_EXPORT void copyTo(void *destination, size_t offset, size_t length) const; WEBCORE_EXPORT void forEachSegment(const Function &)> &) const; WEBCORE_EXPORT bool startsWith(const std::span &prefix) const; WEBCORE_EXPORT void forEachSegmentAsSharedBuffer(const Function &&)> &) const; using DataSegment = WebCore::DataSegment; // To keep backward compatibility when using FragmentedSharedBuffer::DataSegment struct DataSegmentVectorEntry { size_t beginPosition; const Ref segment; }; using DataSegmentVector = Vector; DataSegmentVector::const_iterator begin() const { return m_segments.begin(); } DataSegmentVector::const_iterator end() const { return m_segments.end(); } bool hasOneSegment() const { return m_segments.size() == 1; } // begin and end take O(1) time, this takes O(log(N)) time. WEBCORE_EXPORT SharedBufferDataView getSomeData(size_t position) const; WEBCORE_EXPORT Ref getContiguousData(size_t position, size_t length) const; WEBCORE_EXPORT String toHexString() const; void hintMemoryNotNeededSoon() const; WEBCORE_EXPORT bool operator==(const FragmentedSharedBuffer &) const; bool operator!=(const FragmentedSharedBuffer &other) const { return !operator==(other); } WEBCORE_EXPORT Ref makeContiguous() const; protected: friend class SharedBuffer; DataSegmentVector m_segments; bool m_contiguous { false }; WEBCORE_EXPORT FragmentedSharedBuffer(); explicit FragmentedSharedBuffer(const uint8_t *data, size_t size) { append(data, size); } explicit FragmentedSharedBuffer(const char *data, size_t size) { append(data, size); } explicit FragmentedSharedBuffer(Vector &&data) { append(WTFMove(data)); } WEBCORE_EXPORT explicit FragmentedSharedBuffer(FileSystem::MappedFileData &&); WEBCORE_EXPORT explicit FragmentedSharedBuffer(DataSegment::Provider &&); WEBCORE_EXPORT explicit FragmentedSharedBuffer(Ref &&); #if USE(CF) WEBCORE_EXPORT explicit FragmentedSharedBuffer(CFDataRef); #endif #if USE(GLIB) WEBCORE_EXPORT explicit FragmentedSharedBuffer(GBytes *); #endif #if USE(GSTREAMER) WEBCORE_EXPORT explicit FragmentedSharedBuffer(GstMappedOwnedBuffer &); #endif size_t m_size { 0 }; private: friend class SharedBufferBuilder; WEBCORE_EXPORT void append(const FragmentedSharedBuffer &); WEBCORE_EXPORT void append(const uint8_t *, size_t); void append(std::span value) { append(value.data(), value.size()); } void append(const char *data, size_t length) { append(reinterpret_cast(data), length); } WEBCORE_EXPORT void append(Vector &&); #if USE(FOUNDATION) WEBCORE_EXPORT void append(NSData *); #endif #if USE(CF) WEBCORE_EXPORT void append(CFDataRef); #endif WEBCORE_EXPORT void clear(); // Combines all the segments into a Vector and returns that vector after clearing the FragmentedSharedBuffer. WEBCORE_EXPORT Vector takeData(); const DataSegmentVectorEntry *getSegmentForPosition(size_t position) const; #if ASSERT_ENABLED bool internallyConsistent() const; #endif }; // A SharedBuffer is a FragmentedSharedBuffer that allows to directly access its content via the data() and related methods. class SharedBuffer : public FragmentedSharedBuffer { public: template static Ref create(Args &&...args) { if constexpr (!sizeof...(Args)) return adoptRef(*new SharedBuffer()); else if constexpr (sizeof...(Args) == 1 && (std::is_same_v> && ...)) return adoptRef(*new SharedBuffer(std::forward(args)...)); else if constexpr (sizeof...(Args) == 1 && (std::is_same_v, DataSegment> && ...)) return adoptRef(*new SharedBuffer(std::forward(args)...)); else { auto buffer = FragmentedSharedBuffer::create(std::forward(args)...); return adoptRef(*new SharedBuffer(WTFMove(buffer))); } } WEBCORE_EXPORT const uint8_t *data() const; const char *dataAsCharPtr() const { return reinterpret_cast(data()); } std::span dataAsSpanForContiguousData() const { return std::span(data(), isContiguous() ? size() : 0); } WTF::Persistence::Decoder decoder() const; enum class MayUseFileMapping : bool { No, Yes }; WEBCORE_EXPORT static RefPtr createWithContentsOfFile(const String &filePath, FileSystem::MappedFileMode = FileSystem::MappedFileMode::Shared, MayUseFileMapping = MayUseFileMapping::Yes); #if USE(FOUNDATION) WEBCORE_EXPORT RetainPtr createNSData() const; #endif #if USE(CF) WEBCORE_EXPORT RetainPtr createCFData() const; #endif #if USE(GLIB) WEBCORE_EXPORT GRefPtr createGBytes() const; #endif private: WEBCORE_EXPORT SharedBuffer(); SharedBuffer(const DataSegment &segment) : SharedBuffer(Ref { segment }) { } WEBCORE_EXPORT explicit SharedBuffer(FileSystem::MappedFileData &&); WEBCORE_EXPORT explicit SharedBuffer(Ref &&); WEBCORE_EXPORT explicit SharedBuffer(Ref &&); WEBCORE_EXPORT static RefPtr createFromReadingFile(const String &filePath); }; class SharedBufferBuilder { WTF_MAKE_FAST_ALLOCATED; public: SharedBufferBuilder() = default; SharedBufferBuilder(SharedBufferBuilder &&) = default; WEBCORE_EXPORT explicit SharedBufferBuilder(RefPtr &&); explicit SharedBufferBuilder(Ref &&buffer) { initialize(WTFMove(buffer)); } explicit SharedBufferBuilder(RefPtr &&buffer) : SharedBufferBuilder(RefPtr { WTFMove(buffer) }) { } explicit SharedBufferBuilder(Ref &&buffer) { initialize(WTFMove(buffer)); } template SharedBufferBuilder(std::in_place_t, Args &&...args) : m_buffer(FragmentedSharedBuffer::create(std::forward(args)...)) { } SharedBufferBuilder &operator=(SharedBufferBuilder &&) = default; WEBCORE_EXPORT SharedBufferBuilder &operator=(RefPtr &&); template void append(Args &&...args) { ensureBuffer(); m_buffer->append(std::forward(args)...); } explicit operator bool() const { return !isNull(); } bool isNull() const { return !m_buffer; } bool isEmpty() const { return m_buffer ? m_buffer->isEmpty() : true; } size_t size() const { return m_buffer ? m_buffer->size() : 0; } void reset() { m_buffer = nullptr; } void empty() { m_buffer = FragmentedSharedBuffer::create(); } RefPtr get() const { return m_buffer; } Ref copy() const { return m_buffer ? m_buffer->copy() : FragmentedSharedBuffer::create(); } WEBCORE_EXPORT RefPtr tryCreateArrayBuffer() const; WEBCORE_EXPORT Ref take(); WEBCORE_EXPORT Ref takeAsContiguous(); WEBCORE_EXPORT RefPtr takeAsArrayBuffer(); private: friend class ScriptBuffer; friend class FetchBodyConsumer; // Copy constructor should make a copy of the underlying SharedBuffer // This is prevented by ScriptBuffer and FetchBodyConsumer classes (bug 234215) // For now let the default constructor/operator take a reference to the // SharedBuffer. SharedBufferBuilder(const SharedBufferBuilder &) = default; SharedBufferBuilder &operator=(const SharedBufferBuilder &) = default; WEBCORE_EXPORT void initialize(Ref &&); WEBCORE_EXPORT void ensureBuffer(); RefPtr m_buffer; }; inline Vector FragmentedSharedBuffer::extractData() { if (hasOneRef()) return takeData(); return copyData(); } class SharedBufferDataView { public: WEBCORE_EXPORT SharedBufferDataView(Ref &&, size_t positionWithinSegment, std::optional newSize = std::nullopt); WEBCORE_EXPORT SharedBufferDataView(const SharedBufferDataView &, size_t newSize); size_t size() const { return m_size; } const uint8_t *data() const { return m_segment->data() + m_positionWithinSegment; } const char *dataAsCharPtr() const { return reinterpret_cast(data()); } WEBCORE_EXPORT Ref createSharedBuffer() const; #if USE(FOUNDATION) WEBCORE_EXPORT RetainPtr createNSData() const; #endif private: const Ref m_segment; const size_t m_positionWithinSegment; const size_t m_size; }; RefPtr utf8Buffer(const String &); } // namespace WebCore SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::SharedBuffer) static bool isType(const WebCore::FragmentedSharedBuffer &buffer) { return buffer.isContiguous(); } SPECIALIZE_TYPE_TRAITS_END()