e948a7a42227b43a17f3d1596fef4e018f3ff7b1
[WebKit-https.git] / Source / WebCore / fileapi / AsyncFileStream.cpp
1 /*
2  * Copyright (C) 2010 Google Inc.  All rights reserved.
3  * Copyright (C) 2012 Apple Inc. 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 are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33
34 #if ENABLE(BLOB)
35
36 #include "AsyncFileStream.h"
37
38 #include "Blob.h"
39 #include "CrossThreadTask.h"
40 #include "FileStream.h"
41 #include "FileStreamClient.h"
42 #include "FileThread.h"
43 #include "FileThreadTask.h"
44 #include "ScriptExecutionContext.h"
45 #include <wtf/text/WTFString.h>
46
47 namespace WebCore {
48
49 inline AsyncFileStream::AsyncFileStream(ScriptExecutionContext* context, FileStreamClient* client)
50     : m_context(context)
51     , m_stream(FileStream::create())
52     , m_client(client)
53 {
54 }
55
56 PassRefPtr<AsyncFileStream> AsyncFileStream::create(ScriptExecutionContext* context, FileStreamClient* client)
57 {
58     RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(context, client));
59
60     // Hold a reference so that the instance will not get deleted while there are tasks on the file thread.
61     // This is balanced by the deref in derefProxyOnContext below.
62     proxy->ref();
63
64     proxy->fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread));
65
66     return proxy.release();
67 }
68
69 AsyncFileStream::~AsyncFileStream()
70 {
71 }
72
73 FileThread* AsyncFileStream::fileThread()
74 {
75     ASSERT(m_context->isContextThread());
76     ASSERT(m_context->fileThread());
77     return m_context->fileThread();
78 }
79
80 static void didStart(ScriptExecutionContext*, AsyncFileStream* proxy)
81 {
82     if (proxy->client())
83         proxy->client()->didStart();
84 }
85
86 void AsyncFileStream::startOnFileThread()
87 {
88     if (!client())
89         return;
90     m_stream->start();
91     m_context->postTask(createCallbackTask(&didStart, AllowCrossThreadAccess(this)));
92 }
93
94 void AsyncFileStream::stop()
95 {
96     // Clear the client so that we won't be calling callbacks on the client.
97     setClient(0);
98
99     fileThread()->unscheduleTasks(m_stream.get());
100     fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::stopOnFileThread));
101 }
102
103 static void derefProxyOnContext(ScriptExecutionContext*, AsyncFileStream* proxy)
104 {
105     ASSERT(proxy->hasOneRef());
106     proxy->deref();
107 }
108
109 void AsyncFileStream::stopOnFileThread()
110 {
111     m_stream->stop();
112     m_context->postTask(createCallbackTask(&derefProxyOnContext, AllowCrossThreadAccess(this)));
113 }
114
115 static void didGetSize(ScriptExecutionContext*, AsyncFileStream* proxy, long long size)
116 {
117     if (proxy->client())
118         proxy->client()->didGetSize(size);
119 }
120
121 void AsyncFileStream::getSize(const String& path, double expectedModificationTime)
122 {
123     fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::getSizeOnFileThread, path, expectedModificationTime));
124 }
125
126 void AsyncFileStream::getSizeOnFileThread(const String& path, double expectedModificationTime)
127 {
128     long long size = m_stream->getSize(path, expectedModificationTime);
129     m_context->postTask(createCallbackTask(&didGetSize, AllowCrossThreadAccess(this), size));
130 }
131
132 static void didOpen(ScriptExecutionContext*, AsyncFileStream* proxy, bool success)
133 {
134     if (proxy->client())
135         proxy->client()->didOpen(success);
136 }
137
138 void AsyncFileStream::openForRead(const String& path, long long offset, long long length)
139 {
140     fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::openForReadOnFileThread, path, offset, length));
141 }
142
143 void AsyncFileStream::openForReadOnFileThread(const String& path, long long offset, long long length)
144 {
145     bool success = m_stream->openForRead(path, offset, length);
146     m_context->postTask(createCallbackTask(&didOpen, AllowCrossThreadAccess(this), success));
147 }
148
149 void AsyncFileStream::openForWrite(const String& path)
150 {
151     fileThread()->postTask(
152         createFileThreadTask(this,
153                              &AsyncFileStream::openForWriteOnFileThread, path));
154 }
155
156 void AsyncFileStream::openForWriteOnFileThread(const String& path)
157 {
158     bool success = m_stream->openForWrite(path);
159     m_context->postTask(createCallbackTask(&didOpen, AllowCrossThreadAccess(this), success));
160 }
161
162 void AsyncFileStream::close()
163 {
164     fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::closeOnFileThread));
165 }
166
167 void AsyncFileStream::closeOnFileThread()
168 {
169     m_stream->close();
170 }
171
172 static void didRead(ScriptExecutionContext*, AsyncFileStream* proxy, int bytesRead)
173 {
174     if (proxy->client())
175         proxy->client()->didRead(bytesRead);
176 }
177
178 void AsyncFileStream::read(char* buffer, int length)
179 {
180     fileThread()->postTask(
181         createFileThreadTask(this, &AsyncFileStream::readOnFileThread,
182                              AllowCrossThreadAccess(buffer), length));
183 }
184
185 void AsyncFileStream::readOnFileThread(char* buffer, int length)
186 {
187     int bytesRead = m_stream->read(buffer, length);
188     m_context->postTask(createCallbackTask(&didRead, AllowCrossThreadAccess(this), bytesRead));
189 }
190
191 static void didWrite(ScriptExecutionContext*, AsyncFileStream* proxy, int bytesWritten)
192 {
193     if (proxy->client())
194         proxy->client()->didWrite(bytesWritten);
195 }
196
197 void AsyncFileStream::write(const KURL& blobURL, long long position, int length)
198 {
199     fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::writeOnFileThread, blobURL, position, length));
200 }
201
202 void AsyncFileStream::writeOnFileThread(const KURL& blobURL, long long position, int length)
203 {
204     int bytesWritten = m_stream->write(blobURL, position, length);
205     m_context->postTask(createCallbackTask(&didWrite, AllowCrossThreadAccess(this), bytesWritten));
206 }
207
208 static void didTruncate(ScriptExecutionContext*, AsyncFileStream* proxy, bool success)
209 {
210     if (proxy->client())
211         proxy->client()->didTruncate(success);
212 }
213
214 void AsyncFileStream::truncate(long long position)
215 {
216     fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::truncateOnFileThread, position));
217 }
218
219 void AsyncFileStream::truncateOnFileThread(long long position)
220 {
221     bool success = m_stream->truncate(position);
222     m_context->postTask(createCallbackTask(&didTruncate, AllowCrossThreadAccess(this), success));
223 }
224
225 } // namespace WebCore
226
227 #endif // ENABLE(BLOB)