1 /* 2 * Copyright (C) 2008 Apple 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 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "core/fileapi/File.h" 28 29 #include "platform/FileMetadata.h" 30 #include "platform/MIMETypeRegistry.h" 31 #include "public/platform/Platform.h" 32 #include "public/platform/WebFileUtilities.h" 33 #include "wtf/CurrentTime.h" 34 #include "wtf/DateMath.h" 35 36 namespace WebCore { 37 38 static String getContentTypeFromFileName(const String& name, File::ContentTypeLookupPolicy policy) 39 { 40 String type; 41 int index = name.reverseFind('.'); 42 if (index != -1) { 43 if (policy == File::WellKnownContentTypes) 44 type = MIMETypeRegistry::getWellKnownMIMETypeForExtension(name.substring(index + 1)); 45 else { 46 ASSERT(policy == File::AllContentTypes); 47 type = MIMETypeRegistry::getMIMETypeForExtension(name.substring(index + 1)); 48 } 49 } 50 return type; 51 } 52 53 static PassOwnPtr<BlobData> createBlobDataForFileWithType(const String& path, const String& contentType) 54 { 55 OwnPtr<BlobData> blobData = BlobData::create(); 56 blobData->setContentType(contentType); 57 blobData->appendFile(path); 58 return blobData.release(); 59 } 60 61 static PassOwnPtr<BlobData> createBlobDataForFile(const String& path, File::ContentTypeLookupPolicy policy) 62 { 63 return createBlobDataForFileWithType(path, getContentTypeFromFileName(path, policy)); 64 } 65 66 static PassOwnPtr<BlobData> createBlobDataForFileWithName(const String& path, const String& fileSystemName, File::ContentTypeLookupPolicy policy) 67 { 68 return createBlobDataForFileWithType(path, getContentTypeFromFileName(fileSystemName, policy)); 69 } 70 71 static PassOwnPtr<BlobData> createBlobDataForFileWithMetadata(const String& fileSystemName, const FileMetadata& metadata) 72 { 73 OwnPtr<BlobData> blobData = BlobData::create(); 74 blobData->setContentType(getContentTypeFromFileName(fileSystemName, File::WellKnownContentTypes)); 75 blobData->appendFile(metadata.platformPath, 0, metadata.length, metadata.modificationTime); 76 return blobData.release(); 77 } 78 79 static PassOwnPtr<BlobData> createBlobDataForFileSystemURL(const KURL& fileSystemURL, const FileMetadata& metadata) 80 { 81 OwnPtr<BlobData> blobData = BlobData::create(); 82 blobData->setContentType(getContentTypeFromFileName(fileSystemURL.path(), File::WellKnownContentTypes)); 83 blobData->appendFileSystemURL(fileSystemURL, 0, metadata.length, metadata.modificationTime); 84 return blobData.release(); 85 } 86 87 PassRefPtr<File> File::createWithRelativePath(const String& path, const String& relativePath) 88 { 89 RefPtr<File> file = adoptRef(new File(path, AllContentTypes)); 90 file->m_relativePath = relativePath; 91 return file.release(); 92 } 93 94 File::File(const String& path, ContentTypeLookupPolicy policy) 95 : Blob(BlobDataHandle::create(createBlobDataForFile(path, policy), -1)) 96 , m_hasBackingFile(true) 97 , m_path(path) 98 , m_name(blink::Platform::current()->fileUtilities()->baseName(path)) 99 , m_snapshotSize(-1) 100 , m_snapshotModificationTime(invalidFileTime()) 101 { 102 ScriptWrappable::init(this); 103 } 104 105 File::File(const String& path, const String& name, ContentTypeLookupPolicy policy) 106 : Blob(BlobDataHandle::create(createBlobDataForFileWithName(path, name, policy), -1)) 107 , m_hasBackingFile(true) 108 , m_path(path) 109 , m_name(name) 110 , m_snapshotSize(-1) 111 , m_snapshotModificationTime(invalidFileTime()) 112 { 113 ScriptWrappable::init(this); 114 } 115 116 File::File(const String& path, const String& name, const String& relativePath, bool hasSnaphotData, uint64_t size, double lastModified, PassRefPtr<BlobDataHandle> blobDataHandle) 117 : Blob(blobDataHandle) 118 , m_hasBackingFile(!path.isEmpty() || !relativePath.isEmpty()) 119 , m_path(path) 120 , m_name(name) 121 , m_snapshotSize(hasSnaphotData ? static_cast<long long>(size) : -1) 122 , m_snapshotModificationTime(hasSnaphotData ? lastModified : invalidFileTime()) 123 , m_relativePath(relativePath) 124 { 125 ScriptWrappable::init(this); 126 } 127 128 File::File(const String& name, double modificationTime, PassRefPtr<BlobDataHandle> blobDataHandle) 129 : Blob(blobDataHandle) 130 , m_hasBackingFile(false) 131 , m_name(name) 132 , m_snapshotSize(Blob::size()) 133 , m_snapshotModificationTime(modificationTime) 134 { 135 ScriptWrappable::init(this); 136 } 137 138 File::File(const String& name, const FileMetadata& metadata) 139 : Blob(BlobDataHandle::create(createBlobDataForFileWithMetadata(name, metadata), metadata.length)) 140 , m_hasBackingFile(true) 141 , m_path(metadata.platformPath) 142 , m_name(name) 143 , m_snapshotSize(metadata.length) 144 , m_snapshotModificationTime(metadata.modificationTime) 145 { 146 ScriptWrappable::init(this); 147 } 148 149 File::File(const KURL& fileSystemURL, const FileMetadata& metadata) 150 : Blob(BlobDataHandle::create(createBlobDataForFileSystemURL(fileSystemURL, metadata), metadata.length)) 151 , m_hasBackingFile(true) 152 , m_fileSystemURL(fileSystemURL) 153 , m_snapshotSize(metadata.length) 154 , m_snapshotModificationTime(metadata.modificationTime) 155 { 156 ScriptWrappable::init(this); 157 } 158 159 double File::lastModifiedDate() const 160 { 161 if (hasValidSnapshotMetadata() && isValidFileTime(m_snapshotModificationTime)) 162 return m_snapshotModificationTime * msPerSecond; 163 164 time_t modificationTime; 165 if (getFileModificationTime(m_path, modificationTime) && isValidFileTime(modificationTime)) 166 return modificationTime * msPerSecond; 167 168 return currentTime() * msPerSecond; 169 } 170 171 unsigned long long File::size() const 172 { 173 if (hasValidSnapshotMetadata()) 174 return m_snapshotSize; 175 176 // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to 177 // come up with an exception to throw if file size is not representable. 178 long long size; 179 if (!getFileSize(m_path, size)) 180 return 0; 181 return static_cast<unsigned long long>(size); 182 } 183 184 void File::captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const 185 { 186 if (hasValidSnapshotMetadata()) { 187 snapshotSize = m_snapshotSize; 188 snapshotModificationTime = m_snapshotModificationTime; 189 return; 190 } 191 192 // Obtains a snapshot of the file by capturing its current size and modification time. This is used when we slice a file for the first time. 193 // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, 0 size is returned. 194 FileMetadata metadata; 195 if (!getFileMetadata(m_path, metadata)) { 196 snapshotSize = 0; 197 snapshotModificationTime = invalidFileTime(); 198 return; 199 } 200 201 snapshotSize = metadata.length; 202 snapshotModificationTime = metadata.modificationTime; 203 } 204 205 } // namespace WebCore 206