1/*
2 * Copyright (c) 2000-2002,2004,2011,2014 Apple Inc. All Rights Reserved.
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
34namespace Security {
35
36using 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//
54class Source {
55public:
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
69protected:
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//
81class Sink {
82public:
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
89protected:
90    size_t mSize;
91
92};
93
94
95//
96// The NullSource produces no data.
97//
98class NullSource : public Source {
99public:
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//
111class FileSource : public Source, public FileDesc {
112public:
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//
123class MemorySource : public Source {
124public:
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
134private:
135    const void *mData;
136    size_t mRemaining;
137};
138
139
140//
141// A NullSink eats all data and discards it quietly.
142//
143class NullSink : public Sink {
144public:
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//
152class FileSink : public Sink, public FileDesc {
153public:
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//
167class MemorySink : public Sink {
168public:
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
180private:
181    void grow(size_t newSize);
182
183private:
184    void *mBuffer;		// buffer base
185    size_t mMax;		// currently allocated
186};
187
188
189}	// end namespace Security
190
191
192#endif /* _H_STREAMS */
193