1/*
2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// ReadWriteSection.h
21//
22
23#ifndef _H_APPLEDL_READWRITESECTION
24#define _H_APPLEDL_READWRITESECTION
25
26#include <security_utilities/alloc.h>
27#include <security_filedb/AtomicFile.h>
28#include <security_utilities/endian.h>
29#include <security_cdsa_utilities/cssmerrors.h>
30#include <Security/cssm.h>
31#include "OverUnderflowCheck.h"
32
33namespace Security
34{
35
36//
37// Atom -- An Atom is a 32-bit unsigned integer value that is always internally
38// represented using network byte order.
39//
40typedef Endian<uint32> Atom;
41
42enum {
43	AtomSize = sizeof(uint32) // XXX Why not just use sizeof(Atom)?
44};
45
46//
47// Class representing a range (or subrange of a buffer).
48//
49class Range
50{
51public:
52	Range(uint32 inOffset, uint32 inSize) : mOffset(inOffset), mSize(inSize) {}
53	uint32 mOffset;
54	uint32 mSize;
55};
56
57//
58// Class representing a packed record.  All the accessors on this class are const since the
59// underlying data is read-only
60//
61// XXX Should be replaced by Atom::Vector
62class ReadSection
63{
64protected:
65    ReadSection(uint8 *inAddress, size_t inLength) : mAddress(inAddress), mLength(inLength)
66	{
67		if (mAddress == NULL)
68            CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
69	}
70public:
71	ReadSection() : mAddress(NULL), mLength(0) {}
72    ReadSection(const uint8 *inAddress, size_t inLength) :
73	    mAddress(const_cast<uint8 *>(inAddress)), mLength(inLength) {}
74
75    uint32 size() const { return (uint32)mLength; }
76
77    uint32 at(uint32 inOffset) const
78    {
79		if (inOffset > mLength)
80		{
81            CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
82		}
83
84        return ntohl(*reinterpret_cast<const uint32 *>(mAddress + inOffset));
85    }
86
87    uint32 operator[](uint32 inOffset) const
88    {
89        return at(inOffset);
90    }
91
92	// Return a subsection from inOffset to end of section.
93    ReadSection subsection(uint32 inOffset) const
94    {
95        if (inOffset > mLength)
96            CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
97        return ReadSection(mAddress + inOffset, mLength - inOffset);
98    }
99
100	// Return a subsection from inOffset of inLength bytes.
101    ReadSection subsection(uint32 inOffset, uint32 inLength) const
102    {
103        if (CheckUInt32Add(inOffset, inLength) > mLength)
104            CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
105        return ReadSection(mAddress + inOffset, inLength);
106    }
107
108	ReadSection subsection(const Range &inRange) const
109	{
110		return subsection(inRange.mOffset, inRange.mSize);
111	}
112
113    const uint8 *range(const Range &inRange) const
114    {
115        if (CheckUInt32Add(inRange.mOffset, inRange.mSize) > mLength)
116            CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
117        return mAddress + inRange.mOffset;
118    }
119
120	uint8 *allocCopyRange(const Range &inRange, Allocator &inAllocator) const
121	{
122	    uint8 *aData;
123	    if (inRange.mSize == 0)
124	        aData = NULL;
125	    else
126	    {
127	        if (CheckUInt32Add(inRange.mOffset, inRange.mSize) > mLength)
128	            CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
129
130	        aData = reinterpret_cast<uint8 *>(inAllocator.malloc(inRange.mSize));
131	        memcpy(aData, mAddress + inRange.mOffset, inRange.mSize);
132	    }
133
134		return aData;
135	}
136
137	static uint32 align(uint32 offset) { return (CheckUInt32Subtract(CheckUInt32Add(offset, AtomSize), 1)) & ~(AtomSize - 1); }
138
139protected:
140    uint8 *mAddress;
141    size_t mLength;
142};
143
144//
145// Class representing a packed record (or buffer) used for writing.
146//
147class WriteSection : public ReadSection
148{
149public:
150	static const size_t DefaultCapacity = 64;
151
152    WriteSection(Allocator &inAllocator, size_t inCapacity) :
153        ReadSection(reinterpret_cast<uint8 *>(inAllocator.malloc(inCapacity)), 0),
154        mAllocator(inAllocator),
155        mCapacity(inCapacity)
156	{
157		if (mCapacity > 0)
158			memset(mAddress, 0, mCapacity);
159	}
160
161    WriteSection(Allocator &inAllocator = Allocator::standard()) :
162        ReadSection(reinterpret_cast<uint8 *>(inAllocator.malloc(DefaultCapacity)), 0),
163        mAllocator(inAllocator),
164        mCapacity(DefaultCapacity)
165	{
166	}
167
168	WriteSection(const WriteSection &ws, int length) :
169		ReadSection(reinterpret_cast<uint8 *>(ws.mAllocator.malloc(length)), length),
170		mAllocator(ws.mAllocator),
171		mCapacity(length)
172	{
173		memcpy(mAddress, ws.mAddress, length);
174	}
175
176    ~WriteSection() { mAllocator.free(mAddress); }
177
178private:
179    void grow(size_t inNewCapacity);
180
181public:
182#if BUG_GCC
183	uint32 size() const { return ReadSection::size(); }
184#else
185	// XXX This should work but egcs-2.95.2 doesn't like it.
186	using ReadSection::size;
187#endif
188
189    void size(uint32 inLength) { mLength = inLength; }
190    uint32 put(uint32 inOffset, uint32 inValue);
191    uint32 put(uint32 inOffset, uint32 inLength, const uint8 *inData);
192
193    const uint8 *address() const { return mAddress; }
194    uint8 *release()
195    {
196        uint8 *anAddress = mAddress;
197        mAddress = NULL;
198        mCapacity = 0;
199        return anAddress;
200    }
201
202private:
203    Allocator &mAllocator;
204    size_t mCapacity;
205};
206
207} // end namespace Security
208
209#endif // _H_APPLEDL_READWRITESECTION
210