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