source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/utils/converters/utf8/src/stream.h@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 6.1 KB
Line 
1// Copyright 2012 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you
4// may not use this file except in compliance with the License. You
5// may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12// implied. See the License for the specific language governing
13// permissions and limitations under the License.
14
15#ifndef WEBGL_LOADER_STREAM_H_
16#define WEBGL_LOADER_STREAM_H_
17
18#include <stdio.h>
19#include <string>
20#include <vector>
21
22#include "base.h"
23
24namespace webgl_loader {
25
26// An abstract interface to allow appending bytes to various streams.
27class ByteSinkInterface {
28 public:
29 virtual void Put(char c) = 0;
30 virtual size_t PutN(const char* data, size_t len) = 0;
31 virtual ~ByteSinkInterface() { }
32
33 protected:
34 ByteSinkInterface() { }
35
36 private:
37 // Disallow copy and assignment.
38 ByteSinkInterface(const ByteSinkInterface&);
39 void operator=(const ByteSinkInterface&);
40};
41
42// None of the concrete implementations actually own the backing data.
43// They should be safe to copy.
44
45class NullSink : public ByteSinkInterface {
46 public:
47 NullSink() { }
48
49 virtual void Put(char) { }
50
51 virtual size_t PutN(const char*, size_t len) { return len; }
52};
53
54class FileSink : public ByteSinkInterface {
55 public:
56 // |fp| is unowned and must not be NULL.
57 explicit FileSink(FILE* fp)
58 : fp_(fp) {
59 }
60
61 virtual void Put(char c) {
62 PutChar(c, fp_);
63 }
64
65 virtual size_t PutN(const char* data, size_t len) {
66 return fwrite(data, 1, len, fp_);
67 }
68
69 private:
70 FILE *fp_; // unowned.
71};
72
73class VectorSink : public ByteSinkInterface {
74 public:
75 // |vec| is unowned and must not be NULL.
76 explicit VectorSink(std::vector<char>* vec)
77 : vec_(vec) {
78 }
79
80 virtual void Put(char c) {
81 vec_->push_back(c);
82 }
83
84 virtual size_t PutN(const char* data, size_t len) {
85 vec_->insert(vec_->end(), data, data + len);
86 return len;
87 }
88
89 private:
90 std::vector<char>* vec_; // unowned.
91};
92
93class StringSink : public ByteSinkInterface {
94 public:
95 // |str| is unowned and must not be NULL.
96 explicit StringSink(std::string* str)
97 : str_(str) {
98 DCHECK(str != NULL);
99 }
100
101 virtual void Put(char c) {
102 str_->push_back(c);
103 }
104
105 virtual size_t PutN(const char* data, size_t len) {
106 str_->append(data, len);
107 return len;
108 }
109
110 private:
111 std::string* str_; // unowned.
112};
113
114class ByteHistogramSink : public ByteSinkInterface {
115 public:
116 // |sink| in unowned and must not be NULL.
117 explicit ByteHistogramSink(ByteSinkInterface* sink)
118 : sink_(sink) {
119 memset(histo_, 0, sizeof(histo_));
120 }
121
122 virtual void Put(char c) {
123 histo_[static_cast<uint8>(c)]++;
124 sink_->Put(c);
125 }
126
127 virtual size_t PutN(const char* data, size_t len) {
128 const char* const end = data + len;
129 for (const char* iter = data; iter != end; ++iter) {
130 histo_[static_cast<uint8>(*iter)]++;
131 }
132 return sink_->PutN(data, len);
133 }
134
135 const size_t* histo() const {
136 return histo_;
137 }
138
139 private:
140 size_t histo_[256];
141 ByteSinkInterface* sink_; // unowned.
142};
143
144// TODO: does it make sense to have a global enum? How should
145// new BufferedInput implementations define new error codes?
146enum ErrorCode {
147 kNoError = 0,
148 kEndOfFile = 1,
149 kFileError = 2, // TODO: translate errno.
150};
151
152// Adapted from ryg's BufferedStream abstraction:
153// http://fgiesen.wordpress.com/2011/11/21/buffer-centric-io/
154class BufferedInput {
155 public:
156 typedef ErrorCode (*Refiller)(BufferedInput*);
157
158 BufferedInput(Refiller refiller = RefillZeroes)
159 : cursor(NULL),
160 begin_(NULL),
161 end_(NULL),
162 refiller_(refiller),
163 error_(kNoError) {
164 }
165
166 // InitFromMemory.
167 BufferedInput(const char* data, size_t length)
168 : cursor(data),
169 begin_(data),
170 end_(data + length),
171 refiller_(RefillEndOfFile),
172 error_(kNoError) {
173 }
174
175 const char* begin() const {
176 return begin_;
177 }
178
179 const char* end() const {
180 return end_;
181 }
182
183 const char* cursor;
184
185 ErrorCode error() const {
186 DCHECK(begin() <= cursor);
187 DCHECK(cursor <= end());
188 return error_;
189 }
190
191 ErrorCode Refill() {
192 DCHECK(begin() <= cursor);
193 DCHECK(cursor <= end());
194 if (cursor == end()) {
195 error_ = refiller_(this);
196 }
197 return error_;
198 }
199
200 protected:
201 static ErrorCode RefillZeroes(BufferedInput* bi) {
202 static const char kZeroes[64] = { 0 };
203 bi->cursor = kZeroes;
204 bi->begin_ = kZeroes;
205 bi->end_ = kZeroes + sizeof(kZeroes);
206 return bi->error_;
207 }
208
209 static ErrorCode RefillEndOfFile(BufferedInput* bi) {
210 return bi->fail(kEndOfFile);
211 }
212
213 ErrorCode fail(ErrorCode why) {
214 error_ = why;
215 refiller_ = RefillZeroes;
216 return Refill();
217 }
218
219 const char* begin_;
220 const char* end_;
221 Refiller refiller_;
222 ErrorCode error_;
223
224 private:
225 // Disallow copy and assign.
226 BufferedInput(const BufferedInput&);
227 void operator=(const BufferedInput&);
228};
229
230class BufferedInputStream : public BufferedInput {
231 public:
232 BufferedInputStream(FILE* fp, char* buf, size_t size)
233 : BufferedInput(RefillFread),
234 fp_(fp),
235 buf_(buf),
236 size_(size) {
237 DCHECK(buf != NULL);
238 // Disable buffering since we're doing it ourselves.
239 // TODO check error.
240 setvbuf(fp_, NULL, _IONBF, 0);
241 cursor = buf;
242 begin_ = buf;
243 end_ = buf;
244 }
245 protected:
246 // TODO: figure out how to automate this casting pattern.
247 static ErrorCode RefillFread(BufferedInput* bi) {
248 return static_cast<BufferedInputStream*>(bi)->DoRefillFread();
249 }
250 private:
251 ErrorCode DoRefillFread() {
252 const size_t bytes_read = fread(buf_, 1, size_, fp_);
253 cursor = begin_;
254 end_ = begin_ + bytes_read;
255 if (bytes_read < size_) {
256 if (feof(fp_)) {
257 refiller_ = RefillEndOfFile;
258 } else if (ferror(fp_)) {
259 return fail(kFileError);
260 }
261 }
262 return kNoError;
263 }
264
265 FILE* fp_;
266 char* buf_;
267 size_t size_;
268};
269
270} // namespace webgl_loader
271
272#endif // WEBGL_LOADER_STREAM_H_
Note: See TracBrowser for help on using the repository browser.