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
This commit is contained in:
bungeman@google.com 2013-06-03 17:10:35 +00:00
parent 135ece137b
commit 11c9a55afd
12 changed files with 131 additions and 207 deletions

View File

@ -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.

View File

@ -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);

View File

@ -64,6 +64,11 @@ template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffs
);
}
/** Returns true if the source value 's' will fit in the destination type 'D'. */
template <typename D, typename S> inline bool SkTFitsIn(S s) {
return static_cast<D>(s) == s;
}
/** \class SkAutoTCallVProc
Call a function when this goes out of scope. The template uses two

View File

@ -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<SkData*>(context);

View File

@ -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 <AEEStdLib.h>
#include <stdarg.h>
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

View File

@ -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 <AEEStdLib.h>
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

View File

@ -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 <AEEAppGen.h>
#include <AEEFile.h>
#include <AEEStdLib.h>
SkFILE* sk_fopen(const char path[], SkFILE_Flags flags)
{
int err;
OpenFileMode mode;
IFileMgr* fileMgr;
IFile* file;
IShell* shell;
shell = reinterpret_cast<AEEApplet*>(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

View File

@ -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;
}

View File

@ -7,6 +7,8 @@
#include "SkOSFile.h"
#include "SkTemplates.h"
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
@ -42,16 +44,18 @@ void sk_fmunmap(const void* addr, size_t length) {
munmap(const_cast<void*>(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<size_t>(status.st_size)) {
return NULL;
}
size_t fileSize = static_cast<size_t>(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);
}

View File

@ -7,6 +7,8 @@
#include "SkOSFile.h"
#include "SkTemplates.h"
#include <io.h>
#include <stdio.h>
#include <sys/stat.h>
@ -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<size_t>(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<size_t>(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);
}

View File

@ -8,6 +8,7 @@
#include "SkTypes.h"
#include "SkDWriteFontFileStream.h"
#include "SkHRESULT.h"
#include "SkTemplates.h"
#include "SkTScopedComPtr.h"
#include <dwrite.h>
@ -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<size_t>::max)()) {
if (!SkTFitsIn<size_t>(realFileSize)) {
return 0;
}
return static_cast<size_t>(realFileSize);

View File

@ -9,21 +9,10 @@
#include "SkData.h"
#include "SkDataSet.h"
#include "SkDataTable.h"
#include "SkStream.h"
#include "SkOrderedReadBuffer.h"
#include "SkOrderedWriteBuffer.h"
template <typename T> 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>(SkData::NewWithCString("world")));
SkDataSet set1("hello", SkAutoTUnref<SkData>(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<SkData> r1(SkData::NewFromFILE(file));
REPORTER_ASSERT(reporter, r1.get() != NULL);
REPORTER_ASSERT(reporter, r1->size() == 26);
REPORTER_ASSERT(reporter, strncmp(static_cast<const char*>(r1->data()), s, 26) == 0);
int fd = sk_fileno(file);
SkAutoTUnref<SkData> r2(SkData::NewFromFD(fd));
REPORTER_ASSERT(reporter, r2.get() != NULL);
REPORTER_ASSERT(reporter, r2->size() == 26);
REPORTER_ASSERT(reporter, strncmp(static_cast<const char*>(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"