1/*
2 * Copyright (c) 2000-2004,2011-2012,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// memstreams - primitive memory block streaming support
27//
28#ifndef _H_MEMSTREAMS
29#define _H_MEMSTREAMS
30
31#include <stdint.h>
32#include <security_utilities/memutils.h>
33#include <security_utilities/endian.h>
34#include <security_utilities/errors.h>
35
36
37namespace Security
38{
39
40//
41// Encapsulate these very sharp tools in a separate namespace
42//
43namespace LowLevelMemoryUtilities
44{
45
46
47//
48// A simple utility for incremental creation of a contiguous memory block.
49//
50// Note that Writer and Writer::Counter go together. They use the same alignment
51// and padding rules, so Writer::Counter will correctly calculate total buffer
52// size for Writer, *presuming* that they are called in the same order.
53//
54// This layer allocates no memory; that's up to the caller (you).
55//
56// WARNING: There is no check for overflow. If you write too much, you will die.
57// Writer::Counter can tell you how much you need.
58//
59class Writer {
60private:
61	void *advance(size_t size)
62	{
63		void *here = alignUp(writePos);
64		writePos = increment(here, size);
65		return here;
66	}
67
68public:
69	Writer() { }
70	Writer(void *base) : writePos(base) { }
71	void operator = (void *base) { writePos = base; }
72
73	template <class T>
74	T *operator () (const T &obj)
75	{ T *here = (T *)advance(sizeof(T)); *here = obj; return here; }
76
77	void *operator () (const void *addr, size_t size)
78	{ void *here = advance(size); return memcpy(here, addr, size); }
79
80	char *operator () (const char *s)
81	{ return (char *)(*this)(s, strlen(s) + 1); }
82
83	void countedData(const void *data, size_t length)
84	{
85        if (length > uint32_t(~0))
86            UnixError::throwMe(ERANGE);
87        Endian<uint32_t> temp = (uint32_t)length; (*this)(temp); (*this)(data, length);
88    }
89
90	template <class Data>
91	void countedData(const Data &data)
92	{ countedData(data.data(), data.length()); }
93
94	class Counter;
95
96private:
97	void *writePos;			// next byte address
98};
99
100class Writer::Counter {
101private:
102	void align() { totalSoFar = alignUp(totalSoFar); }
103
104public:
105	Counter() : totalSoFar(0) { }
106	operator size_t () { return totalSoFar; }
107
108	template <class T> size_t operator () (const T &) { align(); return totalSoFar += sizeof(T); }
109	size_t insert(size_t size) { align(); return totalSoFar += size; }
110	size_t operator () (const char *s) { align(); return totalSoFar += strlen(s) + 1; }
111
112	void countedData(const void *, size_t length)
113	{ insert(sizeof(length)); insert(length); }
114
115	template <class Data>
116	void countedData(const Data &data)
117	{ countedData(data.data(), data.length()); }
118
119private:
120	size_t totalSoFar;	// total size counted so far
121};
122
123
124//
125// The Reader counter-part for a Writer.
126// Again, Reader and Writer share alignment and representation rules, so what was
127// Written shall be Read again, just fine.
128//
129class Reader {
130private:
131    const void *advance(size_t size = 0)
132    {
133        const void *here = alignUp(readPos);
134        readPos = increment(here, size);
135        return here;
136    }
137
138public:
139    Reader() { }
140    Reader(const void *base) : readPos(base) { }
141    void operator = (const void *base) { readPos = base; }
142
143    template <class T>
144    void operator () (T &obj) {	obj = *reinterpret_cast<const T *>(advance(sizeof(T))); }
145    void operator () (void *addr, size_t size)	{ memcpy(addr, advance(size), size); }
146    void operator () (const char * &s)
147    { s = reinterpret_cast<const char *>(advance()); advance(strlen(s) + 1); }
148    template <class T>
149    const T *get(size_t size)
150	{ return reinterpret_cast<const T *>(advance(size)); }
151
152	void countedData(const void * &data, size_t &length)
153	{ Endian<uint32_t> temp; (*this)(temp); length = temp; data = advance(length); }
154
155private:
156	// Explicitly forbid some invocations that are likely to be wrong.
157	void operator () (char * &s);	// can't get writable string in-place
158
159private:
160    const void *readPos;	// next byte address
161};
162
163
164} // end namespace LowLevelMemoryUtilities
165
166} // end namespace Security
167
168#endif //_H_MEMUTILS
169