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
18 namespace BPrivate {
19 namespace Archiving {
20 const char* kArchivableField = "_managed_archivable";
21 const char* kManagedField = "_managed_archive";
22 }
23 }
24
25
26 using namespace BPrivate::Archiving;
27
28
29 BArchiveManager*
ArchiveManager(const BMessage * archive)30 BManagerBase::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
44 BUnarchiveManager*
UnarchiveManager(const BMessage * archive)45 BManagerBase::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
64 struct BArchiveManager::ArchiveInfo {
ArchiveInfoBArchiveManager::ArchiveInfo65 ArchiveInfo()
66 :
67 token(-1),
68 archive(NULL)
69 {
70 }
71
72
~ArchiveInfoBArchiveManager::ArchiveInfo73 ~ArchiveInfo()
74 {
75 delete archive;
76 }
77
78
79 int32 token;
80 BMessage* archive;
81 };
82
83
BArchiveManager(const BArchiver * creator)84 BArchiveManager::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
~BArchiveManager()94 BArchiveManager::~BArchiveManager()
95 {
96 fTopLevelArchive->AddBool(kManagedField, true);
97 }
98
99
100 status_t
GetTokenForArchivable(BArchivable * archivable,int32 & _token)101 BArchiveManager::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
118 status_t
ArchiveObject(BArchivable * archivable,bool deep,int32 & _token)119 BArchiveManager::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
150 bool
IsArchived(BArchivable * archivable)151 BArchiveManager::IsArchived(BArchivable* archivable)
152 {
153 if (!archivable)
154 return true;
155
156 return fTokenMap.find(archivable) != fTokenMap.end();
157 }
158
159
160 status_t
ArchiverLeaving(const BArchiver * archiver,status_t err)161 BArchiveManager::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
208 void
RegisterArchivable(const BArchivable * archivable)209 BArchiveManager::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
222 struct BUnarchiveManager::ArchiveInfo {
ArchiveInfoBUnarchiveManager::ArchiveInfo223 ArchiveInfo()
224 :
225 archivable(NULL),
226 archive(),
227 adopted(false)
228 {
229 }
230
231 bool
operator <BUnarchiveManager::ArchiveInfo232 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
BUnarchiveManager(BMessage * archive)246 BUnarchiveManager::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
~BUnarchiveManager()273 BUnarchiveManager::~BUnarchiveManager()
274 {
275 delete[] fObjects;
276 }
277
278
279 status_t
GetArchivableForToken(int32 token,BUnarchiver::ownership_policy owning,BArchivable * & _archivable)280 BUnarchiveManager::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
313 bool
IsInstantiated(int32 token)314 BUnarchiveManager::IsInstantiated(int32 token)
315 {
316 if (token < 0 || token >= fObjectCount)
317 return false;
318 return fObjects[token].archivable;
319 }
320
321
322 void
RegisterArchivable(BArchivable * archivable)323 BUnarchiveManager::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
333 status_t
UnarchiverLeaving(const BUnarchiver * unarchiver,status_t err)334 BUnarchiveManager::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
377 void
RelinquishOwnership(BArchivable * archivable)378 BUnarchiveManager::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
392 void
AssumeOwnership(BArchivable * archivable)393 BUnarchiveManager::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
407 void
Acquire()408 BUnarchiveManager::Acquire()
409 {
410 if (fRefCount >= 0)
411 fRefCount++;
412 }
413