HaikuDepot: notify work status from main window
[haiku.git] / src / kits / support / ArchivingManagers.cpp
blob82838e8d649f04c8c5a24daa54414cc1bc5afc5a
1 /*
2 * Copyright 2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Alex Wilson, yourpalal2@gmail.com
7 */
10 #include "ArchivingManagers.h"
12 #include <syslog.h>
13 #include <typeinfo>
15 #include <StackOrHeapArray.h>
18 namespace BPrivate {
19 namespace Archiving {
20 const char* kArchivableField = "_managed_archivable";
21 const char* kManagedField = "_managed_archive";
26 using namespace BPrivate::Archiving;
29 BArchiveManager*
30 BManagerBase::ArchiveManager(const BMessage* archive)
32 BManagerBase* manager = ManagerPointer(archive);
33 if (!manager)
34 return NULL;
36 if (manager->fType == ARCHIVE_MANAGER)
37 return static_cast<BArchiveManager*>(manager);
39 debugger("Overlapping managed unarchive/archive sessions.");
40 return NULL;
44 BUnarchiveManager*
45 BManagerBase::UnarchiveManager(const BMessage* archive)
47 BManagerBase* manager = ManagerPointer(archive);
48 if (!manager)
49 return NULL;
51 if (manager->fType == UNARCHIVE_MANAGER)
52 return static_cast<BUnarchiveManager*>(manager);
54 debugger("More calls to BUnarchiver::PrepareArchive()"
55 " than BUnarchivers created.");
57 return NULL;
61 // #pragma mark -
64 struct BArchiveManager::ArchiveInfo {
65 ArchiveInfo()
67 token(-1),
68 archive(NULL)
73 ~ArchiveInfo()
75 delete archive;
79 int32 token;
80 BMessage* archive;
84 BArchiveManager::BArchiveManager(const BArchiver* creator)
86 BManagerBase(creator->ArchiveMessage(), BManagerBase::ARCHIVE_MANAGER),
87 fTokenMap(),
88 fCreator(creator),
89 fError(B_OK)
94 BArchiveManager::~BArchiveManager()
96 fTopLevelArchive->AddBool(kManagedField, true);
100 status_t
101 BArchiveManager::GetTokenForArchivable(BArchivable* archivable, int32& _token)
103 if (!archivable) {
104 _token = NULL_TOKEN;
105 return B_OK;
108 TokenMap::iterator it = fTokenMap.find(archivable);
110 if (it == fTokenMap.end())
111 return B_ENTRY_NOT_FOUND;
113 _token = it->second.token;
114 return B_OK;
118 status_t
119 BArchiveManager::ArchiveObject(BArchivable* archivable,
120 bool deep, int32& _token)
122 if (!archivable) {
123 _token = NULL_TOKEN;
124 return B_OK;
127 ArchiveInfo& info = fTokenMap[archivable];
129 status_t err = B_OK;
131 if (!info.archive) {
132 info.archive = new BMessage();
133 info.token = fTokenMap.size() - 1;
135 MarkArchive(info.archive);
136 err = archivable->Archive(info.archive, deep);
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;
146 return err;
150 bool
151 BArchiveManager::IsArchived(BArchivable* archivable)
153 if (!archivable)
154 return true;
156 return fTokenMap.find(archivable) != fTokenMap.end();
160 status_t
161 BArchiveManager::ArchiverLeaving(const BArchiver* archiver, status_t err)
163 if (fError == B_OK)
164 fError = err;
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());
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;
177 // make sure fTopLevelArchive isn't deleted
178 if (info.archive == fTopLevelArchive)
179 info.archive = NULL;
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);
187 if (fError == B_OK && i > 0) {
188 fError = fTopLevelArchive->AddMessage(kArchivableField,
189 pair.first);
192 if (fError != B_OK) {
193 syslog(LOG_ERR, "AllArchived failed for object of type %s.",
194 typeid(*pairs[i].second).name());
195 break;
200 status_t result = fError;
201 if (archiver == fCreator)
202 delete this;
204 return result;
208 void
209 BArchiveManager::RegisterArchivable(const BArchivable* archivable)
211 if (fTokenMap.size() == 0) {
212 ArchiveInfo& info = fTokenMap[archivable];
213 info.archive = fTopLevelArchive;
214 info.token = 0;
219 // #pragma mark -
222 struct BUnarchiveManager::ArchiveInfo {
223 ArchiveInfo()
225 archivable(NULL),
226 archive(),
227 adopted(false)
231 bool
232 operator<(const ArchiveInfo& other)
234 return archivable < other.archivable;
237 BArchivable* archivable;
238 BMessage archive;
239 bool adopted;
243 // #pragma mark -
246 BUnarchiveManager::BUnarchiveManager(BMessage* archive)
248 BManagerBase(archive, BManagerBase::UNARCHIVE_MANAGER),
249 fObjects(NULL),
250 fObjectCount(0),
251 fTokenInProgress(0),
252 fRefCount(0),
253 fError(B_OK)
255 archive->GetInfo(kArchivableField, NULL, &fObjectCount);
256 fObjectCount++;
257 // root object needs a spot too
258 fObjects = new ArchiveInfo[fObjectCount];
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);
267 if (err != B_OK)
268 syslog(LOG_ERR, "Failed to find managed archivable");
273 BUnarchiveManager::~BUnarchiveManager()
275 delete[] fObjects;
279 status_t
280 BUnarchiveManager::GetArchivableForToken(int32 token,
281 BUnarchiver::ownership_policy owning, BArchivable*& _archivable)
283 if (token >= fObjectCount)
284 return B_BAD_VALUE;
286 if (token < 0) {
287 _archivable = NULL;
288 return B_OK;
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;
305 if (owning == BUnarchiver::B_ASSUME_OWNERSHIP)
306 info.adopted = true;
308 _archivable = info.archivable;
309 return err;
313 bool
314 BUnarchiveManager::IsInstantiated(int32 token)
316 if (token < 0 || token >= fObjectCount)
317 return false;
318 return fObjects[token].archivable;
322 void
323 BUnarchiveManager::RegisterArchivable(BArchivable* archivable)
325 if (!archivable)
326 debugger("Cannot register NULL pointer");
328 fObjects[fTokenInProgress].archivable = archivable;
329 archivable->fArchivingToken = fTokenInProgress;
333 status_t
334 BUnarchiveManager::UnarchiverLeaving(const BUnarchiver* unarchiver,
335 status_t err)
337 if (--fRefCount >= 0 && fError == B_OK)
338 fError = err;
340 if (fRefCount != 0)
341 return fError;
343 if (fError == B_OK) {
344 BArchivable* archivable = fObjects[0].archivable;
345 if (archivable) {
346 fError = archivable->AllUnarchived(fTopLevelArchive);
347 archivable->fArchivingToken = NULL_TOKEN;
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;
357 if (fError != B_OK) {
358 syslog(LOG_ERR, "Error in AllUnarchived"
359 " method of object of type %s", typeid(*archivable).name());
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;
371 status_t result = fError;
372 delete this;
373 return result;
377 void
378 BUnarchiveManager::RelinquishOwnership(BArchivable* archivable)
380 int32 token = NULL_TOKEN;
381 if (archivable)
382 token = archivable->fArchivingToken;
384 if (token < 0 || token >= fObjectCount
385 || fObjects[token].archivable != archivable)
386 return;
388 fObjects[token].adopted = false;
392 void
393 BUnarchiveManager::AssumeOwnership(BArchivable* archivable)
395 int32 token = NULL_TOKEN;
396 if (archivable)
397 token = archivable->fArchivingToken;
399 if (token < 0 || token >= fObjectCount
400 || fObjects[token].archivable != archivable)
401 return;
403 fObjects[token].adopted = true;
407 void
408 BUnarchiveManager::Acquire()
410 if (fRefCount >= 0)
411 fRefCount++;