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 "core/platform/FileMetadata.h" 30 #include "core/platform/FileSystem.h" 31 #include "core/platform/MIMETypeRegistry.h" 32 #include "public/platform/Platform.h" 33 #include "public/platform/WebFileUtilities.h" 34 #include "wtf/CurrentTime.h" 35 #include "wtf/DateMath.h" 36 #include "wtf/text/WTFString.h" 37 38 namespace WebCore { 39 40 static String getContentTypeFromFileName(const String& name, File::ContentTypeLookupPolicy policy) 41 { 42 String type; 43 int index = name.reverseFind('.'); 44 if (index != -1) { 45 if (policy == File::WellKnownContentTypes) 46 type = MIMETypeRegistry::getWellKnownMIMETypeForExtension(name.substring(index + 1)); 47 else { 48 ASSERT(policy == File::AllContentTypes); 49 type = MIMETypeRegistry::getMIMETypeForExtension(name.substring(index + 1)); 50 } 51 } 52 return type; 53 } 54 55 static PassOwnPtr<BlobData> createBlobDataForFileWithType(const String& path, const String& contentType) 56 { 57 OwnPtr<BlobData> blobData = BlobData::create(); 58 blobData->setContentType(contentType); 59 blobData->appendFile(path); 60 return blobData.release(); 61 } 62 63 static PassOwnPtr<BlobData> createBlobDataForFile(const String& path, File::ContentTypeLookupPolicy policy) 64 { 65 return createBlobDataForFileWithType(path, getContentTypeFromFileName(path, policy)); 66 } 67 68 static PassOwnPtr<BlobData> createBlobDataForFileWithName(const String& path, const String& fileSystemName, File::ContentTypeLookupPolicy policy) 69 { 70 return createBlobDataForFileWithType(path, getContentTypeFromFileName(fileSystemName, policy)); 71 } 72 73 static PassOwnPtr<BlobData> createBlobDataForFileWithMetadata(const String& fileSystemName, const FileMetadata& metadata) 74 { 75 OwnPtr<BlobData> blobData = BlobData::create(); 76 blobData->setContentType(getContentTypeFromFileName(fileSystemName, File::WellKnownContentTypes)); 77 blobData->appendFile(metadata.platformPath, 0, metadata.length, metadata.modificationTime); 78 return blobData.release(); 79 } 80 81 static PassOwnPtr<BlobData> createBlobDataForFileSystemURL(const KURL& fileSystemURL, const FileMetadata& metadata) 82 { 83 OwnPtr<BlobData> blobData = BlobData::create(); 84 blobData->setContentType(getContentTypeFromFileName(fileSystemURL.path(), File::WellKnownContentTypes)); 85 blobData->appendURL(fileSystemURL, 0, metadata.length, metadata.modificationTime); 86 return blobData.release(); 87 } 88 89 PassRefPtr<File> File::createWithRelativePath(const String& path, const String& relativePath) 90 { 91 RefPtr<File> file = adoptRef(new File(path, AllContentTypes)); 92 file->m_relativePath = relativePath; 93 return file.release(); 94 } 95 96 File::File(const String& path, ContentTypeLookupPolicy policy) 97 : Blob(createBlobDataForFile(path, policy), -1) 98 , m_path(path) 99 , m_name(WebKit::Platform::current()->fileUtilities()->baseName(path)) 100 , m_snapshotSize(-1) 101 , m_snapshotModificationTime(invalidFileTime()) 102 { 103 ScriptWrappable::init(this); 104 } 105 106 File::File(const String& path, const KURL& url, const String& type) 107 : Blob(url, type, -1) 108 , m_path(path) 109 , m_snapshotSize(-1) 110 , m_snapshotModificationTime(invalidFileTime()) 111 { 112 ScriptWrappable::init(this); 113 m_name = WebKit::Platform::current()->fileUtilities()->baseName(path); 114 // FIXME: File object serialization/deserialization does not include 115 // newer file object data members: m_name and m_relativePath. 116 // See SerializedScriptValue.cpp for js and v8. 117 } 118 119 File::File(const String& path, const String& name, ContentTypeLookupPolicy policy) 120 : Blob(createBlobDataForFileWithName(path, name, policy), -1) 121 , m_path(path) 122 , m_name(name) 123 , m_snapshotSize(-1) 124 , m_snapshotModificationTime(invalidFileTime()) 125 { 126 ScriptWrappable::init(this); 127 } 128 129 File::File(const String& name, const FileMetadata& metadata) 130 : Blob(createBlobDataForFileWithMetadata(name, metadata), metadata.length) 131 , m_path(metadata.platformPath) 132 , m_name(name) 133 , m_snapshotSize(metadata.length) 134 , m_snapshotModificationTime(metadata.modificationTime) 135 { 136 ScriptWrappable::init(this); 137 } 138 139 File::File(const KURL& fileSystemURL, const FileMetadata& metadata) 140 : Blob(createBlobDataForFileSystemURL(fileSystemURL, metadata), metadata.length) 141 , m_fileSystemURL(fileSystemURL) 142 , m_snapshotSize(metadata.length) 143 , m_snapshotModificationTime(metadata.modificationTime) 144 { 145 ScriptWrappable::init(this); 146 } 147 148 double File::lastModifiedDate() const 149 { 150 if (hasValidSnapshotMetadata() && isValidFileTime(m_snapshotModificationTime)) 151 return m_snapshotModificationTime * msPerSecond; 152 153 time_t modificationTime; 154 if (getFileModificationTime(m_path, modificationTime) && isValidFileTime(modificationTime)) 155 return modificationTime * msPerSecond; 156 157 return currentTime() * msPerSecond; 158 } 159 160 unsigned long long File::size() const 161 { 162 if (hasValidSnapshotMetadata()) 163 return m_snapshotSize; 164 165 // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to 166 // come up with an exception to throw if file size is not representable. 167 long long size; 168 if (!getFileSize(m_path, size)) 169 return 0; 170 return static_cast<unsigned long long>(size); 171 } 172 173 void File::captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const 174 { 175 if (hasValidSnapshotMetadata()) { 176 snapshotSize = m_snapshotSize; 177 snapshotModificationTime = m_snapshotModificationTime; 178 return; 179 } 180 181 // 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. 182 // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, 0 size is returned. 183 FileMetadata metadata; 184 if (!getFileMetadata(m_path, metadata)) { 185 snapshotSize = 0; 186 snapshotModificationTime = invalidFileTime(); 187 return; 188 } 189 190 snapshotSize = metadata.length; 191 snapshotModificationTime = metadata.modificationTime; 192 } 193 194 } // namespace WebCore 195