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