Patch by Alex Wilson (minor changes by myself) related to the new archiving

features:
* Some cosmetic adjustments of the API, like using references instead of
  pointers, argument order, method names, etc.
* Added convenience template methods for archiving and unarchiving to BArchiver
  and BUnarchiver.
* BUnarchiver (respectively the private BUnarchiveManager) explicitly deals with
  object ownership, now. This is necessary since an error while unarchiving
  could leave an already unarchived object without owning object, which would
  result in it being leaked. The BUnarchiver::{Get,Find}Object() methods do now
  have an optional parameter to specify whether object ownership shall be
  transferred.
* Fixed incorrect header guard in headers/private/binary_compatibility/Global.h.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37538 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2010-07-16 16:49:42 +00:00
parent 6a78d35e85
commit b137ab3eb3
8 changed files with 421 additions and 190 deletions
+4 -4
View File
@@ -54,11 +54,11 @@ public:
virtual status_t Archive(BMessage* into, bool deep = true) const; virtual status_t Archive(BMessage* into, bool deep = true) const;
virtual status_t AllUnarchived(const BMessage* from); virtual status_t AllUnarchived(const BMessage* from);
virtual status_t ArchiveLayoutData(BMessage* into,
const BLayoutItem* of) const;
virtual status_t RestoreItemAndData(const BMessage* from,
BLayoutItem* item);
virtual status_t ItemArchived(BMessage* into, BLayoutItem* item,
int32 index) const;
virtual status_t ItemUnarchived(const BMessage* from,
BLayoutItem* item, int32 index);
protected: protected:
// TODO: Since memory allocations can fail, we should return a bool and // TODO: Since memory allocations can fail, we should return a bool and
// undo the addition, if false. // undo the addition, if false.
+188 -13
View File
@@ -7,11 +7,13 @@
#include <image.h> #include <image.h>
#include <Message.h>
#include <SupportDefs.h> #include <SupportDefs.h>
class BMessage; class BMessage;
namespace BPrivate { namespace BPrivate {
namespace Archiving { namespace Archiving {
class BArchiveManager; class BArchiveManager;
@@ -38,9 +40,12 @@ public:
virtual status_t AllArchived(BMessage* archive) const; virtual status_t AllArchived(BMessage* archive) const;
private: private:
friend class BUnarchiveManager;
virtual void _ReservedArchivable3(); virtual void _ReservedArchivable3();
uint32 _reserved[2]; int32 fArchivingToken;
uint32 _reserved;
}; };
@@ -52,11 +57,13 @@ public:
status_t AddArchivable(const char* name, status_t AddArchivable(const char* name,
BArchivable* archivable, bool deep = true); BArchivable* archivable, bool deep = true);
inline status_t GetTokenForArchivable(BArchivable* archivable,
int32& _token);
status_t GetTokenForArchivable(BArchivable* archivable, status_t GetTokenForArchivable(BArchivable* archivable,
int32& _token, bool deep = true); bool deep, int32& _token);
bool IsArchived(BArchivable* archivable); bool IsArchived(BArchivable* archivable);
status_t Finish(); status_t Finish(status_t err = B_OK);
BMessage* ArchiveMessage() const; BMessage* ArchiveMessage() const;
private: private:
@@ -71,37 +78,64 @@ private:
BArchiveManager* fManager; BArchiveManager* fManager;
BMessage* fArchive; BMessage* fArchive;
bool fFinished; bool fFinished;
uint32 _reserved[2];
}; };
class BUnarchiver { class BUnarchiver {
public: public:
enum ownership_policy {
B_ASSUME_OWNERSHIP,
B_DONT_ASSUME_OWNERSHIP
};
BUnarchiver(const BMessage* archive); BUnarchiver(const BMessage* archive);
~BUnarchiver(); ~BUnarchiver();
status_t GetArchivable(int32 token, template<class T>
BArchivable** archivable); inline status_t GetObject(int32 token, T*& object);
status_t FindArchivable(const char* name, template<class T>
BArchivable** archivable); status_t GetObject(int32 token, ownership_policy owning,
T*& object);
status_t FindArchivable(const char* name, int32 index, template<class T>
BArchivable** archivable); inline status_t FindObject(const char* name, T*& object);
status_t EnsureUnarchived(const char* name, template<class T>
inline status_t FindObject(const char* name,
ownership_policy owning,
T*& object);
template<class T>
inline status_t FindObject(const char* name,
int32 index, T*& object);
template<class T>
status_t FindObject(const char* name, int32 index,
ownership_policy owning, T*& object);
inline status_t EnsureUnarchived(const char* name,
int32 index = 0); int32 index = 0);
status_t EnsureUnarchived(int32 token); inline status_t EnsureUnarchived(int32 token);
bool IsInstantiated(int32 token); bool IsInstantiated(int32 token);
bool IsInstantiated(const char* name, bool IsInstantiated(const char* name,
int32 index = 0); int32 index = 0);
status_t Finish(); status_t Finish(status_t err = B_OK);
const BMessage* ArchiveMessage() const; const BMessage* ArchiveMessage() const;
void AssumeOwnership(BArchivable* archivable);
void RelinquishOwnership(BArchivable* archivable);
static bool IsArchiveManaged(BMessage* archive); static bool IsArchiveManaged(BMessage* archive);
static BMessage* PrepareArchive(BMessage*& archive); static BMessage* PrepareArchive(BMessage*& archive);
template<class T>
static status_t InstantiateObject(BMessage* archive,
T*& object);
private: private:
friend class BArchivable; friend class BArchivable;
@@ -110,11 +144,12 @@ private:
void RegisterArchivable(BArchivable* archivable); void RegisterArchivable(BArchivable* archivable);
void _CallDebuggerIfManagerNull(); inline void _CallDebuggerIfManagerNull();
BUnarchiveManager* fManager; BUnarchiveManager* fManager;
const BMessage* fArchive; const BMessage* fArchive;
bool fFinished; bool fFinished;
uint32 _reserved[2];
}; };
@@ -131,4 +166,144 @@ instantiation_func find_instantiation_func(const char* className,
instantiation_func find_instantiation_func(const char* className); instantiation_func find_instantiation_func(const char* className);
instantiation_func find_instantiation_func(BMessage* archive); instantiation_func find_instantiation_func(BMessage* archive);
status_t
BArchiver::GetTokenForArchivable(BArchivable* archivable, int32& _token)
{
return GetTokenForArchivable(archivable, true, _token);
}
template<>
status_t BUnarchiver::FindObject<BArchivable>(const char* name, int32 index,
ownership_policy owning, BArchivable*& archivable);
template<class T>
status_t
BUnarchiver::FindObject(const char* name, int32 index,
ownership_policy owning, T*& object)
{
object = NULL;
BArchivable* interim;
status_t err = FindObject(name, index, owning, interim);
if (err == B_OK && interim) {
object = dynamic_cast<T*>(interim);
if (!object) {
err = B_BAD_TYPE;
// we will not be deleting this item, but it must be deleted
if (owning == B_ASSUME_OWNERSHIP)
RelinquishOwnership(interim);
}
}
return err;
}
template<>
status_t
BUnarchiver::GetObject<BArchivable>(int32 token,
ownership_policy owning, BArchivable*& object);
template<class T>
status_t
BUnarchiver::GetObject(int32 token, ownership_policy owning, T*& object)
{
object = NULL;
BArchivable* interim;
status_t err = GetObject(token, owning, interim);
if (err == B_OK && interim) {
object = dynamic_cast<T*>(interim);
if (!object) {
err = B_BAD_TYPE;
// we will not be deleting this item, but it must be deleted
if (owning == B_ASSUME_OWNERSHIP)
RelinquishOwnership(interim);
}
}
return err;
}
template<class T>
status_t
BUnarchiver::GetObject(int32 token, T*& object)
{
return GetObject<T>(token, B_ASSUME_OWNERSHIP, object);
}
template<class T>
status_t
BUnarchiver::FindObject(const char* name, ownership_policy owning, T*& object)
{
return FindObject(name, 0, owning, object);
}
template<class T>
status_t
BUnarchiver::FindObject(const char* name, T*& object)
{
return FindObject<T>(name, 0, B_ASSUME_OWNERSHIP, object);
}
template<class T>
status_t
BUnarchiver::FindObject(const char* name,
int32 index, T*& object)
{
return FindObject(name, index, B_ASSUME_OWNERSHIP, object);
}
status_t
BUnarchiver::EnsureUnarchived(int32 token)
{
BArchivable* dummy;
return GetObject(token, B_DONT_ASSUME_OWNERSHIP, dummy);
}
status_t
BUnarchiver::EnsureUnarchived(const char* name, int32 index)
{
BArchivable* dummy;
return FindObject(name, index, B_DONT_ASSUME_OWNERSHIP, dummy);
}
template<>
status_t
BUnarchiver::InstantiateObject<BArchivable>(BMessage* from,
BArchivable*& object);
template<class T>
status_t
BUnarchiver::InstantiateObject(BMessage* archive, T*& object)
{
object = NULL;
BArchivable* interim;
status_t err = InstantiateObject(archive, interim);
if (err != B_OK || interim == NULL)
return err;
object = dynamic_cast<T*>(interim);
if (object == NULL) {
delete interim;
return B_BAD_TYPE;
}
return B_OK;
}
#endif // _ARCHIVABLE_H #endif // _ARCHIVABLE_H
@@ -4,7 +4,7 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _BINARY_COMPATIBILITY_GLOBAL_H_ #ifndef _BINARY_COMPATIBILITY_GLOBAL_H_
#define _BINARY_COMPATIBILITY__GLOBAL_H_ #define _BINARY_COMPATIBILITY_GLOBAL_H_
// method codes // method codes
@@ -24,7 +24,6 @@ enum {
PERFORM_CODE_GET_TOOL_TIP_AT = 1009, PERFORM_CODE_GET_TOOL_TIP_AT = 1009,
// support kit // support kit
PERFORM_CODE_ALL_ARCHIVED = 1010, PERFORM_CODE_ALL_ARCHIVED = 1010,
PERFORM_CODE_ALL_UNARCHIVED = 1011 PERFORM_CODE_ALL_UNARCHIVED = 1011
}; };
@@ -2,8 +2,8 @@
* Copyright 2010, Haiku, Inc. * Copyright 2010, Haiku, Inc.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _BINARY_COMPATIBILITY_SUPPORT_H #ifndef _BINARY_COMPATIBILITY_SUPPORT_H_
#define _BINARY_COMPATIBILITY_SUPPORT_H #define _BINARY_COMPATIBILITY_SUPPORT_H_
#include <binary_compatibility/Global.h> #include <binary_compatibility/Global.h>
@@ -20,4 +20,4 @@ struct perform_data_all_archived {
status_t return_value; status_t return_value;
}; };
#endif /* _BINARY_COMPATIBILITY_INTERFACE_H_ */ #endif /* _BINARY_COMPATIBILITY_SUPPORT_H_ */
+23 -37
View File
@@ -7,6 +7,7 @@
#include <Layout.h> #include <Layout.h>
#include <syslog.h>
#include <new> #include <new>
#include <Message.h> #include <Message.h>
@@ -19,11 +20,9 @@ using std::nothrow;
namespace { namespace {
const char* kLayoutItemField = "BLayout:_items"; const char* kLayoutItemField = "BLayout:_items";
const char* kLayoutDataField = "BLayout:_data";
} }
// constructor
BLayout::BLayout() BLayout::BLayout()
: :
fView(NULL), fView(NULL),
@@ -211,77 +210,64 @@ BLayout::Archive(BMessage* into, bool deep) const
BArchiver archiver(into); BArchiver archiver(into);
status_t err = BArchivable::Archive(into, deep); status_t err = BArchivable::Archive(into, deep);
if (err != B_OK)
return err;
if (deep) { if (deep) {
int32 count = CountItems(); int32 count = CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count && err == B_OK; i++) {
err = archiver.AddArchivable(kLayoutItemField, ItemAt(i), deep); BLayoutItem* item = ItemAt(i);
err = archiver.AddArchivable(kLayoutItemField, item, deep);
if (err == B_OK) { if (err == B_OK) {
BMessage data; err = ItemArchived(into, item, i);
err = ArchiveLayoutData(&data, ItemAt(i));
if (err == B_OK)
err = into->AddMessage(kLayoutDataField, &data);
}
if (err != B_OK) if (err != B_OK)
return err; syslog(LOG_ERR, "ItemArchived() failed at index: %d.", i);
}
} }
} }
return archiver.Finish(); return archiver.Finish(err);
} }
status_t status_t
BLayout::AllUnarchived(const BMessage* from) BLayout::AllUnarchived(const BMessage* from)
{ {
status_t err = BArchivable::AllUnarchived(from);
BUnarchiver unarchiver(from); BUnarchiver unarchiver(from);
status_t err = BArchivable::AllUnarchived(from);
if (err != B_OK) if (err != B_OK)
return err; return err;
for (int32 i = 0; ; i++) { int32 itemCount;
BArchivable* retriever; unarchiver.ArchiveMessage()->GetInfo(kLayoutItemField, NULL, &itemCount);
err = unarchiver.FindArchivable(kLayoutItemField, i, &retriever); for (int32 i = 0; i < itemCount && err == B_OK; i++) {
BLayoutItem* item;
err = unarchiver.FindObject(kLayoutItemField, i, item);
if (err == B_BAD_INDEX) if (err == B_OK && item) {
break; if (fItems.AddItem(item)) {
ItemAdded(item);
if (err == B_OK) { item->SetLayout(this);
BMessage layoutData; err = ItemUnarchived(from, item, i);
err = from->FindMessage(kLayoutDataField, i, &layoutData); } else
err = B_NO_MEMORY;
if (err == B_OK) {
BLayoutItem* item = dynamic_cast<BLayoutItem*>(retriever);
err = RestoreItemAndData(&layoutData, item);
} }
} }
if (err != B_OK)
return err; return err;
}
return B_OK;
} }
status_t status_t
BLayout::ArchiveLayoutData(BMessage* into, const BLayoutItem* of) const BLayout::ItemArchived(BMessage* into, BLayoutItem* of, int32 index) const
{ {
return B_OK; return B_OK;
} }
status_t status_t
BLayout::RestoreItemAndData(const BMessage* from, BLayoutItem* item) BLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item, int32 index)
{ {
if (item && AddItem(item))
return B_OK; return B_OK;
return B_ERROR;
} }
+57 -52
View File
@@ -210,11 +210,15 @@ check_signature(const char* signature, image_info& info)
BArchivable::BArchivable() BArchivable::BArchivable()
:
fArchivingToken(NULL_TOKEN)
{ {
} }
BArchivable::BArchivable(BMessage* from) BArchivable::BArchivable(BMessage* from)
:
fArchivingToken(NULL_TOKEN)
{ {
if (BUnarchiver::IsArchiveManaged(from)) { if (BUnarchiver::IsArchiveManaged(from)) {
BUnarchiver::PrepareArchive(from); BUnarchiver::PrepareArchive(from);
@@ -313,7 +317,7 @@ BArchiver::BArchiver(BMessage* archive)
BArchiver::~BArchiver() BArchiver::~BArchiver()
{ {
if (!fFinished) if (!fFinished)
fManager->ArchiverLeaving(this); fManager->ArchiverLeaving(this, B_OK);
} }
@@ -321,7 +325,7 @@ status_t
BArchiver::AddArchivable(const char* name, BArchivable* archivable, bool deep) BArchiver::AddArchivable(const char* name, BArchivable* archivable, bool deep)
{ {
int32 token; int32 token;
status_t err = GetTokenForArchivable(archivable, token, deep); status_t err = GetTokenForArchivable(archivable, deep, token);
if (err != B_OK) if (err != B_OK)
return err; return err;
@@ -332,17 +336,9 @@ BArchiver::AddArchivable(const char* name, BArchivable* archivable, bool deep)
status_t status_t
BArchiver::GetTokenForArchivable(BArchivable* archivable, BArchiver::GetTokenForArchivable(BArchivable* archivable,
int32& _token, bool deep) bool deep, int32& _token)
{ {
status_t err = B_OK; return fManager->ArchiveObject(archivable, deep, _token);
if (!IsArchived(archivable))
err = fManager->ArchiveObject(archivable, deep);
if (err == B_OK)
return fManager->GetTokenForArchivable(archivable, _token);
return err;
} }
@@ -354,13 +350,14 @@ BArchiver::IsArchived(BArchivable* archivable)
status_t status_t
BArchiver::Finish() BArchiver::Finish(status_t err)
{ {
if (fFinished) if (fFinished)
debugger("Finish() called multiple times on same BArchiver."); debugger("Finish() called multiple times on same BArchiver.");
fFinished = true; fFinished = true;
return fManager->ArchiverLeaving(this);
return fManager->ArchiverLeaving(this, err);
} }
@@ -393,56 +390,32 @@ BUnarchiver::BUnarchiver(const BMessage* archive)
BUnarchiver::~BUnarchiver() BUnarchiver::~BUnarchiver()
{ {
if (!fFinished && fManager) if (!fFinished && fManager)
fManager->UnarchiverLeaving(this); fManager->UnarchiverLeaving(this, B_OK);
} }
template<>
status_t status_t
BUnarchiver::GetArchivable(int32 token, BArchivable** archivable) BUnarchiver::GetObject<BArchivable>(int32 token,
ownership_policy owning, BArchivable*& object)
{ {
_CallDebuggerIfManagerNull(); _CallDebuggerIfManagerNull();
return fManager->GetArchivableForToken(token, owning, object);
if (archivable == NULL)
return B_BAD_VALUE;
return fManager->ArchivableForToken(archivable, token);
} }
template<>
status_t status_t
BUnarchiver::FindArchivable(const char* name, BArchivable** archivable) BUnarchiver::FindObject<BArchivable>(const char* name,
int32 index, ownership_policy owning, BArchivable*& archivable)
{ {
return FindArchivable(name, 0, archivable); archivable = NULL;
}
status_t
BUnarchiver::FindArchivable(const char* name,
int32 index, BArchivable** archivable)
{
int32 token; int32 token;
status_t err = fArchive->FindInt32(name, index, &token); status_t err = fArchive->FindInt32(name, index, &token);
if (err != B_OK) if (err != B_OK)
return err; return err;
return GetArchivable(token, archivable); return GetObject(token, owning, archivable);
}
status_t
BUnarchiver::EnsureUnarchived(const char* name, int32 index)
{
BArchivable* dummy;
return FindArchivable(name, index, &dummy);
}
status_t
BUnarchiver::EnsureUnarchived(int32 token)
{
BArchivable* dummy;
return GetArchivable(token, &dummy);
} }
@@ -452,6 +425,7 @@ BUnarchiver::IsInstantiated(int32 token)
return fManager->IsInstantiated(token); return fManager->IsInstantiated(token);
} }
bool bool
BUnarchiver::IsInstantiated(const char* field, int32 index) BUnarchiver::IsInstantiated(const char* field, int32 index)
{ {
@@ -461,14 +435,18 @@ BUnarchiver::IsInstantiated(const char* field, int32 index)
return false; return false;
} }
status_t status_t
BUnarchiver::Finish() BUnarchiver::Finish(status_t err)
{ {
if (fFinished) if (fFinished)
debugger("Finish() called multiple times on same BArchiver."); debugger("Finish() called multiple times on same BArchiver.");
fFinished = true; fFinished = true;
return fManager->UnarchiverLeaving(this); if (fManager)
return fManager->UnarchiverLeaving(this, err);
else
return B_OK;
} }
@@ -479,6 +457,22 @@ BUnarchiver::ArchiveMessage() const
} }
void
BUnarchiver::AssumeOwnership(BArchivable* archivable)
{
_CallDebuggerIfManagerNull();
fManager->AssumeOwnership(archivable);
}
void
BUnarchiver::RelinquishOwnership(BArchivable* archivable)
{
_CallDebuggerIfManagerNull();
fManager->RelinquishOwnership(archivable);
}
bool bool
BUnarchiver::IsArchiveManaged(BMessage* archive) BUnarchiver::IsArchiveManaged(BMessage* archive)
{ {
@@ -487,14 +481,25 @@ BUnarchiver::IsArchiveManaged(BMessage* archive)
return true; return true;
// managed top level archives return here // managed top level archives return here
int32 dummy; bool dummy;
if (archive->FindInt32(kArchiveCountField, &dummy) == B_OK) if (archive->FindBool(kManagedField, &dummy) == B_OK)
return true; return true;
return false; return false;
} }
template<>
status_t
BUnarchiver::InstantiateObject<BArchivable>(BMessage* from,
BArchivable*& object)
{
BUnarchiver unarchiver(BUnarchiver::PrepareArchive(from));
object = instantiate_object(from);
return unarchiver.Finish();
}
BMessage* BMessage*
BUnarchiver::PrepareArchive(BMessage*& archive) BUnarchiver::PrepareArchive(BMessage*& archive)
{ {
+123 -65
View File
@@ -6,18 +6,16 @@
* Alex Wilson (yourpalal2@gmail.com) * Alex Wilson (yourpalal2@gmail.com)
*/ */
#include "ArchivingManagers.h"
#include <syslog.h> #include <syslog.h>
#include <typeinfo> #include <typeinfo>
#include "ArchivingManagers.h"
namespace BPrivate { namespace BPrivate {
namespace Archiving { namespace Archiving {
const char* kArchiveCountField = "_managed_archive_count";
const char* kArchivableField = "_managed_archivable"; const char* kArchivableField = "_managed_archivable";
const char* kTokenField = "_managed_token"; const char* kManagedField = "_managed_archive";
} }
} }
@@ -50,7 +48,7 @@ BManagerBase::UnarchiveManager(const BMessage* archive)
if (manager->fType == UNARCHIVE_MANAGER) if (manager->fType == UNARCHIVE_MANAGER)
return static_cast<BUnarchiveManager*>(manager); return static_cast<BUnarchiveManager*>(manager);
debugger("More calls to BUnarchiver::PrepareMessage()" debugger("More calls to BUnarchiver::PrepareArchive()"
" than BUnarchivers created."); " than BUnarchivers created.");
return NULL; return NULL;
@@ -84,14 +82,15 @@ BArchiveManager::BArchiveManager(const BArchiver* creator)
: :
BManagerBase(creator->ArchiveMessage(), BManagerBase::ARCHIVE_MANAGER), BManagerBase(creator->ArchiveMessage(), BManagerBase::ARCHIVE_MANAGER),
fTokenMap(), fTokenMap(),
fCreator(creator) fCreator(creator),
fError(B_OK)
{ {
} }
BArchiveManager::~BArchiveManager() BArchiveManager::~BArchiveManager()
{ {
fTopLevelArchive->AddInt32(kArchiveCountField, fTokenMap.size()); fTopLevelArchive->AddBool(kManagedField, true);
} }
@@ -99,7 +98,7 @@ status_t
BArchiveManager::GetTokenForArchivable(BArchivable* archivable, int32& _token) BArchiveManager::GetTokenForArchivable(BArchivable* archivable, int32& _token)
{ {
if (!archivable) { if (!archivable) {
_token = -42; _token = NULL_TOKEN;
return B_OK; return B_OK;
} }
@@ -114,25 +113,32 @@ BArchiveManager::GetTokenForArchivable(BArchivable* archivable, int32& _token)
status_t status_t
BArchiveManager::ArchiveObject(BArchivable* archivable, bool deep) BArchiveManager::ArchiveObject(BArchivable* archivable,
bool deep, int32& _token)
{ {
if (IsArchived(archivable)){ if (!archivable) {
debugger("BArchivable requested to be archived" _token = NULL_TOKEN;
" was previously archived."); return B_OK;
} }
ArchiveInfo& info = fTokenMap[archivable]; ArchiveInfo& info = fTokenMap[archivable];
status_t err = B_OK;
if (!info.archive) {
info.archive = new BMessage(); info.archive = new BMessage();
info.token = fTokenMap.size() - 1; info.token = fTokenMap.size() - 1;
MarkArchive(info.archive); MarkArchive(info.archive);
status_t err = archivable->Archive(info.archive, deep); err = archivable->Archive(info.archive, deep);
}
if (err != B_OK) { if (err != B_OK) {
fTokenMap.erase(archivable); fTokenMap.erase(archivable);
// info.archive gets deleted here // info.archive gets deleted here
} _token = NULL_TOKEN;
} else
_token = info.token;
return err; return err;
} }
@@ -149,9 +155,12 @@ BArchiveManager::IsArchived(BArchivable* archivable)
status_t status_t
BArchiveManager::ArchiverLeaving(const BArchiver* archiver) BArchiveManager::ArchiverLeaving(const BArchiver* archiver, status_t err)
{ {
if (archiver == fCreator) { if (fError == B_OK)
fError = err;
if (archiver == fCreator && fError == B_OK) {
// first, we must sort the objects into the order they were archived in // first, we must sort the objects into the order they were archived in
typedef std::pair<BMessage*, const BArchivable*> ArchivePair; typedef std::pair<BMessage*, const BArchivable*> ArchivePair;
ArchivePair pairs[fTokenMap.size()]; ArchivePair pairs[fTokenMap.size()];
@@ -167,29 +176,28 @@ BArchiveManager::ArchiverLeaving(const BArchiver* archiver)
info.archive = NULL; info.archive = NULL;
} }
status_t err = B_ERROR;
int32 count = fTokenMap.size(); int32 count = fTokenMap.size();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
const ArchivePair& pair = pairs[i]; const ArchivePair& pair = pairs[i];
err = pair.second->AllArchived(pair.first); fError = pair.second->AllArchived(pair.first);
if (err == B_OK && i > 0) { if (fError == B_OK && i > 0) {
err = fTopLevelArchive->AddMessage(kArchivableField, fError = fTopLevelArchive->AddMessage(kArchivableField,
pair.first); pair.first);
} }
if (err != B_OK) { if (fError != B_OK) {
syslog(LOG_ERR, "AllArchived failed for object of type %s.", syslog(LOG_ERR, "AllArchived failed for object of type %s.",
typeid(*pairs[i].second).name()); typeid(*pairs[i].second).name());
break; break;
} }
} }
delete this;
return err;
} }
return B_OK; if (archiver == fCreator)
delete this;
return fError;
} }
@@ -211,7 +219,8 @@ struct BUnarchiveManager::ArchiveInfo {
ArchiveInfo() ArchiveInfo()
: :
archivable(NULL), archivable(NULL),
archive() archive(),
adopted(false)
{ {
} }
@@ -223,6 +232,7 @@ struct BUnarchiveManager::ArchiveInfo {
BArchivable* archivable; BArchivable* archivable;
BMessage archive; BMessage archive;
bool adopted;
}; };
@@ -235,9 +245,12 @@ BUnarchiveManager::BUnarchiveManager(BMessage* archive)
fObjects(NULL), fObjects(NULL),
fObjectCount(0), fObjectCount(0),
fTokenInProgress(0), fTokenInProgress(0),
fRefCount(0) fRefCount(0),
fError(B_OK)
{ {
archive->FindInt32(kArchiveCountField, &fObjectCount); archive->GetInfo(kArchivableField, NULL, &fObjectCount);
fObjectCount++;
// root object needs a spot too
fObjects = new ArchiveInfo[fObjectCount]; fObjects = new ArchiveInfo[fObjectCount];
// fObjects[0] is a placeholder for the object that started // fObjects[0] is a placeholder for the object that started
@@ -260,28 +273,37 @@ BUnarchiveManager::~BUnarchiveManager()
status_t status_t
BUnarchiveManager::ArchivableForToken(BArchivable** _archivable, int32 token) BUnarchiveManager::GetArchivableForToken(int32 token,
BUnarchiver::ownership_policy owning, BArchivable*& _archivable)
{ {
if (!_archivable || token > fObjectCount) if (token >= fObjectCount)
return B_BAD_VALUE; return B_BAD_VALUE;
if (token < 0) { if (token < 0) {
*_archivable = NULL; _archivable = NULL;
return B_OK; return B_OK;
} }
status_t err = B_OK; status_t err = B_OK;
if (!fObjects[token].archivable) { ArchiveInfo& info = fObjects[token];
if (fRefCount > 0) if (!info.archivable) {
err = _InstantiateObjectForToken(token); if (fRefCount > 0) {
else { fTokenInProgress = token;
if(!instantiate_object(&info.archive))
err = B_ERROR;
} else {
syslog(LOG_ERR, "Object requested from AllUnarchived()" syslog(LOG_ERR, "Object requested from AllUnarchived()"
" was not previously instantiated"); " was not previously instantiated");
err = B_ERROR; err = B_ERROR;
} }
} }
*_archivable = fObjects[token].archivable; if (!info.adopted && owning == BUnarchiver::B_ASSUME_OWNERSHIP)
info.adopted = true;
else if (info.adopted && owning == BUnarchiver::B_ASSUME_OWNERSHIP)
debugger("Cannot assume ownership of an object that is already owned");
_archivable = info.archivable;
return err; return err;
} }
@@ -302,37 +324,84 @@ BUnarchiveManager::RegisterArchivable(BArchivable* archivable)
debugger("Cannot register NULL pointer"); debugger("Cannot register NULL pointer");
fObjects[fTokenInProgress].archivable = archivable; fObjects[fTokenInProgress].archivable = archivable;
archivable->fArchivingToken = fTokenInProgress;
} }
status_t status_t
BUnarchiveManager::UnarchiverLeaving(const BUnarchiver* unarchiver) BUnarchiveManager::UnarchiverLeaving(const BUnarchiver* unarchiver,
status_t err)
{ {
if (--fRefCount == 0) { if (--fRefCount >= 0 && fError == B_OK)
fRefCount = -1; fError = err;
// make sure we de not end up here again!
if (fRefCount != 0)
return fError;
if (fError == B_OK) {
BArchivable* archivable = fObjects[0].archivable; BArchivable* archivable = fObjects[0].archivable;
status_t err = archivable->AllUnarchived(fTopLevelArchive); if (archivable) {
fError = archivable->AllUnarchived(fTopLevelArchive);
for (int32 i = 1; i < fObjectCount; i++) { archivable->fArchivingToken = NULL_TOKEN;
if (err != B_OK)
break;
archivable = fObjects[i].archivable;
err = archivable->AllUnarchived(&fObjects[i].archive);
} }
if (err != B_OK) { for (int32 i = 1; i < fObjectCount && fError == B_OK; i++) {
syslog(LOG_ERR, "AllUnarchived failed for object of type %s.", archivable = fObjects[i].archivable;
typeid(*archivable).name()); if (archivable) {
fError = archivable->AllUnarchived(&fObjects[i].archive);
archivable->fArchivingToken = NULL_TOKEN;
}
}
if (fError != B_OK) {
syslog(LOG_ERR, "Error in AllUnarchived"
" method of object of type %s", typeid(*archivable).name());
}
}
if (fError != B_OK) {
syslog(LOG_ERR, "An error occured during unarchival, cleaning up.");
for (int32 i = 1; i < fObjectCount; i++) {
if (!fObjects[i].adopted)
delete fObjects[i].archivable;
}
} }
delete this; delete this;
return err; return fError;
} }
return B_OK;
void
BUnarchiveManager::RelinquishOwnership(BArchivable* archivable)
{
int32 token = NULL_TOKEN;
if (archivable)
token = archivable->fArchivingToken;
if (token < 0 || token >= fObjectCount
|| fObjects[token].archivable != archivable)
return;
fObjects[token].adopted = false;
}
void
BUnarchiveManager::AssumeOwnership(BArchivable* archivable)
{
int32 token = NULL_TOKEN;
if (archivable)
token = archivable->fArchivingToken;
if (token < 0 || token >= fObjectCount
|| fObjects[token].archivable != archivable)
return;
if (!fObjects[token].adopted)
fObjects[token].adopted = true;
else {
debugger("Cannot assume ownership of an object that is already owned");
}
} }
@@ -342,14 +411,3 @@ BUnarchiveManager::Acquire()
if (fRefCount >= 0) if (fRefCount >= 0)
fRefCount++; fRefCount++;
} }
status_t
BUnarchiveManager::_InstantiateObjectForToken(int32 token)
{
fTokenInProgress = token;
if(!instantiate_object(&fObjects[token].archive))
return B_ERROR;
return B_OK;
}
+17 -9
View File
@@ -15,12 +15,13 @@
#include <Archivable.h> #include <Archivable.h>
#define NULL_TOKEN -42
namespace BPrivate { namespace BPrivate {
namespace Archiving { namespace Archiving {
extern const char* kArchiveCountField; extern const char* kManagedField;
extern const char* kArchivableField;
extern const char* kTokenField;
class BManagerBase { class BManagerBase {
@@ -101,11 +102,13 @@ public:
int32& _token); int32& _token);
status_t ArchiveObject(BArchivable* archivable, status_t ArchiveObject(BArchivable* archivable,
bool deep); bool deep, int32& _token);
bool IsArchived(BArchivable* archivable); bool IsArchived(BArchivable* archivable);
status_t ArchiverLeaving(const BArchiver* archiver); status_t ArchiverLeaving(const BArchiver* archiver,
status_t err);
void Acquire(); void Acquire();
void RegisterArchivable( void RegisterArchivable(
const BArchivable* archivable); const BArchivable* archivable);
@@ -118,6 +121,7 @@ private:
TokenMap fTokenMap; TokenMap fTokenMap;
const BArchiver* fCreator; const BArchiver* fCreator;
status_t fError;
}; };
@@ -127,20 +131,23 @@ class BUnarchiveManager: public BManagerBase {
public: public:
BUnarchiveManager(BMessage* topLevelArchive); BUnarchiveManager(BMessage* topLevelArchive);
status_t ArchivableForToken(BArchivable** archivable, status_t GetArchivableForToken(int32 token,
int32 token); BUnarchiver::ownership_policy owning,
BArchivable*& _archivable);
bool IsInstantiated(int32 token); bool IsInstantiated(int32 token);
void RegisterArchivable(BArchivable* archivable); void RegisterArchivable(BArchivable* archivable);
status_t UnarchiverLeaving(const BUnarchiver* archiver); status_t UnarchiverLeaving(const BUnarchiver* archiver,
status_t err);
void Acquire(); void Acquire();
void RelinquishOwnership(BArchivable* archivable);
void AssumeOwnership(BArchivable* archivable);
private: private:
~BUnarchiveManager(); ~BUnarchiveManager();
status_t _ExtractArchiveAt(int32 index); status_t _ExtractArchiveAt(int32 index);
status_t _InstantiateObjectForToken(int32 token);
struct ArchiveInfo; struct ArchiveInfo;
@@ -148,6 +155,7 @@ private:
int32 fObjectCount; int32 fObjectCount;
int32 fTokenInProgress; int32 fTokenInProgress;
int32 fRefCount; int32 fRefCount;
status_t fError;
}; };