]>
git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/walkers.h
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // walkers - facilities for traversing and manipulating recursive data structures
22 // Very briefly, this facility allows for deep traversals of (potentially) recursive
23 // data structures through templated structure "walkers." Standard operations include
24 // deep copying to a contiguous memory buffer, size calculation, and reconstitution
25 // after relocation (e.g. via IPC). You can add other operations (e.g. scattered deep
26 // copy, debug dumping, etc.) by defining operations classes and applying them to the
27 // existing walkers. You can also extend the reach of the facility to new data structures
28 // by writing appropriate walker functions for them.
30 // For more detailed rules and regulations, see the accompanying documentation.
35 #include <Security/utilities.h>
36 #include <Security/cssmalloc.h>
37 #include <Security/memutils.h>
52 // Standard operators for sizing, copying, and reinflating
54 class SizeWalker
: public LowLevelMemoryUtilities::Writer::Counter
{
57 void operator () (T
*, size_t size
= sizeof(T
))
58 { LowLevelMemoryUtilities::Writer::Counter::insert(size
); }
60 void reserve(size_t space
)
61 { LowLevelMemoryUtilities::Writer::Counter::insert(space
); }
63 static const bool needsRelinking
= false;
64 static const bool needsSize
= true;
67 class CopyWalker
: public LowLevelMemoryUtilities::Writer
{
70 CopyWalker(void *base
) : LowLevelMemoryUtilities::Writer(base
) { }
73 void operator () (T
* &addr
, size_t size
= sizeof(T
))
76 addr
= reinterpret_cast<T
*>(LowLevelMemoryUtilities::Writer::operator () (addr
, size
));
79 static const bool needsRelinking
= true;
80 static const bool needsSize
= true;
83 class ReconstituteWalker
{
85 ReconstituteWalker(off_t offset
) : mOffset(offset
) { }
86 ReconstituteWalker(void *ptr
, void *base
)
87 : mOffset(LowLevelMemoryUtilities::difference(ptr
, base
)) { }
90 void operator () (T
* &addr
, size_t = 0)
93 addr
= LowLevelMemoryUtilities::increment
<T
>(addr
, mOffset
);
96 static const bool needsRelinking
= true;
97 static const bool needsSize
= false;
103 class ChunkCopyWalker
{
105 ChunkCopyWalker(CssmAllocator
&alloc
= CssmAllocator::standard()) : allocator(alloc
) { }
107 CssmAllocator
&allocator
;
110 void operator () (T
* &addr
, size_t size
= sizeof(T
))
113 T
*copy
= reinterpret_cast<T
*>(allocator
.malloc(size
));
115 T
*copy
= allocator
.malloc
<T
>(size
);
117 memcpy(copy
, addr
, size
);
121 static const bool needsRelinking
= true;
122 static const bool needsSize
= true;
125 class ChunkFreeWalker
{
127 ChunkFreeWalker(CssmAllocator
&alloc
= CssmAllocator::standard()) : allocator(alloc
) { }
129 CssmAllocator
&allocator
;
132 void operator () (T
*addr
, size_t = sizeof(T
))
134 freeSet
.insert(addr
);
138 ~ChunkFreeWalker() { free(); }
140 static const bool needsRelinking
= false;
141 static const bool needsSize
= false;
144 std::set
<void *> freeSet
;
149 // The VirtualWalker class is a generic walker interface
150 // for dynamic passing around.
152 class VirtualWalker
{
154 VirtualWalker(bool nrl
= false) : needsRelinking(nrl
) { }
155 virtual ~VirtualWalker();
157 virtual void operator () (void * &addr
, size_t size
) = 0;
159 const bool needsRelinking
;
162 template <class Walker
>
163 class VirtualWalkerFor
: public VirtualWalker
{
165 VirtualWalkerFor(Walker
&w
, bool nrl
= false) : VirtualWalker(nrl
), walker(w
) { }
166 void operator () (void * &addr
, size_t size
)
167 { walker(addr
, size
); }
174 // Stand-alone operations for a single structure web
186 T
*copy(const T
*obj
, void *addr
)
192 return reinterpret_cast<T
*>(addr
);
196 T
*copy(const T
*obj
, CssmAllocator
&alloc
= CssmAllocator::standard())
198 return obj
? copy(obj
, alloc
, size(obj
)) : NULL
;
202 T
*copy(const T
*obj
, CssmAllocator
&alloc
, size_t size
)
206 return copy(obj
, alloc
.malloc(size
));
210 void copy(const T
*obj
, CssmAllocator
&alloc
, CssmData
&data
)
216 if (data
.data() == NULL
) {
217 size_t length
= size(obj
);
218 data
= CssmData(alloc
.malloc(length
), length
);
220 assert(size(obj
) <= data
.length());
221 copy(obj
, data
.data());
226 void relocate(T
*obj
, T
*base
)
229 ReconstituteWalker
w(LowLevelMemoryUtilities::difference(obj
, base
));
236 T
*chunkCopy(const T
*obj
, CssmAllocator
&alloc
= CssmAllocator::standard())
239 ChunkCopyWalker
w(alloc
);
246 void chunkFree(const T
*obj
, CssmAllocator
&alloc
= CssmAllocator::standard())
249 ChunkFreeWalker
w(alloc
);
257 Copier(const T
*obj
, CssmAllocator
&alloc
= CssmAllocator::standard()) : allocator(alloc
)
265 mValue
= reinterpret_cast<T
*>(alloc
.malloc(mLength
));
267 mValue
= alloc
.malloc
<T
>(mLength
);
269 mValue
= copy(obj
, mValue
);
273 Copier(const T
*obj
, uint32 count
, CssmAllocator
&alloc
= CssmAllocator::standard())
281 sizer
.reserve(sizeof(T
) * count
); // initial vector size
282 for (uint32 n
= 0; n
< count
; n
++)
283 walk(sizer
, obj
[n
]); // dependent data sizes
286 mValue
= reinterpret_cast<T
*>(alloc
.malloc(mLength
));
288 mValue
= alloc
.malloc
<T
>(mLength
);
290 CopyWalker
copier(LowLevelMemoryUtilities::increment(mValue
, sizeof(T
) * count
));
291 for (uint32 n
= 0; n
< count
; n
++) {
293 walk(copier
, mValue
[n
]);
298 CssmAllocator
&allocator
;
300 ~Copier() { allocator
.free(mValue
); }
302 operator T
*() const { return mValue
; }
303 size_t length() const { return mLength
; }
305 T
*keep() { T
*result
= mValue
; mValue
= NULL
; return result
; }
314 // Allow const pointer input but cast the const-ness away.
315 // This is valid because the walkers never directly *write* into *obj;
316 // they just pass their parts along to operate(). If we are in a writing
317 // pass, operate() must ensure it copies (and replaces) its argument to
319 // (The alternative design calls for three walk() functions for each type,
320 // which is ugly and error prone.)
322 template <class Action
, class T
>
323 T
*walk(Action
&operate
, const T
* &obj
)
324 { return walk(operate
, const_cast<T
* &>(obj
)); }
328 // The default walker assumes a flat data structure
330 template <class Action
, class Type
>
331 Type
*walk(Action
&operate
, Type
* &obj
)
338 } // end namespace DataWalkers
340 } // end namespace Security