2 * Copyright 2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Alex Wilson, yourpalal2@gmail.com
10 #include "ArchivingManagers.h"
15 #include <StackOrHeapArray.h>
20 const char* kArchivableField
= "_managed_archivable";
21 const char* kManagedField
= "_managed_archive";
26 using namespace BPrivate::Archiving
;
30 BManagerBase::ArchiveManager(const BMessage
* archive
)
32 BManagerBase
* manager
= ManagerPointer(archive
);
36 if (manager
->fType
== ARCHIVE_MANAGER
)
37 return static_cast<BArchiveManager
*>(manager
);
39 debugger("Overlapping managed unarchive/archive sessions.");
45 BManagerBase::UnarchiveManager(const BMessage
* archive
)
47 BManagerBase
* manager
= ManagerPointer(archive
);
51 if (manager
->fType
== UNARCHIVE_MANAGER
)
52 return static_cast<BUnarchiveManager
*>(manager
);
54 debugger("More calls to BUnarchiver::PrepareArchive()"
55 " than BUnarchivers created.");
64 struct BArchiveManager::ArchiveInfo
{
84 BArchiveManager::BArchiveManager(const BArchiver
* creator
)
86 BManagerBase(creator
->ArchiveMessage(), BManagerBase::ARCHIVE_MANAGER
),
94 BArchiveManager::~BArchiveManager()
96 fTopLevelArchive
->AddBool(kManagedField
, true);
101 BArchiveManager::GetTokenForArchivable(BArchivable
* archivable
, int32
& _token
)
108 TokenMap::iterator it
= fTokenMap
.find(archivable
);
110 if (it
== fTokenMap
.end())
111 return B_ENTRY_NOT_FOUND
;
113 _token
= it
->second
.token
;
119 BArchiveManager::ArchiveObject(BArchivable
* archivable
,
120 bool deep
, int32
& _token
)
127 ArchiveInfo
& info
= fTokenMap
[archivable
];
132 info
.archive
= new BMessage();
133 info
.token
= fTokenMap
.size() - 1;
135 MarkArchive(info
.archive
);
136 err
= archivable
->Archive(info
.archive
, deep
);
140 fTokenMap
.erase(archivable
);
141 // info.archive gets deleted here
151 BArchiveManager::IsArchived(BArchivable
* archivable
)
156 return fTokenMap
.find(archivable
) != fTokenMap
.end();
161 BArchiveManager::ArchiverLeaving(const BArchiver
* archiver
, status_t 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();
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
)
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
,
192 if (fError
!= B_OK
) {
193 syslog(LOG_ERR
, "AllArchived failed for object of type %s.",
194 typeid(*pairs
[i
].second
).name());
200 status_t result
= fError
;
201 if (archiver
== fCreator
)
209 BArchiveManager::RegisterArchivable(const BArchivable
* archivable
)
211 if (fTokenMap
.size() == 0) {
212 ArchiveInfo
& info
= fTokenMap
[archivable
];
213 info
.archive
= fTopLevelArchive
;
222 struct BUnarchiveManager::ArchiveInfo
{
232 operator<(const ArchiveInfo
& other
)
234 return archivable
< other
.archivable
;
237 BArchivable
* archivable
;
246 BUnarchiveManager::BUnarchiveManager(BMessage
* archive
)
248 BManagerBase(archive
, BManagerBase::UNARCHIVE_MANAGER
),
255 archive
->GetInfo(kArchivableField
, NULL
, &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
);
268 syslog(LOG_ERR
, "Failed to find managed archivable");
273 BUnarchiveManager::~BUnarchiveManager()
280 BUnarchiveManager::GetArchivableForToken(int32 token
,
281 BUnarchiver::ownership_policy owning
, BArchivable
*& _archivable
)
283 if (token
>= fObjectCount
)
292 ArchiveInfo
& info
= fObjects
[token
];
293 if (!info
.archivable
) {
295 fTokenInProgress
= token
;
296 if(!instantiate_object(&info
.archive
))
299 syslog(LOG_ERR
, "Object requested from AllUnarchived()"
300 " was not previously instantiated");
305 if (owning
== BUnarchiver::B_ASSUME_OWNERSHIP
)
308 _archivable
= info
.archivable
;
314 BUnarchiveManager::IsInstantiated(int32 token
)
316 if (token
< 0 || token
>= fObjectCount
)
318 return fObjects
[token
].archivable
;
323 BUnarchiveManager::RegisterArchivable(BArchivable
* archivable
)
326 debugger("Cannot register NULL pointer");
328 fObjects
[fTokenInProgress
].archivable
= archivable
;
329 archivable
->fArchivingToken
= fTokenInProgress
;
334 BUnarchiveManager::UnarchiverLeaving(const BUnarchiver
* unarchiver
,
337 if (--fRefCount
>= 0 && fError
== B_OK
)
343 if (fError
== B_OK
) {
344 BArchivable
* archivable
= fObjects
[0].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
;
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
;
378 BUnarchiveManager::RelinquishOwnership(BArchivable
* archivable
)
380 int32 token
= NULL_TOKEN
;
382 token
= archivable
->fArchivingToken
;
384 if (token
< 0 || token
>= fObjectCount
385 || fObjects
[token
].archivable
!= archivable
)
388 fObjects
[token
].adopted
= false;
393 BUnarchiveManager::AssumeOwnership(BArchivable
* archivable
)
395 int32 token
= NULL_TOKEN
;
397 token
= archivable
->fArchivingToken
;
399 if (token
< 0 || token
>= fObjectCount
400 || fObjects
[token
].archivable
!= archivable
)
403 fObjects
[token
].adopted
= true;
408 BUnarchiveManager::Acquire()