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#include "Blob.h"
33
34#include "BlobURL.h"
35#include "File.h"
36#include "ThreadableBlobRegistry.h"
37
38namespace WebCore {
39
40Blob::Blob(PassOwnPtr<BlobData> blobData, long long size)
41    : m_type(blobData->contentType())
42    , m_size(size)
43{
44    ASSERT(blobData);
45
46    // Create a new internal URL and register it with the provided blob data.
47    m_internalURL = BlobURL::createInternalURL();
48    ThreadableBlobRegistry::registerBlobURL(m_internalURL, blobData);
49}
50
51Blob::Blob(const KURL& srcURL, const String& type, long long size)
52    : m_type(type)
53    , m_size(size)
54{
55    // Create a new internal URL and register it with the same blob data as the source URL.
56    m_internalURL = BlobURL::createInternalURL();
57    ThreadableBlobRegistry::registerBlobURL(m_internalURL, srcURL);
58}
59
60Blob::~Blob()
61{
62    ThreadableBlobRegistry::unregisterBlobURL(m_internalURL);
63}
64
65#if ENABLE(BLOB)
66PassRefPtr<Blob> Blob::webkitSlice(long long start, long long end, const String& contentType) const
67{
68    // When we slice a file for the first time, we obtain a snapshot of the file by capturing its current size and modification time.
69    // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed.
70    long long size;
71    double modificationTime;
72    if (isFile())
73        // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous.
74        static_cast<const File*>(this)->captureSnapshot(size, modificationTime);
75    else {
76        ASSERT(m_size != -1);
77        size = m_size;
78    }
79
80    // Convert the negative value that is used to select from the end.
81    if (start < 0)
82        start = start + size;
83    if (end < 0)
84        end = end + size;
85
86    // Clamp the range if it exceeds the size limit.
87    if (start < 0)
88        start = 0;
89    if (end < 0)
90        end = 0;
91    if (start >= size) {
92        start = 0;
93        end = 0;
94    } else if (end < start)
95        end = start;
96    else if (end > size)
97        end = size;
98
99    long long length = end - start;
100    OwnPtr<BlobData> blobData = BlobData::create();
101    blobData->setContentType(contentType);
102    if (isFile())
103        blobData->appendFile(static_cast<const File*>(this)->path(), start, length, modificationTime);
104    else
105        blobData->appendBlob(m_internalURL, start, length);
106
107    return Blob::create(blobData.release(), length);
108}
109#endif
110
111} // namespace WebCore
112