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