1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #include "core/fileapi/BlobBuilder.h"
34
35 #include "core/fileapi/Blob.h"
36 #include "core/fileapi/File.h"
37 #include "platform/text/LineEnding.h"
38 #include "wtf/ArrayBuffer.h"
39 #include "wtf/ArrayBufferView.h"
40 #include "wtf/PassRefPtr.h"
41 #include "wtf/Vector.h"
42 #include "wtf/text/CString.h"
43 #include "wtf/text/TextEncoding.h"
44
45 namespace WebCore {
46
BlobBuilder()47 BlobBuilder::BlobBuilder()
48 : m_size(0)
49 {
50 }
51
getBuffer()52 Vector<char>& BlobBuilder::getBuffer()
53 {
54 // If the last item is not a data item, create one. Otherwise, we simply append the new string to the last data item.
55 if (m_items.isEmpty() || m_items[m_items.size() - 1].type != BlobDataItem::Data)
56 m_items.append(BlobDataItem(RawData::create()));
57
58 return *m_items[m_items.size() - 1].data->mutableData();
59 }
60
append(const String & text,const String & endingType)61 void BlobBuilder::append(const String& text, const String& endingType)
62 {
63 CString utf8Text = UTF8Encoding().normalizeAndEncode(text, WTF::EntitiesForUnencodables);
64
65 Vector<char>& buffer = getBuffer();
66 size_t oldSize = buffer.size();
67
68 if (endingType == "native")
69 normalizeLineEndingsToNative(utf8Text, buffer);
70 else {
71 ASSERT(endingType == "transparent");
72 buffer.append(utf8Text.data(), utf8Text.length());
73 }
74 m_size += buffer.size() - oldSize;
75 }
76
append(ArrayBuffer * arrayBuffer)77 void BlobBuilder::append(ArrayBuffer* arrayBuffer)
78 {
79 if (!arrayBuffer)
80 return;
81
82 appendBytesData(arrayBuffer->data(), arrayBuffer->byteLength());
83 }
84
append(ArrayBufferView * arrayBufferView)85 void BlobBuilder::append(ArrayBufferView* arrayBufferView)
86 {
87 if (!arrayBufferView)
88 return;
89
90 appendBytesData(arrayBufferView->baseAddress(), arrayBufferView->byteLength());
91 }
92
append(Blob * blob)93 void BlobBuilder::append(Blob* blob)
94 {
95 if (!blob)
96 return;
97 if (blob->hasBackingFile()) {
98 File* file = toFile(blob);
99 // If the blob is file that is not snapshoted, capture the snapshot now.
100 // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous.
101 long long snapshotSize;
102 double snapshotModificationTime;
103 file->captureSnapshot(snapshotSize, snapshotModificationTime);
104
105 m_size += snapshotSize;
106 if (!file->fileSystemURL().isEmpty())
107 m_items.append(BlobDataItem(file->fileSystemURL(), 0, snapshotSize, snapshotModificationTime));
108 else
109 m_items.append(BlobDataItem(file->path(), 0, snapshotSize, snapshotModificationTime));
110 } else {
111 long long blobSize = static_cast<long long>(blob->size());
112 m_size += blobSize;
113 m_items.append(BlobDataItem(blob->blobDataHandle(), 0, blobSize));
114 }
115 }
116
appendBytesData(const void * data,size_t length)117 void BlobBuilder::appendBytesData(const void* data, size_t length)
118 {
119 Vector<char>& buffer = getBuffer();
120 size_t oldSize = buffer.size();
121 buffer.append(static_cast<const char*>(data), length);
122 m_size += buffer.size() - oldSize;
123 }
124
createBlob(const String & contentType)125 PassRefPtr<Blob> BlobBuilder::createBlob(const String& contentType)
126 {
127 OwnPtr<BlobData> blobData = BlobData::create();
128 blobData->setContentType(contentType);
129 blobData->swapItems(m_items);
130
131 RefPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), m_size));
132
133 // After creating a blob from the current blob data, we do not need to keep the data around any more.
134 // Instead, we only need to keep a reference to the blob data just created.
135 m_items.append(BlobDataItem(blob->blobDataHandle(), 0, m_size));
136
137 return blob.release();
138 }
139
createFile(const String & contentType,const String & fileName,double modificationTime)140 PassRefPtr<File> BlobBuilder::createFile(const String& contentType, const String& fileName, double modificationTime)
141 {
142 OwnPtr<BlobData> blobData = BlobData::create();
143 blobData->setContentType(contentType);
144 blobData->swapItems(m_items);
145
146 RefPtr<File> file = File::create(fileName, modificationTime, BlobDataHandle::create(blobData.release(), m_size));
147
148 // After creating a file from the current blob data, we do not need to keep the data around any more.
149 // Instead, we only need to keep a reference to the blob data just created.
150 m_items.append(BlobDataItem(file->blobDataHandle(), 0, m_size));
151
152 return file.release();
153 }
154
155 } // namespace WebCore
156