]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2002,2004,2011,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // streams.h - lightweight source and sink objects | |
27 | // | |
28 | #ifndef _H_STREAMS | |
29 | #define _H_STREAMS | |
30 | ||
31 | #include "unix++.h" | |
32 | ||
33 | ||
34 | namespace Security { | |
35 | ||
36 | using UnixPlusPlus::FileDesc; | |
37 | ||
38 | ||
39 | // | |
40 | // An abstract Source object. | |
41 | // Source can yield data when its produce method is called. Produce can yield | |
42 | // anything between zero and length bytes and sets length accordingly. | |
43 | // If the last call to produce returned zero bytes (and only then), the state method | |
44 | // will yield an explanation: | |
45 | // producing -> we're in business; there just no data quite yet (try again) | |
46 | // stalled -> there may be more data coming, but not in the near future; | |
47 | // wait a while then call state again to see | |
48 | // endOfData -> no more data will be produced by this Source | |
49 | // When called *before* the first call to produce, getSize may return the number | |
50 | // of bytes that all calls to produce will yield together. If getSize returns unknownSize, | |
51 | // this value cannot be determined beforehand. GetSize *may* yield the number of bytes | |
52 | // yet to come when called after produce, but this is not guaranteed for all Sources. | |
53 | // | |
54 | class Source { | |
55 | public: | |
56 | virtual void produce(void *data, size_t &length) = 0; | |
57 | virtual ~Source() { } | |
58 | ||
59 | static const size_t unknownSize = size_t(-1); | |
60 | virtual size_t getSize(); | |
61 | ||
62 | enum State { | |
63 | producing, // yielding data (go ahead) | |
64 | stalled, // no data now, perhaps more later | |
65 | endOfData // end of data (no more data) | |
66 | }; | |
67 | virtual State state() const; | |
68 | ||
69 | protected: | |
70 | State mState; // auto-regulated state (can be overridden) | |
71 | }; | |
72 | ||
73 | ||
74 | // | |
75 | // An abstract Sink object. | |
76 | // Sinks can cansume data when their consume method is called. | |
77 | // Sinks cannot refuse data; they always consume all data given to consume. | |
78 | // There is currently no flow control/throttle mechanism (one will probably | |
79 | // be added soon). | |
80 | // | |
81 | class Sink { | |
82 | public: | |
83 | Sink() : mSize(0) {} | |
84 | virtual ~Sink() { } | |
85 | virtual void consume(const void *data, size_t length) = 0; | |
86 | virtual void setSize(size_t expectedSize); | |
87 | size_t getSize() {return mSize;} | |
88 | ||
89 | protected: | |
90 | size_t mSize; | |
91 | ||
92 | }; | |
93 | ||
94 | ||
95 | // | |
96 | // The NullSource produces no data. | |
97 | // | |
98 | class NullSource : public Source { | |
99 | public: | |
100 | void produce(void *addr, size_t &len); | |
101 | State state() const; | |
102 | }; | |
103 | ||
104 | ||
105 | // | |
106 | // A FileSource reads from a UNIX file or file descriptor. | |
107 | // Note that getSize will yield the size of the underlying i-node, | |
108 | // which is usually correct but may not be in the case of simultaneous | |
109 | // access. | |
110 | // | |
111 | class FileSource : public Source, public FileDesc { | |
112 | public: | |
113 | FileSource(const char *path, int mode = O_RDONLY) : FileDesc(path, mode) { mState = producing; } | |
114 | FileSource(int fd) : FileDesc(fd) { mState = producing; } | |
115 | void produce(void *data, size_t &length); | |
116 | size_t getSize(); | |
117 | }; | |
118 | ||
119 | ||
120 | // | |
121 | // A MemorySource yields the contents of a preset contiguous memory block. | |
122 | // | |
123 | class MemorySource : public Source { | |
124 | public: | |
125 | MemorySource(const void *data, size_t length) : mData(data), mRemaining(length) { } | |
126 | ||
127 | template <class Data> | |
128 | MemorySource(const Data &data) : mData(data.data()), mRemaining(data.length()) { } | |
129 | ||
130 | void produce(void *data, size_t &length); | |
131 | size_t getSize(); | |
132 | State state() const; | |
133 | ||
134 | private: | |
135 | const void *mData; | |
136 | size_t mRemaining; | |
137 | }; | |
138 | ||
139 | ||
140 | // | |
141 | // A NullSink eats all data and discards it quietly. | |
142 | // | |
143 | class NullSink : public Sink { | |
144 | public: | |
145 | void consume(const void *data, size_t length); | |
146 | }; | |
147 | ||
148 | ||
149 | // | |
150 | // A FileSink writes its received data to a UNIX file or file descriptor. | |
151 | // | |
152 | class FileSink : public Sink, public FileDesc { | |
153 | public: | |
154 | FileSink(const char *path, int mode = O_WRONLY | O_CREAT | O_TRUNC) | |
155 | : FileDesc(path, mode) { } | |
156 | FileSink(int fd) : FileDesc(fd) { } | |
157 | void consume(const void *data, size_t length); | |
158 | }; | |
159 | ||
160 | ||
161 | // | |
162 | // MemorySinks collect output in a contiguous memory block. | |
163 | // This is not often a good idea, so if you find yourself using this, | |
164 | // consider consuming on-the-fly or streaming to secondary media, | |
165 | // or (at least) use a BufferFifo instead. | |
166 | // | |
167 | class MemorySink : public Sink { | |
168 | public: | |
169 | MemorySink() : mBuffer(NULL), mMax(0) { } | |
170 | ~MemorySink() { free(mBuffer); } | |
171 | ||
172 | void consume(const void *data, size_t length); | |
173 | void setSize(size_t expectedSize); | |
174 | ||
175 | void *data() const { return mBuffer; } | |
176 | size_t length() const { return mSize; } | |
177 | ||
178 | void clear() { free(mBuffer); mBuffer = NULL; mSize = mMax = 0; } | |
179 | ||
180 | private: | |
181 | void grow(size_t newSize); | |
182 | ||
183 | private: | |
184 | void *mBuffer; // buffer base | |
185 | size_t mMax; // currently allocated | |
186 | }; | |
187 | ||
188 | ||
189 | } // end namespace Security | |
190 | ||
191 | ||
192 | #endif /* _H_STREAMS */ |