1/*
2 * Copyright (c) 2000-2001,2003-2004 Apple Computer, 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// buffer - simple data buffers with convenience
27//
28#ifndef _H_BUFFER
29#define _H_BUFFER
30
31#include <security_utilities/utilities.h>
32#include <cstdarg>
33#include <limits.h>
34
35
36namespace Security {
37
38
39class Buffer {
40public:
41    Buffer(size_t size);			// allocate empty buffer
42    ~Buffer();
43
44    static Buffer reader(void *base, size_t size, bool owned = false)
45    { return Buffer(base, size, true, owned); }
46    static Buffer writer(void *base, size_t size, bool owned = false)
47    { return Buffer(base, size, false, owned); }
48
49    size_t available(bool heavy = false) const
50    { return heavy ? ((mTop - mEnd) + (mStart - mBase)): (mTop - mEnd); }
51    bool isFull(bool heavy = false) const
52    { return heavy ? (mEnd == mTop && mStart == mBase) : (mEnd == mTop); }
53    bool isEmpty() const		{ return mStart == mEnd; }
54
55    size_t length() const		{ return mEnd - mStart; }
56    void *data()				{ assert(mStart == mBase); return mStart; }
57
58    void clear()				{ mStart = mEnd = mBase; }
59
60protected:
61    // private constructor with full flexibility
62    Buffer(void *base, size_t size, bool filled, bool owned = false);
63
64    // perform expensive realignment to coalesce freespace
65    size_t shuffle(size_t needed = UINT_MAX);
66
67    // perform cheap adjustments after data was taken out
68    void adjustGet()
69    {
70        if (isEmpty())	// empty buffer. Reset pointers to base
71            mStart = mEnd = mBase;
72    }
73
74public:
75    // elementary put: copy mode
76    size_t put(const void *data, size_t length)
77    {
78        if (length > available())
79            length = shuffle(length);
80        memcpy(mEnd, data, length);
81        mEnd += length;
82        return length;
83    }
84
85    // elementary put: locate mode. Remember that each can shuffle memory
86    template <class T> void locatePut(T * &addr, size_t &length)
87    {
88        if (length > available())
89            length = shuffle(length);
90        addr = reinterpret_cast<T *>(mEnd);
91    }
92
93    void usePut(size_t length)
94    {
95        assert(length <= available());
96        mEnd += length;
97    }
98
99    // elementary get: locate mode
100    template <class T> void locateGet(T * &addr, size_t &length)
101    {
102        if (length > size_t(mEnd - mStart))
103            length = mEnd - mStart;
104        addr = reinterpret_cast<T *>(mStart);
105    }
106
107    void useGet(size_t length)
108    {
109        assert(length <= this->length());
110        mStart += length;
111        adjustGet();
112    }
113
114    //
115    // I/O via FileDescoid objects
116    //
117    template <class IO>
118    size_t read(IO &io, size_t length)
119    {
120        if (length > available())
121            length = shuffle(length);
122        size_t bytesRead = io.read(mEnd, length);
123        mEnd += bytesRead;
124        return bytesRead;
125    }
126
127    template <class IO>
128    size_t write(IO &io, size_t length)
129    {
130        length = min(this->length(), length);
131        size_t bytesWritten = io.write(mStart, length);
132        mStart += bytesWritten;
133        adjustGet();
134        return bytesWritten;
135    }
136
137    template <class IO> size_t read(IO &io, bool heavy = false)
138    { return read(io, available(heavy)); }
139
140    template <class IO> size_t write(IO &io)
141    { return write(io, length()); }
142
143    // printf-style output to a buffer
144    void printf(const char *format, ...);
145    void vprintf(const char *format, va_list args);
146
147    // memory ownership
148    void own()		{ mOwningMemory = true; }
149
150private:
151    char *const mBase;			// base pointer
152    char *const mTop;			// end pointer + 1
153    char *mStart;				// start of used area
154    char *mEnd;					// end of used area + 1
155    bool mOwningMemory;			// true if we own the memory (free on destruction)
156};
157
158
159}	// end namespace Security
160
161
162#endif //_H_BUFFER
163