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> |
48 | typedef struct _GBytes GBytes; |
49 | #endif |
50 | |
51 | #if USE(GSTREAMER) |
52 | #include "GStreamerCommon.h" |
53 | #endif |
54 | |
55 | #if USE(FOUNDATION) |
56 | OBJC_CLASS NSArray; |
57 | OBJC_CLASS NSData; |
58 | #endif |
59 | |
60 | namespace WebCore { |
61 | |
62 | class SharedBufferDataView; |
63 | |
64 | class WEBCORE_EXPORT SharedBuffer : public RefCounted<SharedBuffer> { |
65 | public: |
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 | |
196 | private: |
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 | |
228 | inline bool operator==(const Ref<SharedBuffer>& left, const SharedBuffer& right) |
229 | { |
230 | return left.get() == right; |
231 | } |
232 | |
233 | inline bool operator!=(const Ref<SharedBuffer>& left, const SharedBuffer& right) |
234 | { |
235 | return left.get() != right; |
236 | } |
237 | |
238 | class WEBCORE_EXPORT SharedBufferDataView { |
239 | public: |
240 | SharedBufferDataView(Ref<SharedBuffer::DataSegment>&&, size_t); |
241 | size_t size() const; |
242 | const char* data() const; |
243 | private: |
244 | size_t m_positionWithinSegment; |
245 | Ref<SharedBuffer::DataSegment> m_segment; |
246 | }; |
247 | |
248 | RefPtr<SharedBuffer> utf8Buffer(const String&); |
249 | |
250 | } // namespace WebCore |
251 | |