X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_utilities/lib/streams.h diff --git a/Security/libsecurity_utilities/lib/streams.h b/Security/libsecurity_utilities/lib/streams.h new file mode 100644 index 00000000..0d2036d7 --- /dev/null +++ b/Security/libsecurity_utilities/lib/streams.h @@ -0,0 +1,192 @@ +/* + * 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 */