1/*
2 * Copyright 2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Alex Wilson, yourpalal2@gmail.com
7 */
8
9
10#include "ArchivingManagers.h"
11
12#include <syslog.h>
13#include <typeinfo>
14
15#include <StackOrHeapArray.h>
16
17
18namespace BPrivate {
19namespace Archiving {
20	const char* kArchivableField = "_managed_archivable";
21	const char* kManagedField = "_managed_archive";
22}
23}
24
25
26using namespace BPrivate::Archiving;
27
28
29BArchiveManager*
30BManagerBase::ArchiveManager(const BMessage* archive)
31{
32	BManagerBase* manager = ManagerPointer(archive);
33	if (!manager)
34		return NULL;
35
36	if (manager->fType == ARCHIVE_MANAGER)
37		return static_cast<BArchiveManager*>(manager);
38
39	debugger("Overlapping managed unarchive/archive sessions.");
40	return NULL;
41}
42
43
44BUnarchiveManager*
45BManagerBase::UnarchiveManager(const BMessage* archive)
46{
47	BManagerBase* manager = ManagerPointer(archive);
48	if (!manager)
49		return NULL;
50
51	if (manager->fType == UNARCHIVE_MANAGER)
52		return static_cast<BUnarchiveManager*>(manager);
53
54	debugger("More calls to BUnarchiver::PrepareArchive()"
55		" than BUnarchivers created.");
56
57	return NULL;
58}
59
60
61// #pragma mark -
62
63
64struct BArchiveManager::ArchiveInfo {
65	ArchiveInfo()
66		:
67		token(-1),
68		archive(NULL)
69	{
70	}
71
72
73	~ArchiveInfo()
74	{
75		delete archive;
76	}
77
78
79	int32		token;
80	BMessage*	archive;
81};
82
83
84BArchiveManager::BArchiveManager(const BArchiver* creator)
85	:
86	BManagerBase(creator->ArchiveMessage(), BManagerBase::ARCHIVE_MANAGER),
87	fTokenMap(),
88	fCreator(creator),
89	fError(B_OK)
90{
91}
92
93
94BArchiveManager::~BArchiveManager()
95{
96	fTopLevelArchive->AddBool(kManagedField, true);
97}
98
99
100status_t
101BArchiveManager::GetTokenForArchivable(BArchivable* archivable, int32& _token)
102{
103	if (!archivable) {
104		_token = NULL_TOKEN;
105		return B_OK;
106	}
107
108	TokenMap::iterator it = fTokenMap.find(archivable);
109
110	if (it == fTokenMap.end())
111		return B_ENTRY_NOT_FOUND;
112
113	_token = it->second.token;
114	return B_OK;
115}
116
117
118status_t
119BArchiveManager::ArchiveObject(BArchivable* archivable,
120	bool deep, int32& _token)
121{
122	if (!archivable) {
123		_token = NULL_TOKEN;
124		return B_OK;
125	}
126
127	ArchiveInfo& info = fTokenMap[archivable];
128
129	status_t err = B_OK;
130
131	if (!info.archive) {
132		info.archive = new BMessage();
133		info.token = fTokenMap.size() - 1;
134
135		MarkArchive(info.archive);
136		err = archivable->Archive(info.archive, deep);
137	}
138
139	if (err != B_OK) {
140		fTokenMap.erase(archivable);
141			// info.archive gets deleted here
142		_token = NULL_TOKEN;
143	} else
144		_token = info.token;
145
146	return err;
147}
148
149
150bool
151BArchiveManager::IsArchived(BArchivable* archivable)
152{
153	if (!archivable)
154		return true;
155
156	return fTokenMap.find(archivable) != fTokenMap.end();
157}
158
159
160status_t
161BArchiveManager::ArchiverLeaving(const BArchiver* archiver, status_t err)
162{
163	if (fError == B_OK)
164		fError = err;
165
166	if (archiver == fCreator && fError == B_OK) {
167		// first, we must sort the objects into the order they were archived in
168		typedef std::pair<BMessage*, const BArchivable*> ArchivePair;
169		BStackOrHeapArray<ArchivePair, 64> pairs(fTokenMap.size());
170
171		for(TokenMap::iterator it = fTokenMap.begin(), end = fTokenMap.end();
172				it != end; it++) {
173			ArchiveInfo& info = it->second;
174			pairs[info.token].first = info.archive;
175			pairs[info.token].second = it->first;
176
177			// make sure fTopLevelArchive isn't deleted
178			if (info.archive == fTopLevelArchive)
179				info.archive = NULL;
180		}
181
182		int32 count = fTokenMap.size();
183		for (int32 i = 0; i < count; i++) {
184			const ArchivePair& pair = pairs[i];
185			fError = pair.second->AllArchived(pair.first);
186
187			if (fError == B_OK && i > 0) {
188				fError = fTopLevelArchive->AddMessage(kArchivableField,
189					pair.first);
190			}
191
192			if (fError != B_OK) {
193				syslog(LOG_ERR, "AllArchived failed for object of type %s.",
194					typeid(*pairs[i].second).name());
195				break;
196			}
197		}
198	}
199
200	status_t result = fError;
201	if (archiver == fCreator)
202		delete this;
203
204	return result;
205}
206
207
208void
209BArchiveManager::RegisterArchivable(const BArchivable* archivable)
210{
211	if (fTokenMap.size() == 0) {
212		ArchiveInfo& info = fTokenMap[archivable];
213		info.archive = fTopLevelArchive;
214		info.token = 0;
215	}
216}
217
218
219// #pragma mark -
220
221
222struct BUnarchiveManager::ArchiveInfo {
223	ArchiveInfo()
224		:
225		archivable(NULL),
226		archive(),
227		adopted(false)
228	{
229	}
230
231	bool
232	operator<(const ArchiveInfo& other)
233	{
234		return archivable < other.archivable;
235	}
236
237	BArchivable*	archivable;
238	BMessage		archive;
239	bool			adopted;
240};
241
242
243// #pragma mark -
244
245
246BUnarchiveManager::BUnarchiveManager(BMessage* archive)
247	:
248	BManagerBase(archive, BManagerBase::UNARCHIVE_MANAGER),
249	fObjects(NULL),
250	fObjectCount(0),
251	fTokenInProgress(0),
252	fRefCount(0),
253	fError(B_OK)
254{
255	archive->GetInfo(kArchivableField, NULL, &fObjectCount);
256	fObjectCount++;
257		// root object needs a spot too
258	fObjects = new ArchiveInfo[fObjectCount];
259
260	// fObjects[0] is a placeholder for the object that started
261	// this unarchiving session.
262	for (int32 i = 0; i < fObjectCount - 1; i++) {
263		BMessage* into = &fObjects[i + 1].archive;
264		status_t err = archive->FindMessage(kArchivableField, i, into);
265		MarkArchive(into);
266
267		if (err != B_OK)
268			syslog(LOG_ERR, "Failed to find managed archivable");
269	}
270}
271
272
273BUnarchiveManager::~BUnarchiveManager()
274{
275	delete[] fObjects;
276}
277
278
279status_t
280BUnarchiveManager::GetArchivableForToken(int32 token,
281	BUnarchiver::ownership_policy owning, BArchivable*& _archivable)
282{
283	if (token >= fObjectCount)
284		return B_BAD_VALUE;
285
286	if (token < 0) {
287		_archivable = NULL;
288		return B_OK;
289	}
290
291	status_t err = B_OK;
292	ArchiveInfo& info = fObjects[token];
293	if (!info.archivable) {
294		if (fRefCount > 0) {
295			fTokenInProgress = token;
296			if(!instantiate_object(&info.archive))
297				err = B_ERROR;
298		} else {
299			syslog(LOG_ERR, "Object requested from AllUnarchived()"
300				" was not previously instantiated");
301			err = B_ERROR;
302		}
303	}
304
305	if (owning == BUnarchiver::B_ASSUME_OWNERSHIP)
306		info.adopted = true;
307
308	_archivable = info.archivable;
309	return err;
310}
311
312
313bool
314BUnarchiveManager::IsInstantiated(int32 token)
315{
316	if (token < 0 || token >= fObjectCount)
317		return false;
318	return fObjects[token].archivable;
319}
320
321
322void
323BUnarchiveManager::RegisterArchivable(BArchivable* archivable)
324{
325	if (!archivable)
326		debugger("Cannot register NULL pointer");
327
328	fObjects[fTokenInProgress].archivable = archivable;
329	archivable->fArchivingToken = fTokenInProgress;
330}
331
332
333status_t
334BUnarchiveManager::UnarchiverLeaving(const BUnarchiver* unarchiver,
335	status_t err)
336{
337	if (--fRefCount >= 0 && fError == B_OK)
338		fError = err;
339
340	if (fRefCount != 0)
341		return fError;
342
343	if (fError == B_OK) {
344		BArchivable* archivable = fObjects[0].archivable;
345		if (archivable) {
346			fError = archivable->AllUnarchived(fTopLevelArchive);
347			archivable->fArchivingToken = NULL_TOKEN;
348		}
349
350		for (int32 i = 1; i < fObjectCount && fError == B_OK; i++) {
351			archivable = fObjects[i].archivable;
352			if (archivable) {
353				fError = archivable->AllUnarchived(&fObjects[i].archive);
354				archivable->fArchivingToken = NULL_TOKEN;
355			}
356		}
357		if (fError != B_OK) {
358			syslog(LOG_ERR, "Error in AllUnarchived"
359				" method of object of type %s", typeid(*archivable).name());
360		}
361	}
362
363	if (fError != B_OK) {
364		syslog(LOG_ERR, "An error occured during unarchival, cleaning up.");
365		for (int32 i = 1; i < fObjectCount; i++) {
366			if (!fObjects[i].adopted)
367				delete fObjects[i].archivable;
368		}
369	}
370
371	status_t result = fError;
372	delete this;
373	return result;
374}
375
376
377void
378BUnarchiveManager::RelinquishOwnership(BArchivable* archivable)
379{
380	int32 token = NULL_TOKEN;
381	if (archivable)
382		token = archivable->fArchivingToken;
383
384	if (token < 0 || token >= fObjectCount
385		|| fObjects[token].archivable != archivable)
386		return;
387
388	fObjects[token].adopted = false;
389}
390
391
392void
393BUnarchiveManager::AssumeOwnership(BArchivable* archivable)
394{
395	int32 token = NULL_TOKEN;
396	if (archivable)
397		token = archivable->fArchivingToken;
398
399	if (token < 0 || token >= fObjectCount
400		|| fObjects[token].archivable != archivable)
401		return;
402
403	fObjects[token].adopted = true;
404}
405
406
407void
408BUnarchiveManager::Acquire()
409{
410	if (fRefCount >= 0)
411		fRefCount++;
412}
413