123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- // Copyright 2012 Google Inc. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License"); you
- // may not use this file except in compliance with the License. You
- // may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- // implied. See the License for the specific language governing
- // permissions and limitations under the License.
- #ifndef WEBGL_LOADER_STREAM_H_
- #define WEBGL_LOADER_STREAM_H_
- #include <stdio.h>
- #include <string>
- #include <vector>
- #include "base.h"
- namespace webgl_loader {
- // An abstract interface to allow appending bytes to various streams.
- class ByteSinkInterface {
- public:
- virtual void Put(char c) = 0;
- virtual size_t PutN(const char* data, size_t len) = 0;
- virtual ~ByteSinkInterface() { }
- protected:
- ByteSinkInterface() { }
- private:
- // Disallow copy and assignment.
- ByteSinkInterface(const ByteSinkInterface&);
- void operator=(const ByteSinkInterface&);
- };
- // None of the concrete implementations actually own the backing data.
- // They should be safe to copy.
- class NullSink : public ByteSinkInterface {
- public:
- NullSink() { }
- virtual void Put(char) { }
-
- virtual size_t PutN(const char*, size_t len) { return len; }
- };
- class FileSink : public ByteSinkInterface {
- public:
- // |fp| is unowned and must not be NULL.
- explicit FileSink(FILE* fp)
- : fp_(fp) {
- }
- virtual void Put(char c) {
- PutChar(c, fp_);
- }
- virtual size_t PutN(const char* data, size_t len) {
- return fwrite(data, 1, len, fp_);
- }
- private:
- FILE *fp_; // unowned.
- };
- class VectorSink : public ByteSinkInterface {
- public:
- // |vec| is unowned and must not be NULL.
- explicit VectorSink(std::vector<char>* vec)
- : vec_(vec) {
- }
-
- virtual void Put(char c) {
- vec_->push_back(c);
- }
- virtual size_t PutN(const char* data, size_t len) {
- vec_->insert(vec_->end(), data, data + len);
- return len;
- }
- private:
- std::vector<char>* vec_; // unowned.
- };
- class StringSink : public ByteSinkInterface {
- public:
- // |str| is unowned and must not be NULL.
- explicit StringSink(std::string* str)
- : str_(str) {
- DCHECK(str != NULL);
- }
- virtual void Put(char c) {
- str_->push_back(c);
- }
- virtual size_t PutN(const char* data, size_t len) {
- str_->append(data, len);
- return len;
- }
- private:
- std::string* str_; // unowned.
- };
- class ByteHistogramSink : public ByteSinkInterface {
- public:
- // |sink| in unowned and must not be NULL.
- explicit ByteHistogramSink(ByteSinkInterface* sink)
- : sink_(sink) {
- memset(histo_, 0, sizeof(histo_));
- }
- virtual void Put(char c) {
- histo_[static_cast<uint8>(c)]++;
- sink_->Put(c);
- }
- virtual size_t PutN(const char* data, size_t len) {
- const char* const end = data + len;
- for (const char* iter = data; iter != end; ++iter) {
- histo_[static_cast<uint8>(*iter)]++;
- }
- return sink_->PutN(data, len);
- }
- const size_t* histo() const {
- return histo_;
- }
- private:
- size_t histo_[256];
- ByteSinkInterface* sink_; // unowned.
- };
- // TODO: does it make sense to have a global enum? How should
- // new BufferedInput implementations define new error codes?
- enum ErrorCode {
- kNoError = 0,
- kEndOfFile = 1,
- kFileError = 2, // TODO: translate errno.
- };
- // Adapted from ryg's BufferedStream abstraction:
- // http://fgiesen.wordpress.com/2011/11/21/buffer-centric-io/
- class BufferedInput {
- public:
- typedef ErrorCode (*Refiller)(BufferedInput*);
- BufferedInput(Refiller refiller = RefillZeroes)
- : cursor(NULL),
- begin_(NULL),
- end_(NULL),
- refiller_(refiller),
- error_(kNoError) {
- }
- // InitFromMemory.
- BufferedInput(const char* data, size_t length)
- : cursor(data),
- begin_(data),
- end_(data + length),
- refiller_(RefillEndOfFile),
- error_(kNoError) {
- }
- const char* begin() const {
- return begin_;
- }
- const char* end() const {
- return end_;
- }
- const char* cursor;
- ErrorCode error() const {
- DCHECK(begin() <= cursor);
- DCHECK(cursor <= end());
- return error_;
- }
- ErrorCode Refill() {
- DCHECK(begin() <= cursor);
- DCHECK(cursor <= end());
- if (cursor == end()) {
- error_ = refiller_(this);
- }
- return error_;
- }
- protected:
- static ErrorCode RefillZeroes(BufferedInput* bi) {
- static const char kZeroes[64] = { 0 };
- bi->cursor = kZeroes;
- bi->begin_ = kZeroes;
- bi->end_ = kZeroes + sizeof(kZeroes);
- return bi->error_;
- }
- static ErrorCode RefillEndOfFile(BufferedInput* bi) {
- return bi->fail(kEndOfFile);
- }
- ErrorCode fail(ErrorCode why) {
- error_ = why;
- refiller_ = RefillZeroes;
- return Refill();
- }
- const char* begin_;
- const char* end_;
- Refiller refiller_;
- ErrorCode error_;
- private:
- // Disallow copy and assign.
- BufferedInput(const BufferedInput&);
- void operator=(const BufferedInput&);
- };
- class BufferedInputStream : public BufferedInput {
- public:
- BufferedInputStream(FILE* fp, char* buf, size_t size)
- : BufferedInput(RefillFread),
- fp_(fp),
- buf_(buf),
- size_(size) {
- DCHECK(buf != NULL);
- // Disable buffering since we're doing it ourselves.
- // TODO check error.
- setvbuf(fp_, NULL, _IONBF, 0);
- cursor = buf;
- begin_ = buf;
- end_ = buf;
- }
- protected:
- // TODO: figure out how to automate this casting pattern.
- static ErrorCode RefillFread(BufferedInput* bi) {
- return static_cast<BufferedInputStream*>(bi)->DoRefillFread();
- }
- private:
- ErrorCode DoRefillFread() {
- const size_t bytes_read = fread(buf_, 1, size_, fp_);
- cursor = begin_;
- end_ = begin_ + bytes_read;
- if (bytes_read < size_) {
- if (feof(fp_)) {
- refiller_ = RefillEndOfFile;
- } else if (ferror(fp_)) {
- return fail(kFileError);
- }
- }
- return kNoError;
- }
- FILE* fp_;
- char* buf_;
- size_t size_;
- };
- } // namespace webgl_loader
- #endif // WEBGL_LOADER_STREAM_H_
|