Change SkStream.

https://codereview.chromium.org/15298009/


git-svn-id: http://skia.googlecode.com/svn/trunk@9312 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bungeman@google.com 2013-05-29 13:43:31 +00:00
parent 6320e8f393
commit 6cab1a4b6a
15 changed files with 662 additions and 721 deletions

View File

@ -78,7 +78,6 @@
'<(skia_src_path)/core/SkEdge.h', '<(skia_src_path)/core/SkEdge.h',
'<(skia_src_path)/core/SkError.cpp', '<(skia_src_path)/core/SkError.cpp',
'<(skia_src_path)/core/SkErrorInternals.h', '<(skia_src_path)/core/SkErrorInternals.h',
'<(skia_src_path)/core/SkFDStream.cpp',
'<(skia_src_path)/core/SkFP.h', '<(skia_src_path)/core/SkFP.h',
'<(skia_src_path)/core/SkFilterProc.cpp', '<(skia_src_path)/core/SkFilterProc.cpp',
'<(skia_src_path)/core/SkFilterProc.h', '<(skia_src_path)/core/SkFilterProc.h',

View File

@ -31,7 +31,9 @@
'../src/ports/SkThread_win.cpp', '../src/ports/SkThread_win.cpp',
'../src/ports/SkMemory_malloc.cpp', '../src/ports/SkMemory_malloc.cpp',
'../src/ports/SkOSFile_posix.cpp',
'../src/ports/SkOSFile_stdio.cpp', '../src/ports/SkOSFile_stdio.cpp',
'../src/ports/SkOSFile_win.cpp',
'../src/ports/SkTime_Unix.cpp', '../src/ports/SkTime_Unix.cpp',
'../src/ports/SkTime_win.cpp', '../src/ports/SkTime_win.cpp',
'../src/ports/SkXMLParser_empty.cpp', '../src/ports/SkXMLParser_empty.cpp',
@ -140,12 +142,14 @@
'sources!': [ # these are used everywhere but windows 'sources!': [ # these are used everywhere but windows
'../src/ports/SkDebug_stdio.cpp', '../src/ports/SkDebug_stdio.cpp',
'../src/ports/SkTime_Unix.cpp', '../src/ports/SkTime_Unix.cpp',
'../src/ports/SkOSFile_posix.cpp',
], ],
}, { # else !win }, { # else !win
'sources!': [ 'sources!': [
'../src/ports/SkDebug_win.cpp', '../src/ports/SkDebug_win.cpp',
'../src/ports/SkFontHost_win.cpp', '../src/ports/SkFontHost_win.cpp',
'../src/ports/SkFontHost_win_dw.cpp', '../src/ports/SkFontHost_win_dw.cpp',
'../src/ports/SkOSFile_win.cpp',
'../src/ports/SkThread_win.cpp', '../src/ports/SkThread_win.cpp',
'../src/ports/SkTime_win.cpp', '../src/ports/SkTime_win.cpp',
], ],

View File

@ -48,9 +48,23 @@ char* sk_fgets(char* str, int size, SkFILE* f);
void sk_fflush(SkFILE*); void sk_fflush(SkFILE*);
int sk_fseek(SkFILE*, size_t, int); bool sk_fseek(SkFILE*, size_t);
bool sk_fmove(SkFILE*, long);
size_t sk_ftell(SkFILE*); size_t sk_ftell(SkFILE*);
/** Maps a file into memory. Returns the address and length on success, NULL otherwise.
* The mapping is read only.
*/
void* sk_fmmap(SkFILE* f, size_t* length);
/** Unmaps a file previously mapped by sk_fmmap.
* The length parameter must be the same as returned from sk_fmmap.
*/
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 true if something (file, directory, ???) exists at this path. // Returns true if something (file, directory, ???) exists at this path.
bool sk_exists(const char *path); bool sk_exists(const char *path);

View File

@ -13,6 +13,12 @@
class SkData; class SkData;
class SkStream;
class SkStreamRewindable;
class SkStreamSeekable;
class SkStreamAsset;
class SkStreamMemory;
/** /**
* SkStream -- abstraction for a source of bytes. Subclasses can be backed by * SkStream -- abstraction for a source of bytes. Subclasses can be backed by
* memory, or a file, or something else. * memory, or a file, or something else.
@ -30,50 +36,43 @@ class SkData;
* no more data (at EOF or hit an error). The caller should *not* call again * no more data (at EOF or hit an error). The caller should *not* call again
* in hopes of fulfilling more of the request. * in hopes of fulfilling more of the request.
*/ */
class SK_API SkStream : public SkRefCnt { class SK_API SkStream : public SkRefCnt { //TODO: remove SkRefCnt
public: public:
/** /**
* Attempts to open the specified file, and return a stream to it (using * Attempts to open the specified file, and return a stream to it (using
* mmap if available). On success, the caller must call unref() on the * mmap if available). On success, the caller must call unref() on the
* returned object. On failure, returns NULL. * returned object. On failure, returns NULL.
*/ */
static SkStream* NewFromFile(const char path[]); static SkStreamAsset* NewFromFile(const char path[]);
SK_DECLARE_INST_COUNT(SkStream) SK_DECLARE_INST_COUNT(SkStream)
/** Called to rewind to the beginning of the stream. If this cannot be /** Reads or skips size number of bytes.
done, return false. * If buffer == NULL, skip size bytes, return how many were skipped.
*/ * If buffer != NULL, copy size bytes into buffer, return how many were copied.
virtual bool rewind() = 0; * @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer
/** If this stream represents a file, this method returns the file's name. * @param size the number of bytes to skip or copy
If it does not, it returns NULL (the default behavior). * @return bytes read on success
*/ */
virtual const char* getFileName();
/** Called to read or skip size number of bytes.
If buffer is NULL and size > 0, skip that many bytes, returning how many were skipped.
If buffer is NULL and size == 0, return the total length of the stream.
If buffer != NULL, copy the requested number of bytes into buffer, returning how many were copied.
@param buffer If buffer is NULL, ignore and just skip size bytes, otherwise copy size bytes into buffer
@param size The number of bytes to skip or copy
@return bytes read on success
*/
virtual size_t read(void* buffer, size_t size) = 0; virtual size_t read(void* buffer, size_t size) = 0;
/** Return the total length of the stream. /** Skip size number of bytes.
*/ * @return the actual number bytes that could be skipped.
size_t getLength() { return this->read(NULL, 0); } */
size_t skip(size_t size) {
//return this->read(NULL, size);
//TODO: remove this old logic after updating existing implementations
return 0 == size ? 0 : this->read(NULL, size);
}
/** Skip the specified number of bytes, returning the actual number /** Returns true if there are no more bytes to be read.
of bytes that could be skipped. * In Progress: do not use until all implementations are updated.
*/ * TODO: after this is implemented everywhere, make pure virtual.
size_t skip(size_t bytes); */
virtual bool isAtEnd() const {
/** If the stream is backed by RAM, this method returns the starting SkASSERT(false);
address for the data. If not (i.e. it is backed by a file or other return true;
structure), this method returns NULL. }
The default implementation returns NULL.
*/
virtual const void* getMemoryBase();
int8_t readS8(); int8_t readS8();
int16_t readS16(); int16_t readS16();
@ -93,10 +92,100 @@ public:
*/ */
SkData* readData(); SkData* readData();
//SkStreamRewindable
/** Rewinds to the beginning of the stream. If this cannot be done, return false. */
virtual bool rewind() { return false; }
/** Duplicates this stream. If this cannot be done, returns NULL.
* The returned stream will be positioned at the beginning of its data.
*/
virtual SkStreamRewindable* duplicate() const { return NULL; }
//SkStreamSeekable
/** Returns true if this stream can report it's current position. */
virtual bool hasPosition() const { return false; }
/** Returns the current position in the stream. If this cannot be done, returns 0. */
virtual size_t getPosition() const { return 0; }
/** Seeks to an absolute position in the stream. If this cannot be done, returns false.
* If an attempt is made to seek past the end of the stream, the position will be set
* to the end of the stream.
*/
virtual bool seek(size_t position) { return false; }
/** Seeks to an relative offset in the stream. If this cannot be done, returns false.
* If an attempt is made to move to a position outside the stream, the position will be set
* to the closest point within the stream (beginning or end).
*/
virtual bool move(long offset) { return false; }
/** Duplicates this stream. If this cannot be done, returns NULL.
* The returned stream will be positioned the same as this stream.
*/
virtual SkStreamSeekable* fork() const { return NULL; }
//SkStreamAsset
/** Returns true if this stream can report it's total length. */
virtual bool hasLength() const { return false; }
/** Returns the total length of the stream. If this cannot be done, returns 0. */
virtual size_t getLength() const {
//return 0;
//TODO: remove the following after everyone is updated.
return ((SkStream*)this)->read(NULL, 0);
}
//SkStreamMemory
/** Returns the starting address for the data. If this cannot be done, returns NULL. */
//TODO: replace with virtual const SkData* getData()
virtual const void* getMemoryBase() { return NULL; }
private: private:
typedef SkRefCnt INHERITED; typedef SkRefCnt INHERITED;
}; };
/** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */
class SK_API SkStreamRewindable : public SkStream {
public:
//TODO: remove the following after everyone is updated (ensures new behavior on new classes).
virtual bool isAtEnd() const SK_OVERRIDE = 0;
//TODO: remove the following after everyone is updated (ensures new behavior on new classes).
virtual size_t getLength() const SK_OVERRIDE { return 0; }
virtual bool rewind() SK_OVERRIDE = 0;
virtual SkStreamRewindable* duplicate() const SK_OVERRIDE = 0;
};
/** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */
class SK_API SkStreamSeekable : public SkStreamRewindable {
public:
virtual SkStreamSeekable* duplicate() const SK_OVERRIDE = 0;
virtual bool hasPosition() const SK_OVERRIDE { return true; }
virtual size_t getPosition() const SK_OVERRIDE = 0;
virtual bool seek(size_t position) SK_OVERRIDE = 0;
virtual bool move(long offset) SK_OVERRIDE = 0;
virtual SkStreamSeekable* fork() const SK_OVERRIDE = 0;
};
/** SkStreamAsset is a SkStreamSeekable for which getLength is required. */
class SK_API SkStreamAsset : public SkStreamSeekable {
public:
virtual SkStreamAsset* duplicate() const SK_OVERRIDE = 0;
virtual SkStreamAsset* fork() const SK_OVERRIDE = 0;
virtual bool hasLength() const SK_OVERRIDE { return true; }
virtual size_t getLength() const SK_OVERRIDE = 0;
};
/** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */
class SK_API SkStreamMemory : public SkStreamAsset {
public:
virtual SkStreamMemory* duplicate() const SK_OVERRIDE = 0;
virtual SkStreamMemory* fork() const SK_OVERRIDE = 0;
virtual const void* getMemoryBase() SK_OVERRIDE = 0;
};
class SK_API SkWStream : SkNoncopyable { class SK_API SkWStream : SkNoncopyable {
public: public:
SK_DECLARE_INST_COUNT_ROOT(SkWStream) SK_DECLARE_INST_COUNT_ROOT(SkWStream)
@ -147,81 +236,76 @@ public:
struct SkFILE; struct SkFILE;
/** A stream that reads from a FILE*, which is opened in the constructor and /** A stream that wraps a C FILE* file stream. */
closed in the destructor class SK_API SkFILEStream : public SkStreamAsset {
*/
class SK_API SkFILEStream : public SkStream {
public: public:
SK_DECLARE_INST_COUNT(SkFILEStream) SK_DECLARE_INST_COUNT(SkFILEStream)
/** Initialize the stream by calling fopen on the specified path. Will be /** Initialize the stream by calling sk_fopen on the specified path.
closed in the destructor. * This internal stream will be closed in the destructor.
*/ */
explicit SkFILEStream(const char path[] = NULL); explicit SkFILEStream(const char path[] = NULL);
enum Ownership {
kCallerPasses_Ownership,
kCallerRetains_Ownership
};
/** Initialize the stream with an existing C file stream.
* While this stream exists, it assumes exclusive access to the C file stream.
* The C file stream will be closed in the destructor unless the caller specifies
* kCallerRetains_Ownership.
*/
explicit SkFILEStream(FILE* file, Ownership ownership = kCallerPasses_Ownership);
virtual ~SkFILEStream(); virtual ~SkFILEStream();
/** Returns true if the current path could be opened. /** Returns true if the current path could be opened. */
*/
bool isValid() const { return fFILE != NULL; } bool isValid() const { return fFILE != NULL; }
/** Close the current file, and open a new file with the specified
path. If path is NULL, just close the current file. /** Close the current file, and open a new file with the specified path.
*/ * If path is NULL, just close the current file.
*/
void setPath(const char path[]); void setPath(const char path[]);
virtual bool rewind() SK_OVERRIDE;
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
virtual const char* getFileName() SK_OVERRIDE; virtual bool isAtEnd() const SK_OVERRIDE;
virtual bool rewind() SK_OVERRIDE;
virtual SkStreamAsset* duplicate() const SK_OVERRIDE;
virtual size_t getPosition() const SK_OVERRIDE;
virtual bool seek(size_t position) SK_OVERRIDE;
virtual bool move(long offset) SK_OVERRIDE;
virtual SkStreamAsset* fork() const SK_OVERRIDE;
virtual size_t getLength() const SK_OVERRIDE;
const void* getMemoryBase() SK_OVERRIDE;
private: private:
SkFILE* fFILE; SkFILE* fFILE;
SkString fName; SkString fName;
Ownership fOwnership;
// fData is lazilly initialized when needed.
mutable SkAutoTUnref<SkData> fData;
typedef SkStream INHERITED; typedef SkStreamAsset INHERITED;
}; };
/** A stream that reads from a file descriptor class SK_API SkMemoryStream : public SkStreamMemory {
*/
class SK_API SkFDStream : public SkStream {
public:
SK_DECLARE_INST_COUNT(SkFDStream)
/** Initialize the stream with a dup() of the specified file descriptor.
If closeWhenDone is true, then the descriptor will be closed in the
destructor.
*/
SkFDStream(int fileDesc, bool closeWhenDone);
virtual ~SkFDStream();
/** Returns true if the current path could be opened.
*/
bool isValid() const { return fFD >= 0; }
virtual bool rewind() SK_OVERRIDE;
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
virtual const char* getFileName() SK_OVERRIDE { return NULL; }
private:
int fFD;
bool fCloseWhenDone;
typedef SkStream INHERITED;
};
class SK_API SkMemoryStream : public SkStream {
public: public:
SK_DECLARE_INST_COUNT(SkMemoryStream) SK_DECLARE_INST_COUNT(SkMemoryStream)
SkMemoryStream(); SkMemoryStream();
/** We allocate (and free) the memory. Write to it via getMemoryBase()
*/ /** We allocate (and free) the memory. Write to it via getMemoryBase() */
SkMemoryStream(size_t length); SkMemoryStream(size_t length);
/** if copyData is true, the stream makes a private copy of the data
*/ /** If copyData is true, the stream makes a private copy of the data. */
SkMemoryStream(const void* data, size_t length, bool copyData = false); SkMemoryStream(const void* data, size_t length, bool copyData = false);
/** /** Use the specified data as the memory for this stream.
* Use the specified data as the memory for this stream. The stream will * The stream will call ref() on the data (assuming it is not NULL).
* call ref() on the data (assuming it is not null).
*/ */
SkMemoryStream(SkData*); SkMemoryStream(SkData*);
@ -239,81 +323,42 @@ public:
*/ */
void setMemoryOwned(const void* data, size_t length); void setMemoryOwned(const void* data, size_t length);
/** /** Return the stream's data in a SkData.
* Return the stream's data in a SkData. The caller must call unref() when * The caller must call unref() when it is finished using the data.
* it is finished using the data.
*/ */
SkData* copyToData() const; SkData* copyToData() const;
/** /**
* Use the specified data as the memory for this stream. The stream will * Use the specified data as the memory for this stream.
* call ref() on the data (assuming it is not null). The function returns * The stream will call ref() on the data (assuming it is not NULL).
* the data parameter as a convenience. * The function returns the data parameter as a convenience.
*/ */
SkData* setData(SkData*); SkData* setData(SkData*);
void skipToAlign4(); void skipToAlign4();
virtual bool rewind() SK_OVERRIDE;
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
virtual const void* getMemoryBase() SK_OVERRIDE;
const void* getAtPos(); const void* getAtPos();
size_t seek(size_t offset);
size_t peek() const { return fOffset; } size_t peek() const { return fOffset; }
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
virtual bool isAtEnd() const SK_OVERRIDE;
virtual bool rewind() SK_OVERRIDE;
virtual SkMemoryStream* duplicate() const SK_OVERRIDE;
virtual size_t getPosition() const SK_OVERRIDE;
virtual bool seek(size_t position) SK_OVERRIDE;
virtual bool move(long offset) SK_OVERRIDE;
virtual SkMemoryStream* fork() const SK_OVERRIDE;
virtual size_t getLength() const SK_OVERRIDE;
virtual const void* getMemoryBase() SK_OVERRIDE;
private: private:
SkData* fData; SkData* fData;
size_t fOffset; size_t fOffset;
typedef SkStream INHERITED; typedef SkStreamMemory INHERITED;
};
/** \class SkBufferStream
This is a wrapper class that adds buffering to another stream.
The caller can provide the buffer, or ask SkBufferStream to allocated/free
it automatically.
*/
class SK_API SkBufferStream : public SkStream {
public:
SK_DECLARE_INST_COUNT(SkBufferStream)
/** Provide the stream to be buffered (proxy), and the size of the buffer that
should be used. This will be allocated and freed automatically. If bufferSize is 0,
a default buffer size will be used.
The proxy stream is referenced, and will be unreferenced in when the
bufferstream is destroyed.
*/
SkBufferStream(SkStream* proxy, size_t bufferSize = 0);
/** Provide the stream to be buffered (proxy), and a buffer and size to be used.
This buffer is owned by the caller, and must be at least bufferSize bytes big.
Passing NULL for buffer will cause the buffer to be allocated/freed automatically.
If buffer is not NULL, it is an error for bufferSize to be 0.
The proxy stream is referenced, and will be unreferenced in when the
bufferstream is destroyed.
*/
SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize);
virtual ~SkBufferStream();
virtual bool rewind() SK_OVERRIDE;
virtual const char* getFileName() SK_OVERRIDE;
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
virtual const void* getMemoryBase() SK_OVERRIDE;
private:
enum {
kDefaultBufferSize = 128
};
// illegal
SkBufferStream(const SkBufferStream&);
SkBufferStream& operator=(const SkBufferStream&);
SkStream* fProxy;
char* fBuffer;
size_t fOrigBufferSize, fBufferSize, fBufferOffset;
bool fWeOwnTheBuffer;
void init(void*, size_t);
typedef SkStream INHERITED;
}; };
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -9,16 +9,6 @@
#include "SkFlattenableBuffers.h" #include "SkFlattenableBuffers.h"
#include "SkOSFile.h" #include "SkOSFile.h"
#if SK_MMAP_SUPPORT
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#else
#include <io.h>
#endif
SK_DEFINE_INST_COUNT(SkData) SK_DEFINE_INST_COUNT(SkData)
SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) { SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
@ -92,96 +82,27 @@ SkData* SkData::NewWithProc(const void* data, size_t length,
return new SkData(data, length, proc, context); return new SkData(data, length, proc, context);
} }
// assumes fPtr was allocated with sk_fmmap
static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
sk_fmunmap(addr, length);
}
SkData* SkData::NewFromFILE(SkFILE* f) {
size_t size;
void* addr = sk_fmmap(f, &size);
if (NULL == addr) {
return NULL;
}
return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
}
// assumes context is a SkData // assumes context is a SkData
static void sk_dataref_releaseproc(const void*, size_t, void* context) { static void sk_dataref_releaseproc(const void*, size_t, void* context) {
SkData* src = reinterpret_cast<SkData*>(context); SkData* src = reinterpret_cast<SkData*>(context);
src->unref(); src->unref();
} }
#if SK_MMAP_SUPPORT
static void sk_munmap_releaseproc(const void* addr, size_t length, void*) {
munmap(const_cast<void*>(addr), length);
}
SkData* SkData::NewFromFILE(SkFILE* f) {
size_t size = sk_fgetsize(f);
if (0 == size) {
return NULL;
}
int fd = fileno((FILE*)f);
if (fd < 0) {
return NULL;
}
void* addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (MAP_FAILED == addr) {
return NULL;
}
return SkData::NewWithProc(addr, size, sk_munmap_releaseproc, NULL);
}
#elif defined(SK_BUILD_FOR_WIN32)
template <typename HandleType, HandleType InvalidValue, BOOL (WINAPI * Close)(HandleType)>
class SkAutoTHandle : SkNoncopyable {
public:
SkAutoTHandle(HandleType handle) : fHandle(handle) { }
~SkAutoTHandle() { Close(fHandle); }
operator HandleType() { return fHandle; }
bool isValid() { return InvalidValue != fHandle; }
private:
HandleType fHandle;
};
typedef SkAutoTHandle<HANDLE, INVALID_HANDLE_VALUE, CloseHandle> SkAutoWinFile;
typedef SkAutoTHandle<HANDLE, NULL, CloseHandle> SkAutoWinMMap;
static void sk_munmap_releaseproc(const void* addr, size_t, void*) {
UnmapViewOfFile(addr);
}
SkData* SkData::NewFromFILE(SkFILE* f) {
size_t size = sk_fgetsize(f);
if (0 == size) {
return NULL;
}
int fileno = _fileno((FILE*)f);
if (fileno < 0) {
return NULL;
}
HANDLE file = (HANDLE)_get_osfhandle(fileno);
if (INVALID_HANDLE_VALUE == file) {
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.
return NULL;
}
// Eventually call UnmapViewOfFile
void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
if (NULL == addr) {
//TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
return NULL;
}
return SkData::NewWithProc(addr, size, sk_munmap_releaseproc, NULL);
}
#else
SkData* SkData::NewFromFILE(SkFILE* f) {
return NULL;
}
#endif
SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) { SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
/* /*
We could, if we wanted/need to, just make a deep copy of src's data, We could, if we wanted/need to, just make a deep copy of src's data,

View File

@ -1,104 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkStream.h"
#ifdef SK_BUILD_FOR_WIN
// -1 means isValid() will return false
SkFDStream::SkFDStream(int, bool) : fFD(-1), fCloseWhenDone(false) {}
SkFDStream::~SkFDStream() {}
bool SkFDStream::rewind() { return false; }
size_t SkFDStream::read(void*, size_t) { return 0; }
#else
#include <unistd.h>
//#define TRACE_FDSTREAM
SkFDStream::SkFDStream(int fileDesc, bool closeWhenDone)
: fFD(fileDesc), fCloseWhenDone(closeWhenDone) {
}
SkFDStream::~SkFDStream() {
if (fFD >= 0 && fCloseWhenDone) {
::close(fFD);
}
}
bool SkFDStream::rewind() {
if (fFD >= 0) {
off_t value = ::lseek(fFD, 0, SEEK_SET);
#ifdef TRACE_FDSTREAM
if (value) {
SkDebugf("xxxxxxxxxxxxxx rewind failed %d\n", value);
}
#endif
return value == 0;
}
return false;
}
size_t SkFDStream::read(void* buffer, size_t size) {
if (fFD >= 0) {
if (buffer == NULL && size == 0) { // request total size
off_t curr = ::lseek(fFD, 0, SEEK_CUR);
if (curr < 0) {
#ifdef TRACE_FDSTREAM
SkDebugf("xxxxxxxxxxxxx lseek failed 0 CURR\n");
#endif
return 0; // error
}
off_t size = ::lseek(fFD, 0, SEEK_END);
if (size < 0) {
#ifdef TRACE_FDSTREAM
SkDebugf("xxxxxxxxxxxxx lseek failed 0 END\n");
#endif
size = 0; // error
}
if (::lseek(fFD, curr, SEEK_SET) != curr) {
// can't restore, error
#ifdef TRACE_FDSTREAM
SkDebugf("xxxxxxxxxxxxx lseek failed %d SET\n", curr);
#endif
return 0;
}
return (size_t) size;
} else if (NULL == buffer) { // skip
off_t oldCurr = ::lseek(fFD, 0, SEEK_CUR);
if (oldCurr < 0) {
#ifdef TRACE_FDSTREAM
SkDebugf("xxxxxxxxxxxxx lseek1 failed %d CUR\n", oldCurr);
#endif
return 0; // error;
}
off_t newCurr = ::lseek(fFD, size, SEEK_CUR);
if (newCurr < 0) {
#ifdef TRACE_FDSTREAM
SkDebugf("xxxxxxxxxxxxx lseek2 failed %d CUR\n", newCurr);
#endif
return 0; // error;
}
// return the actual amount we skipped
return (size_t) (newCurr - oldCurr);
} else { // read
ssize_t actual = ::read(fFD, buffer, size);
// our API can't return an error, so we return 0
if (actual < 0) {
#ifdef TRACE_FDSTREAM
SkDebugf("xxxxxxxxxxxxx read failed %d actual %d\n", size, actual);
#endif
actual = 0;
}
return actual;
}
}
return 0;
}
#endif

View File

@ -16,9 +16,7 @@
SK_DEFINE_INST_COUNT(SkStream) SK_DEFINE_INST_COUNT(SkStream)
SK_DEFINE_INST_COUNT(SkWStream) SK_DEFINE_INST_COUNT(SkWStream)
SK_DEFINE_INST_COUNT(SkFILEStream) SK_DEFINE_INST_COUNT(SkFILEStream)
SK_DEFINE_INST_COUNT(SkFDStream)
SK_DEFINE_INST_COUNT(SkMemoryStream) SK_DEFINE_INST_COUNT(SkMemoryStream)
SK_DEFINE_INST_COUNT(SkBufferStream)
SK_DEFINE_INST_COUNT(SkFILEWStream) SK_DEFINE_INST_COUNT(SkFILEWStream)
SK_DEFINE_INST_COUNT(SkMemoryWStream) SK_DEFINE_INST_COUNT(SkMemoryWStream)
SK_DEFINE_INST_COUNT(SkDynamicMemoryWStream) SK_DEFINE_INST_COUNT(SkDynamicMemoryWStream)
@ -26,26 +24,6 @@ SK_DEFINE_INST_COUNT(SkDebugWStream)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
const char* SkStream::getFileName()
{
// override in subclass if you represent a file
return NULL;
}
const void* SkStream::getMemoryBase()
{
// override in subclass if you represent a memory block
return NULL;
}
size_t SkStream::skip(size_t size)
{
/* Check for size == 0, and just return 0. If we passed that
to read(), it would interpret it as a request for the entire
size of the stream.
*/
return size ? this->read(NULL, size) : 0;
}
int8_t SkStream::readS8() { int8_t SkStream::readS8() {
int8_t value; int8_t value;
@ -221,12 +199,17 @@ bool SkWStream::writeData(const SkData* data) {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
SkFILEStream::SkFILEStream(const char file[]) : fName(file) { SkFILEStream::SkFILEStream(const char file[]) : fName(file), fOwnership(kCallerPasses_Ownership) {
fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : NULL; fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : NULL;
} }
SkFILEStream::SkFILEStream(FILE* file, Ownership ownership)
: fFILE((SkFILE*)file)
, fOwnership(ownership) {
}
SkFILEStream::~SkFILEStream() { SkFILEStream::~SkFILEStream() {
if (fFILE) { if (fFILE && fOwnership != kCallerRetains_Ownership) {
sk_fclose(fFILE); sk_fclose(fFILE);
} }
} }
@ -242,8 +225,15 @@ void SkFILEStream::setPath(const char path[]) {
} }
} }
const char* SkFILEStream::getFileName() { size_t SkFILEStream::read(void* buffer, size_t size) {
return fName.c_str(); if (fFILE) {
return sk_fread(buffer, size, fFILE);
}
return 0;
}
bool SkFILEStream::isAtEnd() const {
return sk_feof(fFILE);
} }
bool SkFILEStream::rewind() { bool SkFILEStream::rewind() {
@ -258,15 +248,56 @@ bool SkFILEStream::rewind() {
return false; return false;
} }
size_t SkFILEStream::read(void* buffer, size_t size) { SkStreamAsset* SkFILEStream::duplicate() const {
if (fFILE) { if (NULL == fFILE) {
if (buffer == NULL && size == 0) { // special signature, they want the total size return new SkMemoryStream();
return sk_fgetsize(fFILE); }
} else {
return sk_fread(buffer, size, fFILE); if (NULL != fData.get()) {
return new SkMemoryStream(fData);
}
if (!fName.isEmpty()) {
SkAutoTUnref<SkFILEStream> that(new SkFILEStream(fName.c_str()));
if (sk_fidentical(that->fFILE, this->fFILE)) {
return that.detach();
} }
} }
return 0;
fData.reset(SkData::NewFromFILE(fFILE));
if (NULL == fData.get()) {
return NULL;
}
return new SkMemoryStream(fData);
}
size_t SkFILEStream::getPosition() const {
return sk_ftell(fFILE);
}
bool SkFILEStream::seek(size_t position) {
return sk_fseek(fFILE, position);
}
bool SkFILEStream::move(long offset) {
return sk_fmove(fFILE, offset);
}
SkStreamAsset* SkFILEStream::fork() const {
SkAutoTUnref<SkStreamAsset> that(this->duplicate());
that->seek(this->getPosition());
return that.detach();
}
size_t SkFILEStream::getLength() const {
return sk_fgetsize(fFILE);
}
const void* SkFILEStream::getMemoryBase() {
if (NULL == fData.get()) {
return NULL;
}
return fData->data();
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -341,22 +372,9 @@ void SkMemoryStream::skipToAlign4() {
fOffset += -(int)fOffset & 0x03; fOffset += -(int)fOffset & 0x03;
} }
bool SkMemoryStream::rewind() {
fOffset = 0;
return true;
}
size_t SkMemoryStream::read(void* buffer, size_t size) { size_t SkMemoryStream::read(void* buffer, size_t size) {
size_t dataSize = fData->size(); size_t dataSize = fData->size();
if (buffer == NULL && size == 0) // special signature, they want the total size
return dataSize;
// if buffer is NULL, seek ahead by size
if (size == 0) {
return 0;
}
if (size > dataSize - fOffset) { if (size > dataSize - fOffset) {
size = dataSize - fOffset; size = dataSize - fOffset;
} }
@ -367,6 +385,44 @@ size_t SkMemoryStream::read(void* buffer, size_t size) {
return size; return size;
} }
bool SkMemoryStream::isAtEnd() const {
return fOffset == fData->size();
}
bool SkMemoryStream::rewind() {
fOffset = 0;
return true;
}
SkMemoryStream* SkMemoryStream::duplicate() const {
return SkNEW_ARGS(SkMemoryStream, (fData));
}
size_t SkMemoryStream::getPosition() const {
return fOffset;
}
bool SkMemoryStream::seek(size_t position) {
fOffset = position > fData->size()
? fData->size()
: position;
return true;
}
bool SkMemoryStream::move(long offset) {
return this->seek(fOffset + offset);
}
SkMemoryStream* SkMemoryStream::fork() const {
SkAutoTUnref<SkMemoryStream> that(this->duplicate());
that->seek(fOffset);
return that.detach();
}
size_t SkMemoryStream::getLength() const {
return fData->size();
}
const void* SkMemoryStream::getMemoryBase() { const void* SkMemoryStream::getMemoryBase() {
return fData->data(); return fData->data();
} }
@ -375,165 +431,6 @@ const void* SkMemoryStream::getAtPos() {
return fData->bytes() + fOffset; return fData->bytes() + fOffset;
} }
size_t SkMemoryStream::seek(size_t offset) {
if (offset > fData->size()) {
offset = fData->size();
}
fOffset = offset;
return offset;
}
///////////////////////////////////////////////////////////////////////////////
SkBufferStream::SkBufferStream(SkStream* proxy, size_t bufferSize)
: fProxy(proxy)
{
SkASSERT(proxy != NULL);
proxy->ref();
this->init(NULL, bufferSize);
}
SkBufferStream::SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize)
: fProxy(proxy)
{
SkASSERT(proxy != NULL);
SkASSERT(buffer == NULL || bufferSize != 0); // init(addr, 0) makes no sense, we must know how big their buffer is
proxy->ref();
this->init(buffer, bufferSize);
}
void SkBufferStream::init(void* buffer, size_t bufferSize)
{
if (bufferSize == 0)
bufferSize = kDefaultBufferSize;
fOrigBufferSize = bufferSize;
fBufferSize = bufferSize;
fBufferOffset = bufferSize; // to trigger a reload on the first read()
if (buffer == NULL)
{
fBuffer = (char*)sk_malloc_throw(fBufferSize);
fWeOwnTheBuffer = true;
}
else
{
fBuffer = (char*)buffer;
fWeOwnTheBuffer = false;
}
}
SkBufferStream::~SkBufferStream()
{
fProxy->unref();
if (fWeOwnTheBuffer)
sk_free(fBuffer);
}
bool SkBufferStream::rewind()
{
fBufferOffset = fBufferSize = fOrigBufferSize;
return fProxy->rewind();
}
const char* SkBufferStream::getFileName()
{
return fProxy->getFileName();
}
#ifdef SK_DEBUG
// #define SK_TRACE_BUFFERSTREAM
#endif
size_t SkBufferStream::read(void* buffer, size_t size) {
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf("Request %d", size);
#endif
if (buffer == NULL && size == 0) {
return fProxy->read(buffer, size); // requesting total size
}
if (0 == size) {
return 0;
}
// skip size bytes
if (NULL == buffer) {
size_t remaining = fBufferSize - fBufferOffset;
if (remaining >= size) {
fBufferOffset += size;
return size;
}
// if we get here, we are being asked to skip beyond our current buffer
// so reset our offset to force a read next time, and skip the diff
// in our proxy
fBufferOffset = fOrigBufferSize;
return remaining + fProxy->read(NULL, size - remaining);
}
size_t s = size;
size_t actuallyRead = 0;
// flush what we can from our fBuffer
if (fBufferOffset < fBufferSize)
{
if (s > fBufferSize - fBufferOffset)
s = fBufferSize - fBufferOffset;
memcpy(buffer, fBuffer + fBufferOffset, s);
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf(" flush %d", s);
#endif
size -= s;
fBufferOffset += s;
buffer = (char*)buffer + s;
actuallyRead = s;
}
// check if there is more to read
if (size)
{
SkASSERT(fBufferOffset >= fBufferSize); // need to refill our fBuffer
if (size < fBufferSize) // lets try to read more than the request
{
s = fProxy->read(fBuffer, fBufferSize);
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf(" read %d into fBuffer", s);
#endif
if (size > s) // they asked for too much
size = s;
if (size)
{
memcpy(buffer, fBuffer, size);
actuallyRead += size;
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf(" memcpy %d into dst", size);
#endif
}
fBufferOffset = size;
fBufferSize = s; // record the (possibly smaller) size for the buffer
}
else // just do a direct read
{
actuallyRead += fProxy->read(buffer, size);
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf(" direct read %d", size);
#endif
}
}
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf("\n");
#endif
return actuallyRead;
}
const void* SkBufferStream::getMemoryBase()
{
return fProxy->getMemoryBase();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -800,7 +697,7 @@ static SkData* mmap_filename(const char path[]) {
return data; return data;
} }
SkStream* SkStream::NewFromFile(const char path[]) { SkStreamAsset* SkStream::NewFromFile(const char path[]) {
SkAutoTUnref<SkData> data(mmap_filename(path)); SkAutoTUnref<SkData> data(mmap_filename(path));
if (data.get()) { if (data.get()) {
return SkNEW_ARGS(SkMemoryStream, (data.get())); return SkNEW_ARGS(SkMemoryStream, (data.get()));

View File

@ -136,16 +136,30 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
SkStream* FontConfigTypeface::onOpenStream(int* ttcIndex) const { SkStream* FontConfigTypeface::onOpenStream(int* ttcIndex) const {
SkStream* stream = this->getLocalStream(); SkStream* stream = this->getLocalStream();
if (stream) { if (stream) {
// TODO: fix issue 1176.
// As of now open_stream will return a stream and unwind it, but the
// SkStream is not thread safe, and if two threads use the stream they
// may collide and print preview for example could still fail,
// or there could be some failures in rendering if this stream is used
// there.
stream->rewind();
stream->ref();
// should have been provided by CreateFromStream() // should have been provided by CreateFromStream()
*ttcIndex = 0; *ttcIndex = 0;
SkAutoTUnref<SkStream> dupStream(stream->duplicate());
if (dupStream) {
return dupStream.detach();
}
// TODO: update interface use, remove the following code in this block.
size_t length = stream->getLength();
const void* memory = stream->getMemoryBase();
if (NULL != memory) {
return new SkMemoryStream(memory, length, true);
}
SkAutoTMalloc<uint8_t> allocMemory(length);
stream->rewind();
if (length == stream->read(allocMemory.get(), length)) {
return new SkMemoryStream(allocMemory.detach(), length);
}
stream->rewind();
stream->ref();
} else { } else {
SkAutoTUnref<SkFontConfigInterface> fci(RefFCI()); SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
if (NULL == fci.get()) { if (NULL == fci.get()) {

View File

@ -0,0 +1,18 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkOSFile.h"
bool sk_fidentical(SkFILE* a, SkFILE* b) {
return false;
}
void sk_fmunmap(const void* addr, size_t length) { }
void* sk_fmmap(SkFILE* f, size_t* size) {
return NULL;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkOSFile.h"
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
typedef struct {
dev_t dev;
ino_t ino;
} SkFILEID;
static bool sk_ino(SkFILE* a, SkFILEID* id) {
int fd = fileno((FILE*)a);
if (fd < 0) {
return 0;
}
struct stat status;
if (0 != fstat(fd, &status)) {
return 0;
}
id->dev = status.st_dev;
id->ino = status.st_ino;
return true;
}
bool sk_fidentical(SkFILE* a, SkFILE* b) {
SkFILEID aID, bID;
return sk_ino(a, &aID) && sk_ino(b, &bID)
&& aID.ino == bID.ino
&& aID.dev == bID.dev;
}
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) {
return NULL;
}
int fd = fileno((FILE*)f);
if (fd < 0) {
return NULL;
}
void* addr = mmap(NULL, fileSize, PROT_READ, MAP_PRIVATE, fd, 0);
if (MAP_FAILED == addr) {
return NULL;
}
*size = fileSize;
return addr;
}

View File

@ -1,4 +1,3 @@
/* /*
* Copyright 2006 The Android Open Source Project * Copyright 2006 The Android Open Source Project
* *
@ -6,7 +5,6 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "SkOSFile.h" #include "SkOSFile.h"
#include <errno.h> #include <errno.h>
@ -21,74 +19,65 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
SkFILE* sk_fopen(const char path[], SkFILE_Flags flags) SkFILE* sk_fopen(const char path[], SkFILE_Flags flags) {
{
char perm[4]; char perm[4];
char* p = perm; char* p = perm;
if (flags & kRead_SkFILE_Flag) if (flags & kRead_SkFILE_Flag) {
*p++ = 'r'; *p++ = 'r';
if (flags & kWrite_SkFILE_Flag) }
if (flags & kWrite_SkFILE_Flag) {
*p++ = 'w'; *p++ = 'w';
}
*p++ = 'b'; *p++ = 'b';
*p = 0; *p = 0;
//TODO: on Windows fopen is just ASCII or the current code page, //TODO: on Windows fopen is just ASCII or the current code page,
//convert to utf16 and use _wfopen //convert to utf16 and use _wfopen
SkFILE* f = (SkFILE*)::fopen(path, perm); return (SkFILE*)::fopen(path, perm);
#if 0
if (NULL == f)
SkDebugf("sk_fopen failed for %s (%s), errno=%s\n", path, perm, strerror(errno));
#endif
return f;
} }
char* sk_fgets(char* str, int size, SkFILE* f) { char* sk_fgets(char* str, int size, SkFILE* f) {
return ::fgets(str, size, (FILE *)f); return ::fgets(str, size, (FILE *)f);
} }
int sk_feof(SkFILE *f) { int sk_feof(SkFILE *f) {
// no :: namespace qualifier because it breaks android // no :: namespace qualifier because it breaks android
return feof((FILE *)f); return feof((FILE *)f);
} }
size_t sk_fgetsize(SkFILE* f) size_t sk_fgetsize(SkFILE* f) {
{
SkASSERT(f); SkASSERT(f);
long curr = ::ftell((FILE*)f); // remember where we are long curr = ::ftell((FILE*)f); // remember where we are
if (curr < 0) { if (curr < 0) {
return 0; return 0;
} }
::fseek((FILE*)f, 0, SEEK_END); // go to the end
long size = ::ftell((FILE*)f); // record the size ::fseek((FILE*)f, 0, SEEK_END); // go to the end
long size = ::ftell((FILE*)f); // record the size
if (size < 0) { if (size < 0) {
size = 0; size = 0;
} }
::fseek((FILE*)f, curr, SEEK_SET); // go back to our prev loc
::fseek((FILE*)f, curr, SEEK_SET); // go back to our prev location
return size; return size;
} }
bool sk_frewind(SkFILE* f) bool sk_frewind(SkFILE* f) {
{
SkASSERT(f); SkASSERT(f);
::rewind((FILE*)f); ::rewind((FILE*)f);
// ::fseek((FILE*)f, 0, SEEK_SET);
return true; return true;
} }
size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f) size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f) {
{
SkASSERT(f); SkASSERT(f);
if (buffer == NULL) if (buffer == NULL) {
{
size_t curr = ::ftell((FILE*)f); size_t curr = ::ftell((FILE*)f);
if ((long)curr == -1) { if ((long)curr == -1) {
SkDEBUGF(("sk_fread: ftell(%p) returned -1 feof:%d ferror:%d\n", f, feof((FILE*)f), ferror((FILE*)f))); SkDEBUGF(("sk_fread: ftell(%p) returned -1 feof:%d ferror:%d\n", f, feof((FILE*)f), ferror((FILE*)f)));
return 0; return 0;
} }
// ::fseek((FILE*)f, (long)(curr + byteCount), SEEK_SET);
int err = ::fseek((FILE*)f, (long)byteCount, SEEK_CUR); int err = ::fseek((FILE*)f, (long)byteCount, SEEK_CUR);
if (err != 0) { if (err != 0) {
SkDEBUGF(("sk_fread: fseek(%d) tell:%d failed with feof:%d ferror:%d returned:%d\n", SkDEBUGF(("sk_fread: fseek(%d) tell:%d failed with feof:%d ferror:%d returned:%d\n",
@ -101,26 +90,40 @@ size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f)
return ::fread(buffer, 1, byteCount, (FILE*)f); return ::fread(buffer, 1, byteCount, (FILE*)f);
} }
size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE* f) size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE* f) {
{
SkASSERT(f); SkASSERT(f);
return ::fwrite(buffer, 1, byteCount, (FILE*)f); return ::fwrite(buffer, 1, byteCount, (FILE*)f);
} }
void sk_fflush(SkFILE* f) void sk_fflush(SkFILE* f) {
{
SkASSERT(f); SkASSERT(f);
::fflush((FILE*)f); ::fflush((FILE*)f);
} }
void sk_fclose(SkFILE* f) bool sk_fseek(SkFILE* f, size_t byteCount) {
{ int err = ::fseek((FILE*)f, (long)byteCount, SEEK_SET);
return err == 0;
}
bool sk_fmove(SkFILE* f, long byteCount) {
int err = ::fseek((FILE*)f, byteCount, SEEK_CUR);
return err == 0;
}
size_t sk_ftell(SkFILE* f) {
long curr = ::ftell((FILE*)f);
if (curr < 0) {
return 0;
}
return curr;
}
void sk_fclose(SkFILE* f) {
SkASSERT(f); SkASSERT(f);
::fclose((FILE*)f); ::fclose((FILE*)f);
} }
bool sk_exists(const char *path) bool sk_exists(const char *path) {
{
#ifdef _WIN32 #ifdef _WIN32
return (0 == _access(path, 0)); return (0 == _access(path, 0));
#else #else
@ -128,8 +131,7 @@ bool sk_exists(const char *path)
#endif #endif
} }
bool sk_isdir(const char *path) bool sk_isdir(const char *path) {
{
struct stat status; struct stat status;
if (0 != stat(path, &status)) { if (0 != stat(path, &status)) {
return false; return false;
@ -137,8 +139,7 @@ bool sk_isdir(const char *path)
return SkToBool(status.st_mode & S_IFDIR); return SkToBool(status.st_mode & S_IFDIR);
} }
bool sk_mkdir(const char* path) bool sk_mkdir(const char* path) {
{
if (sk_isdir(path)) { if (sk_isdir(path)) {
return true; return true;
} }

View File

@ -0,0 +1,99 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkOSFile.h"
#include <io.h>
#include <stdio.h>
#include <sys/stat.h>
typedef struct {
ULONGLONG fVolume;
ULONGLONG fLsbSize;
ULONGLONG fMsbSize;
} SkFILEID;
static bool sk_ino(SkFILE* f, SkFILEID* id) {
int fileno = _fileno((FILE*)f);
if (fileno < 0) {
return false;
}
HANDLE file = (HANDLE)_get_osfhandle(fileno);
if (INVALID_HANDLE_VALUE == file) {
return false;
}
//TODO: call GetFileInformationByHandleEx on Vista and later with FileIdInfo.
BY_HANDLE_FILE_INFORMATION info;
if (0 == GetFileInformationByHandle(file, &info)) {
return false;
}
id->fVolume = info.dwVolumeSerialNumber;
id->fLsbSize = info.nFileIndexLow + (((ULONGLONG)info.nFileIndexHigh) << 32);
id->fMsbSize = 0;
return true;
}
bool sk_fidentical(SkFILE* a, SkFILE* b) {
SkFILEID aID, bID;
return sk_ino(a, &aID) && sk_ino(b, &bID)
&& aID.fLsbSize == bID.fLsbSize
&& aID.fMsbSize == bID.fMsbSize
&& aID.fVolume == bID.fVolume;
}
template <typename HandleType, HandleType InvalidValue, BOOL (WINAPI * Close)(HandleType)>
class SkAutoTHandle : SkNoncopyable {
public:
SkAutoTHandle(HandleType handle) : fHandle(handle) { }
~SkAutoTHandle() { Close(fHandle); }
operator HandleType() { return fHandle; }
bool isValid() { return InvalidValue != fHandle; }
private:
HandleType fHandle;
};
typedef SkAutoTHandle<HANDLE, INVALID_HANDLE_VALUE, CloseHandle> SkAutoWinFile;
typedef SkAutoTHandle<HANDLE, NULL, CloseHandle> SkAutoWinMMap;
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;
}
HANDLE file = (HANDLE)_get_osfhandle(fileno);
if (INVALID_HANDLE_VALUE == file) {
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.
return NULL;
}
// Eventually call UnmapViewOfFile
void* addr = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
if (NULL == addr) {
//TODO: use SK_TRACEHR(GetLastError(), "Could not map view of file.") to report.
return NULL;
}
*length = fileSize;
return addr;
}

View File

@ -8,6 +8,7 @@
#include "SkTypes.h" #include "SkTypes.h"
#include "SkDWriteFontFileStream.h" #include "SkDWriteFontFileStream.h"
#include "SkHRESULT.h" #include "SkHRESULT.h"
#include "SkTScopedComPtr.h"
#include <dwrite.h> #include <dwrite.h>
#include <limits> #include <limits>
@ -16,11 +17,10 @@
// SkIDWriteFontFileStream // SkIDWriteFontFileStream
SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream) SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
: fFontFileStream(fontFileStream) : fFontFileStream(SkRefComPtr(fontFileStream))
, fPos(0) , fPos(0)
, fLockedMemory(NULL) , fLockedMemory(NULL)
, fFragmentLock(NULL) { , fFragmentLock(NULL) {
fontFileStream->AddRef();
} }
SkDWriteFontFileStream::~SkDWriteFontFileStream() { SkDWriteFontFileStream::~SkDWriteFontFileStream() {
@ -29,44 +29,19 @@ SkDWriteFontFileStream::~SkDWriteFontFileStream() {
} }
} }
const void* SkDWriteFontFileStream::getMemoryBase() {
if (fLockedMemory) {
return fLockedMemory;
}
UINT64 fileSize;
HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size");
HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock),
"Could not lock file fragment.");
return fLockedMemory;
}
bool SkDWriteFontFileStream::rewind() {
fPos = 0;
return true;
}
size_t SkDWriteFontFileStream::read(void* buffer, size_t size) { size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (NULL == buffer) { if (NULL == buffer) {
UINT64 realFileSize = 0; size_t fileSize = this->getLength();
hr = fFontFileStream->GetFileSize(&realFileSize);
if (realFileSize > (std::numeric_limits<size_t>::max)()) { if (fPos + size > fileSize) {
return 0; size_t skipped = fileSize - fPos;
} fPos = fileSize;
size_t fileSize = static_cast<size_t>(realFileSize); return skipped;
if (size == 0) {
return fileSize;
} else { } else {
if (fPos + size > fileSize) { fPos += size;
size_t skipped = fileSize - fPos; return size;
fPos = fileSize;
return skipped;
} else {
fPos += size;
return size;
}
} }
} }
@ -81,28 +56,78 @@ size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
} }
//The read may have failed because we asked for too much data. //The read may have failed because we asked for too much data.
size_t fileSize = this->getLength();
if (fPos + size <= fileSize) {
//This means we were within bounds, but failed for some other reason.
return 0;
}
size_t read = fileSize - fPos;
hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock);
if (SUCCEEDED(hr)) {
memcpy(buffer, start, read);
fFontFileStream->ReleaseFileFragment(fragmentLock);
fPos = fileSize;
return read;
}
return 0;
}
bool SkDWriteFontFileStream::isAtEnd() const {
return fPos == this->getLength();
}
bool SkDWriteFontFileStream::rewind() {
fPos = 0;
return true;
}
SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const {
return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get()));
}
size_t SkDWriteFontFileStream::getPosition() const {
return fPos;
}
bool SkDWriteFontFileStream::seek(size_t position) {
size_t length = this->getLength();
fPos = (position > length) ? length : position;
return true;
}
bool SkDWriteFontFileStream::move(long offset) {
return seek(fPos + offset);
}
SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const {
SkAutoTUnref<SkDWriteFontFileStream> that(this->duplicate());
that->seek(fPos);
return that.detach();
}
size_t SkDWriteFontFileStream::getLength() const {
HRESULT hr = S_OK;
UINT64 realFileSize = 0; UINT64 realFileSize = 0;
hr = fFontFileStream->GetFileSize(&realFileSize); hr = fFontFileStream->GetFileSize(&realFileSize);
if (realFileSize > (std::numeric_limits<size_t>::max)()) { if (realFileSize > (std::numeric_limits<size_t>::max)()) {
return 0; return 0;
} }
size_t fileSize = static_cast<size_t>(realFileSize); return static_cast<size_t>(realFileSize);
if (fPos + size > fileSize) {
size_t read = fileSize - fPos;
hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock);
if (SUCCEEDED(hr)) {
memcpy(buffer, start, read);
fFontFileStream->ReleaseFileFragment(fragmentLock);
fPos = fileSize;
return read;
}
return 0;
} else {
//This means we were within bounds, but failed for some other reason.
return 0;
}
} }
const void* SkDWriteFontFileStream::getMemoryBase() {
if (fLockedMemory) {
return fLockedMemory;
}
UINT64 fileSize;
HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size");
HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock),
"Could not lock file fragment.");
return fLockedMemory;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// SkIDWriteFontFileStreamWrapper // SkIDWriteFontFileStreamWrapper
@ -116,8 +141,7 @@ HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFile
} }
SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream) SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream)
: fRefCount(1), fStream(stream) { : fRefCount(1), fStream(SkRef(stream)) {
stream->ref();
} }
HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) { HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
@ -180,7 +204,7 @@ HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) { if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) {
return E_FAIL; return E_FAIL;
} }
SkAutoTDeleteArray<uint8_t> streamData(new uint8_t[static_cast<size_t>(fragmentSize)]); SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize));
if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) { if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
return E_FAIL; return E_FAIL;
} }
@ -192,10 +216,7 @@ HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
} }
void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) { void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
if (NULL == fragmentContext) { sk_free(fragmentContext);
return;
}
delete [] fragmentContext;
} }
HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) { HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {

View File

@ -19,13 +19,20 @@
* An SkStream backed by an IDWriteFontFileStream. * An SkStream backed by an IDWriteFontFileStream.
* This allows Skia code to read an IDWriteFontFileStream. * This allows Skia code to read an IDWriteFontFileStream.
*/ */
class SkDWriteFontFileStream : public SkStream { class SkDWriteFontFileStream : public SkStreamMemory {
public: public:
explicit SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream); explicit SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream);
virtual ~SkDWriteFontFileStream(); virtual ~SkDWriteFontFileStream();
virtual bool rewind() SK_OVERRIDE;
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
virtual bool isAtEnd() const SK_OVERRIDE;
virtual bool rewind() SK_OVERRIDE;
virtual SkDWriteFontFileStream* duplicate() const SK_OVERRIDE;
virtual size_t getPosition() const SK_OVERRIDE;
virtual bool seek(size_t position) SK_OVERRIDE;
virtual bool move(long offset) SK_OVERRIDE;
virtual SkDWriteFontFileStream* fork() const SK_OVERRIDE;
virtual size_t getLength() const SK_OVERRIDE;
virtual const void* getMemoryBase() SK_OVERRIDE; virtual const void* getMemoryBase() SK_OVERRIDE;
private: private:

View File

@ -7,6 +7,7 @@
*/ */
#include "Test.h" #include "Test.h"
#include "SkRandom.h" #include "SkRandom.h"
#include "SkOSFile.h"
#include "SkStream.h" #include "SkStream.h"
#include "SkData.h" #include "SkData.h"
@ -17,67 +18,6 @@
#define MAX_SIZE (256 * 1024) #define MAX_SIZE (256 * 1024)
static void random_fill(SkMWCRandom& rand, void* buffer, size_t size) {
char* p = (char*)buffer;
char* stop = p + size;
while (p < stop) {
*p++ = (char)(rand.nextU() >> 8);
}
}
static void test_buffer(skiatest::Reporter* reporter) {
SkMWCRandom rand;
SkAutoMalloc am(MAX_SIZE * 2);
char* storage = (char*)am.get();
char* storage2 = storage + MAX_SIZE;
random_fill(rand, storage, MAX_SIZE);
for (int sizeTimes = 0; sizeTimes < 100; sizeTimes++) {
int size = rand.nextU() % MAX_SIZE;
if (size == 0) {
size = MAX_SIZE;
}
for (int times = 0; times < 100; times++) {
int bufferSize = 1 + (rand.nextU() & 0xFFFF);
SkMemoryStream mstream(storage, size);
SkBufferStream bstream(&mstream, bufferSize);
int bytesRead = 0;
while (bytesRead < size) {
int s = 17 + (rand.nextU() & 0xFFFF);
int ss = bstream.read(storage2, s);
REPORTER_ASSERT(reporter, ss > 0 && ss <= s);
REPORTER_ASSERT(reporter, bytesRead + ss <= size);
REPORTER_ASSERT(reporter,
memcmp(storage + bytesRead, storage2, ss) == 0);
bytesRead += ss;
}
REPORTER_ASSERT(reporter, bytesRead == size);
}
}
}
static void TestRStream(skiatest::Reporter* reporter) {
static const char s[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char copy[sizeof(s)];
SkMWCRandom rand;
for (int i = 0; i < 65; i++) {
char* copyPtr = copy;
SkMemoryStream mem(s, sizeof(s));
SkBufferStream buff(&mem, i);
do {
copyPtr += buff.read(copyPtr, rand.nextU() & 15);
} while (copyPtr < copy + sizeof(s));
REPORTER_ASSERT(reporter, copyPtr == copy + sizeof(s));
REPORTER_ASSERT(reporter, memcmp(s, copy, sizeof(s)) == 0);
}
test_buffer(reporter);
}
static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream, static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
const void* src, size_t len, int repeat) { const void* src, size_t len, int repeat) {
SkAutoSMalloc<256> storage(len); SkAutoSMalloc<256> storage(len);
@ -118,16 +58,20 @@ static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
SkFILEStream stream(path.c_str()); SkFILEStream stream(path.c_str());
REPORTER_ASSERT(reporter, stream.isValid()); REPORTER_ASSERT(reporter, stream.isValid());
test_loop_stream(reporter, &stream, s, 26, 100); test_loop_stream(reporter, &stream, s, 26, 100);
SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate());
test_loop_stream(reporter, stream2.get(), s, 26, 100);
} }
#ifndef SK_BUILD_FOR_WIN
{ {
int fd = ::open(path.c_str(), O_RDONLY); FILE* file = ::fopen(path.c_str(), "rb");
SkFDStream stream(fd, true); SkFILEStream stream(file, SkFILEStream::kCallerPasses_Ownership);
REPORTER_ASSERT(reporter, stream.isValid()); REPORTER_ASSERT(reporter, stream.isValid());
test_loop_stream(reporter, &stream, s, 26, 100); test_loop_stream(reporter, &stream, s, 26, 100);
SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate());
test_loop_stream(reporter, stream2.get(), s, 26, 100);
} }
#endif
} }
static void TestWStream(skiatest::Reporter* reporter) { static void TestWStream(skiatest::Reporter* reporter) {
@ -142,7 +86,6 @@ static void TestWStream(skiatest::Reporter* reporter) {
dst[100*26] = '*'; dst[100*26] = '*';
ds.copyTo(dst); ds.copyTo(dst);
REPORTER_ASSERT(reporter, dst[100*26] == '*'); REPORTER_ASSERT(reporter, dst[100*26] == '*');
// char* p = dst;
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0); REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
} }
@ -210,7 +153,6 @@ static void TestNullData() {
} }
static void TestStreams(skiatest::Reporter* reporter) { static void TestStreams(skiatest::Reporter* reporter) {
TestRStream(reporter);
TestWStream(reporter); TestWStream(reporter);
TestPackedUInt(reporter); TestPackedUInt(reporter);
TestNullData(); TestNullData();