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:
parent
6320e8f393
commit
6cab1a4b6a
@ -78,7 +78,6 @@
|
||||
'<(skia_src_path)/core/SkEdge.h',
|
||||
'<(skia_src_path)/core/SkError.cpp',
|
||||
'<(skia_src_path)/core/SkErrorInternals.h',
|
||||
'<(skia_src_path)/core/SkFDStream.cpp',
|
||||
'<(skia_src_path)/core/SkFP.h',
|
||||
'<(skia_src_path)/core/SkFilterProc.cpp',
|
||||
'<(skia_src_path)/core/SkFilterProc.h',
|
||||
|
@ -31,7 +31,9 @@
|
||||
'../src/ports/SkThread_win.cpp',
|
||||
|
||||
'../src/ports/SkMemory_malloc.cpp',
|
||||
'../src/ports/SkOSFile_posix.cpp',
|
||||
'../src/ports/SkOSFile_stdio.cpp',
|
||||
'../src/ports/SkOSFile_win.cpp',
|
||||
'../src/ports/SkTime_Unix.cpp',
|
||||
'../src/ports/SkTime_win.cpp',
|
||||
'../src/ports/SkXMLParser_empty.cpp',
|
||||
@ -140,12 +142,14 @@
|
||||
'sources!': [ # these are used everywhere but windows
|
||||
'../src/ports/SkDebug_stdio.cpp',
|
||||
'../src/ports/SkTime_Unix.cpp',
|
||||
'../src/ports/SkOSFile_posix.cpp',
|
||||
],
|
||||
}, { # else !win
|
||||
'sources!': [
|
||||
'../src/ports/SkDebug_win.cpp',
|
||||
'../src/ports/SkFontHost_win.cpp',
|
||||
'../src/ports/SkFontHost_win_dw.cpp',
|
||||
'../src/ports/SkOSFile_win.cpp',
|
||||
'../src/ports/SkThread_win.cpp',
|
||||
'../src/ports/SkTime_win.cpp',
|
||||
],
|
||||
|
@ -48,9 +48,23 @@ char* sk_fgets(char* str, int size, SkFILE* f);
|
||||
|
||||
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*);
|
||||
|
||||
/** 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.
|
||||
bool sk_exists(const char *path);
|
||||
|
||||
|
@ -13,6 +13,12 @@
|
||||
|
||||
class SkData;
|
||||
|
||||
class SkStream;
|
||||
class SkStreamRewindable;
|
||||
class SkStreamSeekable;
|
||||
class SkStreamAsset;
|
||||
class SkStreamMemory;
|
||||
|
||||
/**
|
||||
* SkStream -- abstraction for a source of bytes. Subclasses can be backed by
|
||||
* 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
|
||||
* in hopes of fulfilling more of the request.
|
||||
*/
|
||||
class SK_API SkStream : public SkRefCnt {
|
||||
class SK_API SkStream : public SkRefCnt { //TODO: remove SkRefCnt
|
||||
public:
|
||||
/**
|
||||
* 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
|
||||
* returned object. On failure, returns NULL.
|
||||
*/
|
||||
static SkStream* NewFromFile(const char path[]);
|
||||
static SkStreamAsset* NewFromFile(const char path[]);
|
||||
|
||||
SK_DECLARE_INST_COUNT(SkStream)
|
||||
|
||||
/** Called to rewind to the beginning of the stream. If this cannot be
|
||||
done, return false.
|
||||
*/
|
||||
virtual bool rewind() = 0;
|
||||
/** If this stream represents a file, this method returns the file's name.
|
||||
If it does not, it returns NULL (the default behavior).
|
||||
*/
|
||||
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
|
||||
*/
|
||||
/** Reads or skips size number of bytes.
|
||||
* If buffer == NULL, skip size bytes, return how many were skipped.
|
||||
* If buffer != NULL, copy size bytes into buffer, return how many were copied.
|
||||
* @param buffer when NULL 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;
|
||||
|
||||
/** Return the total length of the stream.
|
||||
*/
|
||||
size_t getLength() { return this->read(NULL, 0); }
|
||||
/** Skip size number of bytes.
|
||||
* @return the actual number bytes that could be skipped.
|
||||
*/
|
||||
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
|
||||
of bytes that could be skipped.
|
||||
*/
|
||||
size_t skip(size_t bytes);
|
||||
|
||||
/** If the stream is backed by RAM, this method returns the starting
|
||||
address for the data. If not (i.e. it is backed by a file or other
|
||||
structure), this method returns NULL.
|
||||
The default implementation returns NULL.
|
||||
*/
|
||||
virtual const void* getMemoryBase();
|
||||
/** Returns true if there are no more bytes to be read.
|
||||
* In Progress: do not use until all implementations are updated.
|
||||
* TODO: after this is implemented everywhere, make pure virtual.
|
||||
*/
|
||||
virtual bool isAtEnd() const {
|
||||
SkASSERT(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
int8_t readS8();
|
||||
int16_t readS16();
|
||||
@ -93,10 +92,100 @@ public:
|
||||
*/
|
||||
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:
|
||||
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 {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT_ROOT(SkWStream)
|
||||
@ -147,81 +236,76 @@ public:
|
||||
|
||||
struct SkFILE;
|
||||
|
||||
/** A stream that reads from a FILE*, which is opened in the constructor and
|
||||
closed in the destructor
|
||||
*/
|
||||
class SK_API SkFILEStream : public SkStream {
|
||||
/** A stream that wraps a C FILE* file stream. */
|
||||
class SK_API SkFILEStream : public SkStreamAsset {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkFILEStream)
|
||||
|
||||
/** Initialize the stream by calling fopen on the specified path. Will be
|
||||
closed in the destructor.
|
||||
/** Initialize the stream by calling sk_fopen on the specified path.
|
||||
* This internal stream will be closed in the destructor.
|
||||
*/
|
||||
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();
|
||||
|
||||
/** Returns true if the current path could be opened.
|
||||
*/
|
||||
/** Returns true if the current path could be opened. */
|
||||
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[]);
|
||||
|
||||
virtual bool rewind() 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:
|
||||
SkFILE* fFILE;
|
||||
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 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 {
|
||||
class SK_API SkMemoryStream : public SkStreamMemory {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(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);
|
||||
/** 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);
|
||||
|
||||
/**
|
||||
* Use the specified data as the memory for this stream. The stream will
|
||||
* call ref() on the data (assuming it is not null).
|
||||
/** Use the specified data as the memory for this stream.
|
||||
* The stream will call ref() on the data (assuming it is not NULL).
|
||||
*/
|
||||
SkMemoryStream(SkData*);
|
||||
|
||||
@ -239,81 +323,42 @@ public:
|
||||
*/
|
||||
void setMemoryOwned(const void* data, size_t length);
|
||||
|
||||
/**
|
||||
* Return the stream's data in a SkData. The caller must call unref() when
|
||||
* it is finished using the data.
|
||||
/** Return the stream's data in a SkData.
|
||||
* The caller must call unref() when it is finished using the data.
|
||||
*/
|
||||
SkData* copyToData() const;
|
||||
|
||||
/**
|
||||
* Use the specified data as the memory for this stream. The stream will
|
||||
* call ref() on the data (assuming it is not null). The function returns
|
||||
* the data parameter as a convenience.
|
||||
* Use the specified data as the memory for this stream.
|
||||
* The stream will call ref() on the data (assuming it is not NULL).
|
||||
* The function returns the data parameter as a convenience.
|
||||
*/
|
||||
SkData* setData(SkData*);
|
||||
|
||||
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();
|
||||
size_t seek(size_t offset);
|
||||
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:
|
||||
SkData* fData;
|
||||
size_t fOffset;
|
||||
|
||||
typedef SkStream 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;
|
||||
typedef SkStreamMemory INHERITED;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -9,16 +9,6 @@
|
||||
#include "SkFlattenableBuffers.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)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
static void sk_dataref_releaseproc(const void*, size_t, void* context) {
|
||||
SkData* src = reinterpret_cast<SkData*>(context);
|
||||
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) {
|
||||
/*
|
||||
We could, if we wanted/need to, just make a deep copy of src's data,
|
||||
|
@ -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
|
@ -16,9 +16,7 @@
|
||||
SK_DEFINE_INST_COUNT(SkStream)
|
||||
SK_DEFINE_INST_COUNT(SkWStream)
|
||||
SK_DEFINE_INST_COUNT(SkFILEStream)
|
||||
SK_DEFINE_INST_COUNT(SkFDStream)
|
||||
SK_DEFINE_INST_COUNT(SkMemoryStream)
|
||||
SK_DEFINE_INST_COUNT(SkBufferStream)
|
||||
SK_DEFINE_INST_COUNT(SkFILEWStream)
|
||||
SK_DEFINE_INST_COUNT(SkMemoryWStream)
|
||||
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 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;
|
||||
}
|
||||
|
||||
SkFILEStream::SkFILEStream(FILE* file, Ownership ownership)
|
||||
: fFILE((SkFILE*)file)
|
||||
, fOwnership(ownership) {
|
||||
}
|
||||
|
||||
SkFILEStream::~SkFILEStream() {
|
||||
if (fFILE) {
|
||||
if (fFILE && fOwnership != kCallerRetains_Ownership) {
|
||||
sk_fclose(fFILE);
|
||||
}
|
||||
}
|
||||
@ -242,8 +225,15 @@ void SkFILEStream::setPath(const char path[]) {
|
||||
}
|
||||
}
|
||||
|
||||
const char* SkFILEStream::getFileName() {
|
||||
return fName.c_str();
|
||||
size_t SkFILEStream::read(void* buffer, size_t size) {
|
||||
if (fFILE) {
|
||||
return sk_fread(buffer, size, fFILE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SkFILEStream::isAtEnd() const {
|
||||
return sk_feof(fFILE);
|
||||
}
|
||||
|
||||
bool SkFILEStream::rewind() {
|
||||
@ -258,15 +248,56 @@ bool SkFILEStream::rewind() {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t SkFILEStream::read(void* buffer, size_t size) {
|
||||
if (fFILE) {
|
||||
if (buffer == NULL && size == 0) { // special signature, they want the total size
|
||||
return sk_fgetsize(fFILE);
|
||||
} else {
|
||||
return sk_fread(buffer, size, fFILE);
|
||||
SkStreamAsset* SkFILEStream::duplicate() const {
|
||||
if (NULL == fFILE) {
|
||||
return new SkMemoryStream();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool SkMemoryStream::rewind() {
|
||||
fOffset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t SkMemoryStream::read(void* buffer, size_t 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) {
|
||||
size = dataSize - fOffset;
|
||||
}
|
||||
@ -367,6 +385,44 @@ size_t SkMemoryStream::read(void* buffer, size_t 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() {
|
||||
return fData->data();
|
||||
}
|
||||
@ -375,165 +431,6 @@ const void* SkMemoryStream::getAtPos() {
|
||||
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;
|
||||
}
|
||||
|
||||
SkStream* SkStream::NewFromFile(const char path[]) {
|
||||
SkStreamAsset* SkStream::NewFromFile(const char path[]) {
|
||||
SkAutoTUnref<SkData> data(mmap_filename(path));
|
||||
if (data.get()) {
|
||||
return SkNEW_ARGS(SkMemoryStream, (data.get()));
|
||||
|
@ -136,16 +136,30 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
|
||||
SkStream* FontConfigTypeface::onOpenStream(int* ttcIndex) const {
|
||||
SkStream* stream = this->getLocalStream();
|
||||
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()
|
||||
*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 {
|
||||
SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
|
||||
if (NULL == fci.get()) {
|
||||
|
18
src/ports/SkOSFile_none.cpp
Normal file
18
src/ports/SkOSFile_none.cpp
Normal 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;
|
||||
}
|
63
src/ports/SkOSFile_posix.cpp
Normal file
63
src/ports/SkOSFile_posix.cpp
Normal 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;
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
@ -6,7 +5,6 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkOSFile.h"
|
||||
|
||||
#include <errno.h>
|
||||
@ -21,74 +19,65 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
SkFILE* sk_fopen(const char path[], SkFILE_Flags flags)
|
||||
{
|
||||
SkFILE* sk_fopen(const char path[], SkFILE_Flags flags) {
|
||||
char perm[4];
|
||||
char* p = perm;
|
||||
|
||||
if (flags & kRead_SkFILE_Flag)
|
||||
if (flags & kRead_SkFILE_Flag) {
|
||||
*p++ = 'r';
|
||||
if (flags & kWrite_SkFILE_Flag)
|
||||
}
|
||||
if (flags & kWrite_SkFILE_Flag) {
|
||||
*p++ = 'w';
|
||||
}
|
||||
*p++ = 'b';
|
||||
*p = 0;
|
||||
|
||||
//TODO: on Windows fopen is just ASCII or the current code page,
|
||||
//convert to utf16 and use _wfopen
|
||||
SkFILE* f = (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;
|
||||
return (SkFILE*)::fopen(path, perm);
|
||||
}
|
||||
|
||||
char* sk_fgets(char* str, int size, SkFILE* f) {
|
||||
return ::fgets(str, size, (FILE *)f);
|
||||
}
|
||||
|
||||
|
||||
int sk_feof(SkFILE *f) {
|
||||
// no :: namespace qualifier because it breaks android
|
||||
return feof((FILE *)f);
|
||||
}
|
||||
|
||||
size_t sk_fgetsize(SkFILE* f)
|
||||
{
|
||||
size_t sk_fgetsize(SkFILE* f) {
|
||||
SkASSERT(f);
|
||||
|
||||
long curr = ::ftell((FILE*)f); // remember where we are
|
||||
long curr = ::ftell((FILE*)f); // remember where we are
|
||||
if (curr < 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool sk_frewind(SkFILE* f)
|
||||
{
|
||||
bool sk_frewind(SkFILE* f) {
|
||||
SkASSERT(f);
|
||||
::rewind((FILE*)f);
|
||||
// ::fseek((FILE*)f, 0, SEEK_SET);
|
||||
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);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
if (buffer == NULL) {
|
||||
size_t curr = ::ftell((FILE*)f);
|
||||
if ((long)curr == -1) {
|
||||
SkDEBUGF(("sk_fread: ftell(%p) returned -1 feof:%d ferror:%d\n", f, feof((FILE*)f), ferror((FILE*)f)));
|
||||
return 0;
|
||||
}
|
||||
// ::fseek((FILE*)f, (long)(curr + byteCount), SEEK_SET);
|
||||
int err = ::fseek((FILE*)f, (long)byteCount, SEEK_CUR);
|
||||
if (err != 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
return ::fwrite(buffer, 1, byteCount, (FILE*)f);
|
||||
}
|
||||
|
||||
void sk_fflush(SkFILE* f)
|
||||
{
|
||||
void sk_fflush(SkFILE* f) {
|
||||
SkASSERT(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);
|
||||
::fclose((FILE*)f);
|
||||
}
|
||||
|
||||
bool sk_exists(const char *path)
|
||||
{
|
||||
bool sk_exists(const char *path) {
|
||||
#ifdef _WIN32
|
||||
return (0 == _access(path, 0));
|
||||
#else
|
||||
@ -128,8 +131,7 @@ bool sk_exists(const char *path)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool sk_isdir(const char *path)
|
||||
{
|
||||
bool sk_isdir(const char *path) {
|
||||
struct stat status;
|
||||
if (0 != stat(path, &status)) {
|
||||
return false;
|
||||
@ -137,8 +139,7 @@ bool sk_isdir(const char *path)
|
||||
return SkToBool(status.st_mode & S_IFDIR);
|
||||
}
|
||||
|
||||
bool sk_mkdir(const char* path)
|
||||
{
|
||||
bool sk_mkdir(const char* path) {
|
||||
if (sk_isdir(path)) {
|
||||
return true;
|
||||
}
|
||||
|
99
src/ports/SkOSFile_win.cpp
Normal file
99
src/ports/SkOSFile_win.cpp
Normal 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;
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
#include "SkTypes.h"
|
||||
#include "SkDWriteFontFileStream.h"
|
||||
#include "SkHRESULT.h"
|
||||
#include "SkTScopedComPtr.h"
|
||||
|
||||
#include <dwrite.h>
|
||||
#include <limits>
|
||||
@ -16,11 +17,10 @@
|
||||
// SkIDWriteFontFileStream
|
||||
|
||||
SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
|
||||
: fFontFileStream(fontFileStream)
|
||||
: fFontFileStream(SkRefComPtr(fontFileStream))
|
||||
, fPos(0)
|
||||
, fLockedMemory(NULL)
|
||||
, fFragmentLock(NULL) {
|
||||
fontFileStream->AddRef();
|
||||
}
|
||||
|
||||
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) {
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (NULL == buffer) {
|
||||
UINT64 realFileSize = 0;
|
||||
hr = fFontFileStream->GetFileSize(&realFileSize);
|
||||
if (realFileSize > (std::numeric_limits<size_t>::max)()) {
|
||||
return 0;
|
||||
}
|
||||
size_t fileSize = static_cast<size_t>(realFileSize);
|
||||
if (size == 0) {
|
||||
return fileSize;
|
||||
size_t fileSize = this->getLength();
|
||||
|
||||
if (fPos + size > fileSize) {
|
||||
size_t skipped = fileSize - fPos;
|
||||
fPos = fileSize;
|
||||
return skipped;
|
||||
} else {
|
||||
if (fPos + size > fileSize) {
|
||||
size_t skipped = fileSize - fPos;
|
||||
fPos = fileSize;
|
||||
return skipped;
|
||||
} else {
|
||||
fPos += size;
|
||||
return size;
|
||||
}
|
||||
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.
|
||||
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;
|
||||
hr = fFontFileStream->GetFileSize(&realFileSize);
|
||||
if (realFileSize > (std::numeric_limits<size_t>::max)()) {
|
||||
return 0;
|
||||
}
|
||||
size_t fileSize = 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;
|
||||
}
|
||||
return static_cast<size_t>(realFileSize);
|
||||
}
|
||||
|
||||
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
|
||||
@ -116,8 +141,7 @@ HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFile
|
||||
}
|
||||
|
||||
SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream)
|
||||
: fRefCount(1), fStream(stream) {
|
||||
stream->ref();
|
||||
: fRefCount(1), fStream(SkRef(stream)) {
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
return E_FAIL;
|
||||
}
|
||||
@ -192,10 +216,7 @@ HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
|
||||
if (NULL == fragmentContext) {
|
||||
return;
|
||||
}
|
||||
delete [] fragmentContext;
|
||||
sk_free(fragmentContext);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {
|
||||
|
@ -19,13 +19,20 @@
|
||||
* An SkStream backed by an IDWriteFontFileStream.
|
||||
* This allows Skia code to read an IDWriteFontFileStream.
|
||||
*/
|
||||
class SkDWriteFontFileStream : public SkStream {
|
||||
class SkDWriteFontFileStream : public SkStreamMemory {
|
||||
public:
|
||||
explicit SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream);
|
||||
virtual ~SkDWriteFontFileStream();
|
||||
|
||||
virtual bool rewind() 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;
|
||||
|
||||
private:
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
#include "Test.h"
|
||||
#include "SkRandom.h"
|
||||
#include "SkOSFile.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkData.h"
|
||||
|
||||
@ -17,67 +18,6 @@
|
||||
|
||||
#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,
|
||||
const void* src, size_t len, int repeat) {
|
||||
SkAutoSMalloc<256> storage(len);
|
||||
@ -118,16 +58,20 @@ static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
|
||||
SkFILEStream stream(path.c_str());
|
||||
REPORTER_ASSERT(reporter, stream.isValid());
|
||||
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);
|
||||
SkFDStream stream(fd, true);
|
||||
FILE* file = ::fopen(path.c_str(), "rb");
|
||||
SkFILEStream stream(file, SkFILEStream::kCallerPasses_Ownership);
|
||||
REPORTER_ASSERT(reporter, stream.isValid());
|
||||
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) {
|
||||
@ -142,7 +86,6 @@ static void TestWStream(skiatest::Reporter* reporter) {
|
||||
dst[100*26] = '*';
|
||||
ds.copyTo(dst);
|
||||
REPORTER_ASSERT(reporter, dst[100*26] == '*');
|
||||
// char* p = dst;
|
||||
for (i = 0; i < 100; i++) {
|
||||
REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
|
||||
}
|
||||
@ -210,7 +153,6 @@ static void TestNullData() {
|
||||
}
|
||||
|
||||
static void TestStreams(skiatest::Reporter* reporter) {
|
||||
TestRStream(reporter);
|
||||
TestWStream(reporter);
|
||||
TestPackedUInt(reporter);
|
||||
TestNullData();
|
||||
|
Loading…
Reference in New Issue
Block a user