mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2025-01-11 19:55:10 +01:00
273 lines
6.1 KiB
C++
Executable File
273 lines
6.1 KiB
C++
Executable File
// 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_
|