From 11c9a55afd95078d14ab8cd7c1c5c0032af2a498 Mon Sep 17 00:00:00 2001 From: "bungeman@google.com" Date: Mon, 3 Jun 2013 17:10:35 +0000 Subject: [PATCH] Add SkData::NewFromFD. Chromium needs a SkStream backed by a file descriptor. Skia already has the code and can do the work, this change exposes the functionality in Skia in a clean way. https://codereview.chromium.org/15941025/ git-svn-id: http://skia.googlecode.com/svn/trunk@9408 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkData.h | 10 +++ include/core/SkOSFile.h | 14 +++- include/core/SkTemplates.h | 5 ++ src/core/SkData.cpp | 10 +++ src/ports/SkDebug_brew.cpp | 28 -------- src/ports/SkMemory_brew.cpp | 55 --------------- src/ports/SkOSFile_brew.cpp | 90 ------------------------ src/ports/SkOSFile_none.cpp | 4 ++ src/ports/SkOSFile_posix.cpp | 29 ++++++-- src/ports/SkOSFile_win.cpp | 38 ++++++---- src/utils/win/SkDWriteFontFileStream.cpp | 3 +- tests/DataRefTest.cpp | 52 ++++++++++---- 12 files changed, 131 insertions(+), 207 deletions(-) delete mode 100644 src/ports/SkDebug_brew.cpp delete mode 100644 src/ports/SkMemory_brew.cpp delete mode 100644 src/ports/SkOSFile_brew.cpp diff --git a/include/core/SkData.h b/include/core/SkData.h index 0e8ee2219e..4600429fea 100644 --- a/include/core/SkData.h +++ b/include/core/SkData.h @@ -93,11 +93,21 @@ public: /** * Create a new dataref from a SkFILE. * This does not take ownership of the SkFILE, nor close it. + * The caller is free to close the SkFILE at its convenience. * The SkFILE must be open for reading only. * Returns NULL on failure. */ static SkData* NewFromFILE(SkFILE* f); + /** + * Create a new dataref from a file descriptor. + * This does not take ownership of the file descriptor, nor close it. + * The caller is free to close the file descriptor at its convenience. + * The file descriptor must be open for reading only. + * Returns NULL on failure. + */ + static SkData* NewFromFD(int fd); + /** * Create a new dataref using a subset of the data in the specified * src dataref. diff --git a/include/core/SkOSFile.h b/include/core/SkOSFile.h index 11330a03b1..f8ce06bcaf 100644 --- a/include/core/SkOSFile.h +++ b/include/core/SkOSFile.h @@ -54,10 +54,17 @@ size_t sk_ftell(SkFILE*); /** Maps a file into memory. Returns the address and length on success, NULL otherwise. * The mapping is read only. + * When finished with the mapping, free the returned pointer with sk_fmunmap. */ void* sk_fmmap(SkFILE* f, size_t* length); -/** Unmaps a file previously mapped by sk_fmmap. +/** Maps a file descriptor into memory. Returns the address and length on success, NULL otherwise. + * The mapping is read only. + * When finished with the mapping, free the returned pointer with sk_fmunmap. + */ +void* sk_fdmmap(int fd, size_t* length); + +/** Unmaps a file previously mapped by sk_fmmap or sk_fdmmap. * The length parameter must be the same as returned from sk_fmmap. */ void sk_fmunmap(const void* addr, size_t length); @@ -65,6 +72,11 @@ void sk_fmunmap(const void* addr, size_t length); /** Returns true if the two point at the exact same filesystem object. */ bool sk_fidentical(SkFILE* a, SkFILE* b); +/** Returns the underlying file descriptor for the given file. + * The return value will be < 0 on failure. + */ +int sk_fileno(SkFILE* f); + // Returns true if something (file, directory, ???) exists at this path. bool sk_exists(const char *path); diff --git a/include/core/SkTemplates.h b/include/core/SkTemplates.h index ce76dbfbba..bbbed48cea 100644 --- a/include/core/SkTemplates.h +++ b/include/core/SkTemplates.h @@ -64,6 +64,11 @@ template static D* SkTAddOffset(S* ptr, size_t byteOffs ); } +/** Returns true if the source value 's' will fit in the destination type 'D'. */ +template inline bool SkTFitsIn(S s) { + return static_cast(s) == s; +} + /** \class SkAutoTCallVProc Call a function when this goes out of scope. The template uses two diff --git a/src/core/SkData.cpp b/src/core/SkData.cpp index 32e029740a..c1a21365ab 100644 --- a/src/core/SkData.cpp +++ b/src/core/SkData.cpp @@ -97,6 +97,16 @@ SkData* SkData::NewFromFILE(SkFILE* f) { return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); } +SkData* SkData::NewFromFD(int fd) { + size_t size; + void* addr = sk_fdmmap(fd, &size); + if (NULL == addr) { + return NULL; + } + + return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL); +} + // assumes context is a SkData static void sk_dataref_releaseproc(const void*, size_t, void* context) { SkData* src = reinterpret_cast(context); diff --git a/src/ports/SkDebug_brew.cpp b/src/ports/SkDebug_brew.cpp deleted file mode 100644 index b7ad3ef275..0000000000 --- a/src/ports/SkDebug_brew.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* libs/corecg/SkDebug_brew.cpp - * - * Copyright 2009, The Android Open Source Project - * Copyright 2009, Company 100, Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTypes.h" - -#ifdef SK_BUILD_FOR_BREW - -static const size_t kBufferSize = 256; - -#include -#include - -void SkDebugf(const char format[], ...) { - char buffer[kBufferSize + 1]; - va_list args; - va_start(args, format); - VSNPRINTF(buffer, kBufferSize, format, args); - va_end(args); - DBGPRINTF(buffer); -} - -#endif SK_BUILD_FOR_BREW diff --git a/src/ports/SkMemory_brew.cpp b/src/ports/SkMemory_brew.cpp deleted file mode 100644 index 96af7021e6..0000000000 --- a/src/ports/SkMemory_brew.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* libs/graphics/ports/SkMemory_brew.cpp - * - * Copyright 2009, The Android Open Source Project - * Copyright 2009, Company 100, Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTypes.h" - -#ifdef SK_BUILD_FOR_BREW - -#include - -void sk_throw() { - SkDEBUGFAIL("sk_throw"); - abort(); -} - -void sk_out_of_memory(void) { - SkDEBUGFAIL("sk_out_of_memory"); - abort(); -} - -void* sk_malloc_throw(size_t size) { - return sk_malloc_flags(size, SK_MALLOC_THROW); -} - -void* sk_realloc_throw(void* addr, size_t size) { - void* p = REALLOC(addr, size | ALLOC_NO_ZMEM); - if (size == 0) { - return p; - } - if (p == NULL) { - sk_throw(); - } - return p; -} - -void sk_free(void* p) { - FREEIF(p); -} - -void* sk_malloc_flags(size_t size, unsigned flags) { - void* p = MALLOC(size | ALLOC_NO_ZMEM); - if (p == NULL) { - if (flags & SK_MALLOC_THROW) { - sk_throw(); - } - } - return p; -} - -#endif diff --git a/src/ports/SkOSFile_brew.cpp b/src/ports/SkOSFile_brew.cpp deleted file mode 100644 index 50e133ff2f..0000000000 --- a/src/ports/SkOSFile_brew.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* libs/graphics/ports/SkOSFile_brew.cpp - * - * Copyright 2006, The Android Open Source Project - * Copyright 2009, Company 100, Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkOSFile.h" - -#ifdef SK_BUILD_FOR_BREW - -#include -#include -#include - -SkFILE* sk_fopen(const char path[], SkFILE_Flags flags) -{ - int err; - OpenFileMode mode; - IFileMgr* fileMgr; - IFile* file; - IShell* shell; - - shell = reinterpret_cast(GETAPPINSTANCE())->m_pIShell; - err = ISHELL_CreateInstance(shell, AEECLSID_FILEMGR, (void**)&fileMgr); - if (err!= SUCCESS) - return NULL; - - if (flags & kWrite_SkFILE_Flag) - mode = _OFM_READWRITE; - else /* kRead_SkFILE_Flag */ - mode = _OFM_READ; - - file = IFILEMGR_OpenFile(fileMgr, path, mode); - IFILEMGR_Release(fileMgr); - - return (SkFILE*)file; -} - -size_t sk_fgetsize(SkFILE* f) -{ - FileInfo fileInfo; - - IFILE_GetInfo((IFile*)f, &fileInfo); - return fileInfo.dwSize; -} - -bool sk_frewind(SkFILE* f) -{ - SkASSERT(f); - return IFILE_Seek((IFile*)f, _SEEK_START, 0) == SUCCESS; -} - -size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f) -{ - SkASSERT(f); - if (buffer == NULL) - { - int err = IFILE_Seek((IFile*)f, _SEEK_CURRENT, (int)byteCount); - if (err == EFAILED) { - SkDEBUGF(("sk_fread: IFILE_Seek(%d) failed returned:%d\n", byteCount, err)); - return 0; - } - return byteCount; - } - else - return IFILE_Read((IFile*)f, buffer, byteCount); -} - -size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE* f) -{ - SkASSERT(f); - return IFILE_Write((IFile*)f, buffer, byteCount); -} - -void sk_fflush(SkFILE* f) -{ - SkASSERT(f); -} - -void sk_fclose(SkFILE* f) -{ - SkASSERT(f); - IFILE_Release((IFile*)f); -} - -#endif diff --git a/src/ports/SkOSFile_none.cpp b/src/ports/SkOSFile_none.cpp index e22d22ed4d..f268e13783 100644 --- a/src/ports/SkOSFile_none.cpp +++ b/src/ports/SkOSFile_none.cpp @@ -13,6 +13,10 @@ bool sk_fidentical(SkFILE* a, SkFILE* b) { void sk_fmunmap(const void* addr, size_t length) { } +void* sk_fdmmap(int fd, size_t* size) { + return NULL; +} + void* sk_fmmap(SkFILE* f, size_t* size) { return NULL; } diff --git a/src/ports/SkOSFile_posix.cpp b/src/ports/SkOSFile_posix.cpp index c9da4db6b8..72a1b59335 100644 --- a/src/ports/SkOSFile_posix.cpp +++ b/src/ports/SkOSFile_posix.cpp @@ -7,6 +7,8 @@ #include "SkOSFile.h" +#include "SkTemplates.h" + #include #include #include @@ -42,16 +44,18 @@ void sk_fmunmap(const void* addr, size_t length) { munmap(const_cast(addr), length); } -void* sk_fmmap(SkFILE* f, size_t* size) { - size_t fileSize = sk_fgetsize(f); - if (0 == fileSize) { +void* sk_fdmmap(int fd, size_t* size) { + struct stat status; + if (0 != fstat(fd, &status)) { return NULL; } - - int fd = fileno((FILE*)f); - if (fd < 0) { + if (!S_ISREG(status.st_mode)) { return NULL; } + if (!SkTFitsIn(status.st_size)) { + return NULL; + } + size_t fileSize = static_cast(status.st_size); void* addr = mmap(NULL, fileSize, PROT_READ, MAP_PRIVATE, fd, 0); if (MAP_FAILED == addr) { @@ -61,3 +65,16 @@ void* sk_fmmap(SkFILE* f, size_t* size) { *size = fileSize; return addr; } + +int sk_fileno(SkFILE* f) { + return fileno((FILE*)f); +} + +void* sk_fmmap(SkFILE* f, size_t* size) { + int fd = sk_fileno(f); + if (fd < 0) { + return NULL; + } + + return sk_fdmmap(fd, size); +} diff --git a/src/ports/SkOSFile_win.cpp b/src/ports/SkOSFile_win.cpp index fdf9ca5013..2133f7bf12 100644 --- a/src/ports/SkOSFile_win.cpp +++ b/src/ports/SkOSFile_win.cpp @@ -7,6 +7,8 @@ #include "SkOSFile.h" +#include "SkTemplates.h" + #include #include #include @@ -65,22 +67,21 @@ void sk_fmunmap(const void* addr, size_t) { UnmapViewOfFile(addr); } -void* sk_fmmap(SkFILE* f, size_t* length) { - size_t fileSize = sk_fgetsize(f); - if (0 == fileSize) { - return NULL; - } - - int fileno = _fileno((FILE*)f); - if (fileno < 0) { - return NULL; - } - +void* sk_fdmmap(int fileno, size_t* length) { HANDLE file = (HANDLE)_get_osfhandle(fileno); if (INVALID_HANDLE_VALUE == file) { return NULL; } + LARGE_INTEGER fileSize; + if (0 == GetFileSizeEx(file, &fileSize)) { + //TODO: use SK_TRACEHR(GetLastError(), "Could not get file size.") to report. + return NULL; + } + if (!SkTFitsIn(fileSize.QuadPart)) { + return NULL; + } + SkAutoWinMMap mmap(CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL)); if (!mmap.isValid()) { //TODO: use SK_TRACEHR(GetLastError(), "Could not create file mapping.") to report. @@ -94,6 +95,19 @@ void* sk_fmmap(SkFILE* f, size_t* length) { return NULL; } - *length = fileSize; + *length = static_cast(fileSize.QuadPart); return addr; } + +int sk_fileno(SkFILE* f) { + return _fileno((FILE*)f); +} + +void* sk_fmmap(SkFILE* f, size_t* length) { + int fileno = sk_fileno(f); + if (fileno < 0) { + return NULL; + } + + return sk_fdmmap(fileno, length); +} diff --git a/src/utils/win/SkDWriteFontFileStream.cpp b/src/utils/win/SkDWriteFontFileStream.cpp index 971fdb98b4..eb591138b7 100644 --- a/src/utils/win/SkDWriteFontFileStream.cpp +++ b/src/utils/win/SkDWriteFontFileStream.cpp @@ -8,6 +8,7 @@ #include "SkTypes.h" #include "SkDWriteFontFileStream.h" #include "SkHRESULT.h" +#include "SkTemplates.h" #include "SkTScopedComPtr.h" #include @@ -111,7 +112,7 @@ size_t SkDWriteFontFileStream::getLength() const { HRESULT hr = S_OK; UINT64 realFileSize = 0; hr = fFontFileStream->GetFileSize(&realFileSize); - if (realFileSize > (std::numeric_limits::max)()) { + if (!SkTFitsIn(realFileSize)) { return 0; } return static_cast(realFileSize); diff --git a/tests/DataRefTest.cpp b/tests/DataRefTest.cpp index 0cbce3fcd1..d8bd24b2ba 100644 --- a/tests/DataRefTest.cpp +++ b/tests/DataRefTest.cpp @@ -9,21 +9,10 @@ #include "SkData.h" #include "SkDataSet.h" #include "SkDataTable.h" -#include "SkStream.h" #include "SkOrderedReadBuffer.h" #include "SkOrderedWriteBuffer.h" - -template class SkTUnref { -public: - SkTUnref(T* ref) : fRef(ref) {} - ~SkTUnref() { fRef->unref(); } - - operator T*() { return fRef; } - operator const T*() { return fRef; } - -private: - T* fRef; -}; +#include "SkOSFile.h" +#include "SkStream.h" static void test_is_equal(skiatest::Reporter* reporter, const SkDataTable* a, const SkDataTable* b) { @@ -223,7 +212,7 @@ static void test_dataset(skiatest::Reporter* reporter, const SkDataSet& ds, static void test_dataset(skiatest::Reporter* reporter) { SkDataSet set0(NULL, 0); - SkDataSet set1("hello", SkTUnref(SkData::NewWithCString("world"))); + SkDataSet set1("hello", SkAutoTUnref(SkData::NewWithCString("world"))); const SkDataSet::Pair pairs[] = { { "one", SkData::NewWithCString("1") }, @@ -270,6 +259,40 @@ static void test_cstring(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, 0 == *r2->bytes()); } +static void test_files(skiatest::Reporter* reporter) { + if (skiatest::Test::GetTmpDir().isEmpty()) { + return; + } + + const char* tmpDir = skiatest::Test::GetTmpDir().c_str(); + SkString path; + path.printf("%s%s", tmpDir, "data_test"); + + const char s[] = "abcdefghijklmnopqrstuvwxyz"; + { + SkFILEWStream writer(path.c_str()); + if (!writer.isValid()) { + SkString msg; + msg.printf("Failed to create tmp file %s\n", path.c_str()); + reporter->reportFailed(msg.c_str()); + return; + } + writer.write(s, 26); + } + + SkFILE* file = sk_fopen(path.c_str(), kRead_SkFILE_Flag); + SkAutoTUnref r1(SkData::NewFromFILE(file)); + REPORTER_ASSERT(reporter, r1.get() != NULL); + REPORTER_ASSERT(reporter, r1->size() == 26); + REPORTER_ASSERT(reporter, strncmp(static_cast(r1->data()), s, 26) == 0); + + int fd = sk_fileno(file); + SkAutoTUnref r2(SkData::NewFromFD(fd)); + REPORTER_ASSERT(reporter, r2.get() != NULL); + REPORTER_ASSERT(reporter, r2->size() == 26); + REPORTER_ASSERT(reporter, strncmp(static_cast(r2->data()), s, 26) == 0); +} + static void TestData(skiatest::Reporter* reporter) { const char* str = "We the people, in order to form a more perfect union."; const int N = 10; @@ -297,6 +320,7 @@ static void TestData(skiatest::Reporter* reporter) { test_cstring(reporter); test_dataset(reporter); + test_files(reporter); } #include "TestClassDef.h"