/* * Copyright (c) 2000-2002,2004,2011,2014 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // // streams.h - lightweight source and sink objects // #ifndef _H_STREAMS #define _H_STREAMS #include "unix++.h" namespace Security { using UnixPlusPlus::FileDesc; // // An abstract Source object. // Source can yield data when its produce method is called. Produce can yield // anything between zero and length bytes and sets length accordingly. // If the last call to produce returned zero bytes (and only then), the state method // will yield an explanation: // producing -> we're in business; there just no data quite yet (try again) // stalled -> there may be more data coming, but not in the near future; // wait a while then call state again to see // endOfData -> no more data will be produced by this Source // When called *before* the first call to produce, getSize may return the number // of bytes that all calls to produce will yield together. If getSize returns unknownSize, // this value cannot be determined beforehand. GetSize *may* yield the number of bytes // yet to come when called after produce, but this is not guaranteed for all Sources. // class Source { public: virtual void produce(void *data, size_t &length) = 0; virtual ~Source() { } static const size_t unknownSize = size_t(-1); virtual size_t getSize(); enum State { producing, // yielding data (go ahead) stalled, // no data now, perhaps more later endOfData // end of data (no more data) }; virtual State state() const; protected: State mState; // auto-regulated state (can be overridden) }; // // An abstract Sink object. // Sinks can cansume data when their consume method is called. // Sinks cannot refuse data; they always consume all data given to consume. // There is currently no flow control/throttle mechanism (one will probably // be added soon). // class Sink { public: Sink() : mSize(0) {} virtual ~Sink() { } virtual void consume(const void *data, size_t length) = 0; virtual void setSize(size_t expectedSize); size_t getSize() {return mSize;} protected: size_t mSize; }; // // The NullSource produces no data. // class NullSource : public Source { public: void produce(void *addr, size_t &len); State state() const; }; // // A FileSource reads from a UNIX file or file descriptor. // Note that getSize will yield the size of the underlying i-node, // which is usually correct but may not be in the case of simultaneous // access. // class FileSource : public Source, public FileDesc { public: FileSource(const char *path, int mode = O_RDONLY) : FileDesc(path, mode) { mState = producing; } FileSource(int fd) : FileDesc(fd) { mState = producing; } void produce(void *data, size_t &length); size_t getSize(); }; // // A MemorySource yields the contents of a preset contiguous memory block. // class MemorySource : public Source { public: MemorySource(const void *data, size_t length) : mData(data), mRemaining(length) { } template MemorySource(const Data &data) : mData(data.data()), mRemaining(data.length()) { } void produce(void *data, size_t &length); size_t getSize(); State state() const; private: const void *mData; size_t mRemaining; }; // // A NullSink eats all data and discards it quietly. // class NullSink : public Sink { public: void consume(const void *data, size_t length); }; // // A FileSink writes its received data to a UNIX file or file descriptor. // class FileSink : public Sink, public FileDesc { public: FileSink(const char *path, int mode = O_WRONLY | O_CREAT | O_TRUNC) : FileDesc(path, mode) { } FileSink(int fd) : FileDesc(fd) { } void consume(const void *data, size_t length); }; // // MemorySinks collect output in a contiguous memory block. // This is not often a good idea, so if you find yourself using this, // consider consuming on-the-fly or streaming to secondary media, // or (at least) use a BufferFifo instead. // class MemorySink : public Sink { public: MemorySink() : mBuffer(NULL), mMax(0) { } ~MemorySink() { free(mBuffer); } void consume(const void *data, size_t length); void setSize(size_t expectedSize); void *data() const { return mBuffer; } size_t length() const { return mSize; } void clear() { free(mBuffer); mBuffer = NULL; mSize = mMax = 0; } private: void grow(size_t newSize); private: void *mBuffer; // buffer base size_t mMax; // currently allocated }; } // end namespace Security #endif /* _H_STREAMS */