1/*
2 * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
3 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <JavaScriptCore/ArrayBuffer.h>
30#include <wtf/FileSystem.h>
31#include <wtf/Forward.h>
32#include <wtf/RefCounted.h>
33#include <wtf/ThreadSafeRefCounted.h>
34#include <wtf/Variant.h>
35#include <wtf/Vector.h>
36#include <wtf/text/WTFString.h>
37
38#if USE(CF)
39#include <wtf/RetainPtr.h>
40#endif
41
42#if USE(SOUP)
43#include "GUniquePtrSoup.h"
44#endif
45
46#if USE(GLIB)
47#include <wtf/glib/GRefPtr.h>
48typedef struct _GBytes GBytes;
49#endif
50
51#if USE(GSTREAMER)
52#include "GStreamerCommon.h"
53#endif
54
55#if USE(FOUNDATION)
56OBJC_CLASS NSArray;
57OBJC_CLASS NSData;
58#endif
59
60namespace WebCore {
61
62class SharedBufferDataView;
63
64class WEBCORE_EXPORT SharedBuffer : public RefCounted<SharedBuffer> {
65public:
66 static Ref<SharedBuffer> create() { return adoptRef(*new SharedBuffer); }
67 static Ref<SharedBuffer> create(const char* data, size_t size) { return adoptRef(*new SharedBuffer(data, size)); }
68 static Ref<SharedBuffer> create(const unsigned char* data, size_t size) { return adoptRef(*new SharedBuffer(data, size)); }
69 static RefPtr<SharedBuffer> createWithContentsOfFile(const String& filePath);
70
71 static Ref<SharedBuffer> create(Vector<char>&&);
72 static Ref<SharedBuffer> create(Vector<uint8_t>&&);
73
74#if USE(FOUNDATION)
75 RetainPtr<NSData> createNSData() const;
76 RetainPtr<NSArray> createNSDataArray() const;
77 static Ref<SharedBuffer> create(NSData *);
78 void append(NSData *);
79#endif
80#if USE(CF)
81 RetainPtr<CFDataRef> createCFData() const;
82 static Ref<SharedBuffer> create(CFDataRef);
83 void append(CFDataRef);
84#endif
85
86#if USE(SOUP)
87 GUniquePtr<SoupBuffer> createSoupBuffer(unsigned offset = 0, unsigned size = 0);
88 static Ref<SharedBuffer> wrapSoupBuffer(SoupBuffer*);
89#endif
90
91#if USE(GLIB)
92 static Ref<SharedBuffer> create(GBytes*);
93#endif
94
95#if USE(GSTREAMER)
96 static Ref<SharedBuffer> create(GstMappedBuffer&);
97#endif
98 // Calling data() causes all the data segments to be copied into one segment if they are not already.
99 // Iterate the segments using begin() and end() instead.
100 // FIXME: Audit the call sites of this function and replace them with iteration if possible.
101 const char* data() const;
102
103 // Creates an ArrayBuffer and copies this SharedBuffer's contents to that
104 // ArrayBuffer without merging segmented buffers into a flat buffer.
105 RefPtr<ArrayBuffer> tryCreateArrayBuffer() const;
106
107 size_t size() const { return m_size; }
108
109 bool isEmpty() const { return !size(); }
110
111 void append(const SharedBuffer&);
112 void append(const char*, size_t);
113 void append(Vector<char>&&);
114
115 void clear();
116
117 Ref<SharedBuffer> copy() const;
118
119 // Data wrapped by a DataSegment should be immutable because it can be referenced by other objects.
120 // To modify or combine the data, allocate a new DataSegment.
121 class DataSegment : public ThreadSafeRefCounted<DataSegment> {
122 public:
123 WEBCORE_EXPORT const char* data() const;
124 WEBCORE_EXPORT size_t size() const;
125
126 static Ref<DataSegment> create(Vector<char>&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
127#if USE(CF)
128 static Ref<DataSegment> create(RetainPtr<CFDataRef>&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
129#endif
130#if USE(SOUP)
131 static Ref<DataSegment> create(GUniquePtr<SoupBuffer>&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
132#endif
133#if USE(GLIB)
134 static Ref<DataSegment> create(GRefPtr<GBytes>&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
135#endif
136#if USE(GSTREAMER)
137 static Ref<DataSegment> create(RefPtr<GstMappedBuffer>&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
138#endif
139 static Ref<DataSegment> create(FileSystem::MappedFileData&& data) { return adoptRef(*new DataSegment(WTFMove(data))); }
140
141 private:
142 DataSegment(Vector<char>&& data)
143 : m_immutableData(WTFMove(data)) { }
144#if USE(CF)
145 DataSegment(RetainPtr<CFDataRef>&& data)
146 : m_immutableData(WTFMove(data)) { }
147#endif
148#if USE(SOUP)
149 DataSegment(GUniquePtr<SoupBuffer>&& data)
150 : m_immutableData(WTFMove(data)) { }
151#endif
152#if USE(GLIB)
153 DataSegment(GRefPtr<GBytes>&& data)
154 : m_immutableData(WTFMove(data)) { }
155#endif
156#if USE(GSTREAMER)
157 DataSegment(RefPtr<GstMappedBuffer>&& data)
158 : m_immutableData(WTFMove(data)) { }
159#endif
160 DataSegment(FileSystem::MappedFileData&& data)
161 : m_immutableData(WTFMove(data)) { }
162
163 Variant<Vector<char>,
164#if USE(CF)
165 RetainPtr<CFDataRef>,
166#endif
167#if USE(SOUP)
168 GUniquePtr<SoupBuffer>,
169#endif
170#if USE(GLIB)
171 GRefPtr<GBytes>,
172#endif
173#if USE(GSTREAMER)
174 RefPtr<GstMappedBuffer>,
175#endif
176 FileSystem::MappedFileData> m_immutableData;
177 friend class SharedBuffer;
178 };
179
180 struct DataSegmentVectorEntry {
181 size_t beginPosition;
182 Ref<DataSegment> segment;
183 };
184 using DataSegmentVector = Vector<DataSegmentVectorEntry, 1>;
185 DataSegmentVector::const_iterator begin() const { return m_segments.begin(); }
186 DataSegmentVector::const_iterator end() const { return m_segments.end(); }
187
188 // begin and end take O(1) time, this takes O(log(N)) time.
189 SharedBufferDataView getSomeData(size_t position) const;
190
191 void hintMemoryNotNeededSoon() const;
192
193 bool operator==(const SharedBuffer&) const;
194 bool operator!=(const SharedBuffer& other) const { return !operator==(other); }
195
196private:
197 explicit SharedBuffer() = default;
198 explicit SharedBuffer(const char*, size_t);
199 explicit SharedBuffer(const unsigned char*, size_t);
200 explicit SharedBuffer(Vector<char>&&);
201 explicit SharedBuffer(FileSystem::MappedFileData&&);
202#if USE(CF)
203 explicit SharedBuffer(CFDataRef);
204#endif
205#if USE(SOUP)
206 explicit SharedBuffer(SoupBuffer*);
207#endif
208#if USE(GLIB)
209 explicit SharedBuffer(GBytes*);
210#endif
211#if USE(GSTREAMER)
212 explicit SharedBuffer(GstMappedBuffer&);
213#endif
214
215 void combineIntoOneSegment() const;
216
217 static RefPtr<SharedBuffer> createFromReadingFile(const String& filePath);
218
219 size_t m_size { 0 };
220 mutable DataSegmentVector m_segments;
221
222#if !ASSERT_DISABLED
223 mutable bool m_hasBeenCombinedIntoOneSegment { false };
224 bool internallyConsistent() const;
225#endif
226};
227
228inline bool operator==(const Ref<SharedBuffer>& left, const SharedBuffer& right)
229{
230 return left.get() == right;
231}
232
233inline bool operator!=(const Ref<SharedBuffer>& left, const SharedBuffer& right)
234{
235 return left.get() != right;
236}
237
238class WEBCORE_EXPORT SharedBufferDataView {
239public:
240 SharedBufferDataView(Ref<SharedBuffer::DataSegment>&&, size_t);
241 size_t size() const;
242 const char* data() const;
243private:
244 size_t m_positionWithinSegment;
245 Ref<SharedBuffer::DataSegment> m_segment;
246};
247
248RefPtr<SharedBuffer> utf8Buffer(const String&);
249
250} // namespace WebCore
251