1// UserDataWriter.cpp
2
3#include <util/kernel_cpp.h>
4#include <ddm_userland_interface.h>
5#include <Vector.h>
6
7#include "UserDataWriter.h"
8
9using namespace std;
10
11typedef uint8	*addr;
12
13// RelocationEntryList
14struct UserDataWriter::RelocationEntryList : Vector<addr*> {};
15
16// constructor
17UserDataWriter::UserDataWriter()
18	: fBuffer(NULL),
19	  fBufferSize(0),
20	  fAllocatedSize(0),
21	  fRelocationEntries(NULL)
22{
23}
24
25// constructor
26UserDataWriter::UserDataWriter(user_disk_device_data *buffer,
27							   size_t bufferSize)
28	: fBuffer(NULL),
29	  fBufferSize(0),
30	  fAllocatedSize(0),
31	  fRelocationEntries(NULL)
32{
33	SetTo(buffer, bufferSize);
34}
35
36// destructor
37UserDataWriter::~UserDataWriter()
38{
39	delete fRelocationEntries;
40}
41
42// SetTo
43status_t
44UserDataWriter::SetTo(user_disk_device_data *buffer, size_t bufferSize)
45{
46	Unset();
47	fBuffer = buffer;
48	fBufferSize = bufferSize;
49	fAllocatedSize = 0;
50	if (fBuffer && fBufferSize > 0) {
51		fRelocationEntries = new(nothrow) RelocationEntryList;
52		if (!fRelocationEntries)
53			return B_NO_MEMORY;
54	}
55	return B_OK;
56}
57
58// Unset
59void
60UserDataWriter::Unset()
61{
62	delete fRelocationEntries;
63	fBuffer = NULL;
64	fBufferSize = 0;
65	fAllocatedSize = 0;
66	fRelocationEntries = NULL;
67}
68
69// AllocateData
70void *
71UserDataWriter::AllocateData(size_t size, size_t align)
72{
73	// handles size == 0 gracefully
74	// get a properly aligned offset
75	size_t offset = fAllocatedSize;
76	if (align > 1)
77		offset = (fAllocatedSize + align - 1) / align * align;
78	// get the result pointer
79	void *result = NULL;
80	if (fBuffer && offset + size <= fBufferSize)
81		result = (uint8*)fBuffer + offset;
82	// always update the allocated size, even if there wasn't enough space
83	fAllocatedSize = offset + size;
84	return result;
85}
86
87// AllocatePartitionData
88user_partition_data *
89UserDataWriter::AllocatePartitionData(size_t childCount)
90{
91	return (user_partition_data*)AllocateData(
92		sizeof(user_partition_data)
93		+ sizeof(user_partition_data*) * ((int32)childCount - 1),
94		sizeof(int));
95}
96
97// AllocateDeviceData
98user_disk_device_data *
99UserDataWriter::AllocateDeviceData(size_t childCount)
100{
101	return (user_disk_device_data*)AllocateData(
102		sizeof(user_disk_device_data)
103		+ sizeof(user_partition_data*) * ((int32)childCount - 1),
104		sizeof(int));
105}
106
107// PlaceString
108char *
109UserDataWriter::PlaceString(const char *str)
110{
111	if (!str)
112		return NULL;
113	size_t len = strlen(str) + 1;
114	char *data = (char*)AllocateData(len);
115	if (data)
116		memcpy(data, str, len);
117	return data;
118}
119
120// AllocatedSize
121size_t
122UserDataWriter::AllocatedSize() const
123{
124	return fAllocatedSize;
125}
126
127// AddRelocationEntry
128status_t
129UserDataWriter::AddRelocationEntry(void *address)
130{
131	if (fRelocationEntries && (addr)address >= (addr)fBuffer
132		&& (addr)address < (addr)fBuffer + fBufferSize - sizeof(void*)) {
133		return fRelocationEntries->PushBack((addr*)address);
134	}
135	return B_ERROR;
136}
137
138// Relocate
139status_t
140UserDataWriter::Relocate(void *address)
141{
142	if (!fRelocationEntries || !fBuffer)
143		return B_BAD_VALUE;
144	int32 count = fRelocationEntries->Count();
145	for (int32 i = 0; i < count; i++) {
146		addr *entry = fRelocationEntries->ElementAt(i);
147		if (*entry)
148			*entry += (addr)address - (addr)fBuffer;
149	}
150	return B_OK;
151}
152
153