From e5150e28472204582c41b3d3cd5b4eabdbef323e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 8 Jul 2010 14:54:25 +0000 Subject: [PATCH] Patch by Alex Wilson (compilation fixes by myself): Extended the archiving/ unarchiving protocol to support archival of arbitrary object graphs. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37431 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/app/Message.h | 6 +- headers/os/support/Archivable.h | 114 +++++- headers/private/app/MessagePrivate.h | 16 +- headers/private/binary_compatibility/Global.h | 5 +- .../private/binary_compatibility/Support.h | 23 ++ src/kits/app/Message.cpp | 6 +- src/kits/support/Archivable.cpp | 343 ++++++++++++++++- src/kits/support/ArchivingManagers.cpp | 355 ++++++++++++++++++ src/kits/support/ArchivingManagers.h | 150 ++++++++ src/kits/support/Jamfile | 1 + 10 files changed, 990 insertions(+), 29 deletions(-) create mode 100644 headers/private/binary_compatibility/Support.h create mode 100644 src/kits/support/ArchivingManagers.cpp create mode 100644 src/kits/support/ArchivingManagers.h diff --git a/headers/os/app/Message.h b/headers/os/app/Message.h index a58a21ca26..6b0ff2030a 100644 --- a/headers/os/app/Message.h +++ b/headers/os/app/Message.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009, Haiku Inc. All Rights Reserved. + * Copyright 2005-2010, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -320,7 +320,9 @@ class BMessage { BMessage* fQueueLink; // fQueueLink is used by BMessageQueue to build a linked list - uint32 fReserved[9]; + void* fArchivingPointer; + + uint32 fReserved[8]; // deprecated BMessage(BMessage *message); diff --git a/headers/os/support/Archivable.h b/headers/os/support/Archivable.h index fa8dc98f37..121b789c9a 100644 --- a/headers/os/support/Archivable.h +++ b/headers/os/support/Archivable.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2001-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _ARCHIVABLE_H @@ -12,25 +12,107 @@ class BMessage; +namespace BPrivate { +namespace Archiving { + class BArchiveManager; + class BUnarchiveManager; +} +} + +using BPrivate::Archiving::BArchiveManager; +using BPrivate::Archiving::BUnarchiveManager; + class BArchivable { - public: - BArchivable(BMessage* from); - BArchivable(); - virtual ~BArchivable(); +public: + BArchivable(BMessage* from); + BArchivable(); + virtual ~BArchivable(); - virtual status_t Archive(BMessage* into, bool deep = true) const; - static BArchivable* Instantiate(BMessage* archive); + virtual status_t Archive(BMessage* into, bool deep = true) const; + static BArchivable* Instantiate(BMessage* archive); - // Private or reserved - virtual status_t Perform(perform_code d, void* arg); + virtual status_t Perform(perform_code d, void* arg); - private: - virtual void _ReservedArchivable1(); - virtual void _ReservedArchivable2(); - virtual void _ReservedArchivable3(); + virtual status_t AllUnarchived(const BMessage* archive); + virtual status_t AllArchived(BMessage* archive) const; - uint32 _reserved[2]; +private: + virtual void _ReservedArchivable3(); + + uint32 _reserved[2]; +}; + + +class BArchiver { +public: + BArchiver(BMessage* archive); + ~BArchiver(); + + status_t AddArchivable(const char* name, + BArchivable* archivable, bool deep = true); + + status_t GetTokenForArchivable(BArchivable* archivable, + int32& _token, bool deep = true); + + bool IsArchived(BArchivable* archivable); + status_t Finish(); + BMessage* ArchiveMessage() const; + +private: + friend class BArchivable; + + BArchiver(); // not defined + BArchiver(const BArchiver&); // not defined + + void RegisterArchivable(const BArchivable* archivable); + + BArchiveManager* fManager; + BMessage* fArchive; + bool fFinished; +}; + + +class BUnarchiver { +public: + BUnarchiver(const BMessage* archive); + ~BUnarchiver(); + + status_t GetArchivable(int32 token, + BArchivable** archivable); + + status_t FindArchivable(const char* name, + BArchivable** archivable); + + status_t FindArchivable(const char* name, int32 index, + BArchivable** archivable); + + status_t EnsureUnarchived(const char* name, + int32 index = 0); + status_t EnsureUnarchived(int32 token); + + bool IsInstantiated(int32 token); + bool IsInstantiated(const char* name, + int32 index = 0); + + status_t Finish(); + const BMessage* ArchiveMessage() const; + + static bool IsArchiveManaged(BMessage* archive); + static BMessage* PrepareArchive(BMessage*& archive); +private: + friend class BArchivable; + + BUnarchiver(); // not defined + BUnarchiver(const BUnarchiver&); // not defined + + void RegisterArchivable(BArchivable* archivable); + + void _CallDebuggerIfManagerNull(); + + BUnarchiveManager* fManager; + const BMessage* fArchive; + bool fFinished; }; @@ -38,8 +120,8 @@ class BArchivable { typedef BArchivable* (*instantiation_func)(BMessage*); -BArchivable* instantiate_object(BMessage *from, image_id *id); -BArchivable* instantiate_object(BMessage *from); +BArchivable* instantiate_object(BMessage* from, image_id* id); +BArchivable* instantiate_object(BMessage* from); bool validate_instantiation(BMessage* from, const char* className); instantiation_func find_instantiation_func(const char* className, diff --git a/headers/private/app/MessagePrivate.h b/headers/private/app/MessagePrivate.h index bbc79217bb..fb79a2f275 100644 --- a/headers/private/app/MessagePrivate.h +++ b/headers/private/app/MessagePrivate.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009, Haiku Inc. All rights reserved. + * Copyright 2005-2010, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -191,6 +191,20 @@ class BMessage::Private { reply, sendTimeout, replyTimeout); } + + void* + ArchivingPointer() + { + return fMessage->fArchivingPointer; + } + + + void + SetArchivingPointer(void* pointer) + { + fMessage->fArchivingPointer = pointer; + } + // static methods static status_t diff --git a/headers/private/binary_compatibility/Global.h b/headers/private/binary_compatibility/Global.h index e8f30af980..b2897035e1 100644 --- a/headers/private/binary_compatibility/Global.h +++ b/headers/private/binary_compatibility/Global.h @@ -21,9 +21,12 @@ enum { PERFORM_CODE_SET_LAYOUT = 1006, PERFORM_CODE_INVALIDATE_LAYOUT = 1007, PERFORM_CODE_DO_LAYOUT = 1008, - PERFORM_CODE_GET_TOOL_TIP_AT = 1009 + PERFORM_CODE_GET_TOOL_TIP_AT = 1009, // support kit + + PERFORM_CODE_ALL_ARCHIVED = 1010, + PERFORM_CODE_ALL_UNARCHIVED = 1011 }; diff --git a/headers/private/binary_compatibility/Support.h b/headers/private/binary_compatibility/Support.h new file mode 100644 index 0000000000..5d8ae0a176 --- /dev/null +++ b/headers/private/binary_compatibility/Support.h @@ -0,0 +1,23 @@ +/* + * Copyright 2010, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _BINARY_COMPATIBILITY_SUPPORT_H +#define _BINARY_COMPATIBILITY_SUPPORT_H + + +#include + + +struct perform_data_all_unarchived { + const BMessage* archive; + status_t return_value; +}; + + +struct perform_data_all_archived { + BMessage* archive; + status_t return_value; +}; + +#endif /* _BINARY_COMPATIBILITY_INTERFACE_H_ */ diff --git a/src/kits/app/Message.cpp b/src/kits/app/Message.cpp index 40df985758..a2b6576162 100644 --- a/src/kits/app/Message.cpp +++ b/src/kits/app/Message.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009, Haiku Inc. All rights reserved. + * Copyright 2005-2010, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -333,6 +333,8 @@ BMessage::_InitCommon(bool initHeader) fOriginal = NULL; fQueueLink = NULL; + fArchivingPointer = NULL; + if (initHeader) return _InitHeader(); @@ -394,6 +396,8 @@ BMessage::_Clear() free(fData); fData = NULL; + fArchivingPointer = NULL; + fFieldsAvailable = 0; fDataAvailable = 0; diff --git a/src/kits/support/Archivable.cpp b/src/kits/support/Archivable.cpp index ace759fcde..82a44173b7 100644 --- a/src/kits/support/Archivable.cpp +++ b/src/kits/support/Archivable.cpp @@ -1,9 +1,10 @@ /* - * Copyright (c) 2001-2008, Haiku, Inc. + * Copyright (c) 2001-2010, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: * Erik Jaesler (erik@cgsoftware.com) + * Alex Wilson (yourpalal2@gmail.com) */ /*! BArchivable mix-in class defines the archiving protocol. @@ -29,10 +30,16 @@ #include #include +#include + +#include "ArchivingManagers.h" + using std::string; using std::vector; +using namespace BPrivate::Archiving; + const char* B_CLASS_FIELD = "class"; const char* B_ADD_ON_FIELD = "add_on"; const int32 FUNC_NAME_LEN = 1024; @@ -61,7 +68,7 @@ demangle_class_name(const char* name, BString& out) namespaceCount = strtoul(name, (char**)&name, 10); if (name[0] != '_') - return B_BAD_VALUE; + return B_BAD_VALUE; } else namespaceCount = name[0] - '0'; @@ -69,7 +76,7 @@ demangle_class_name(const char* name, BString& out) for (int i = 0; i < namespaceCount - 1; i++) { if (!isdigit(name[0])) - return B_BAD_VALUE; + return B_BAD_VALUE; int nameLength = strtoul(name, (char**)&name, 10); out.Append(name, nameLength); @@ -209,6 +216,10 @@ BArchivable::BArchivable() BArchivable::BArchivable(BMessage* from) { + if (BUnarchiver::IsArchiveManaged(from)) { + BUnarchiver::PrepareArchive(from); + BUnarchiver(from).RegisterArchivable(this); + } } @@ -225,6 +236,9 @@ BArchivable::Archive(BMessage* into, bool deep) const return B_BAD_VALUE; } + if (BManagerBase::ArchiveManager(into)) + BArchiver(into).RegisterArchivable(this); + BString name; status_t status = demangle_class_name(typeid(*this).name(), name); if (status != B_OK) @@ -245,14 +259,269 @@ BArchivable::Instantiate(BMessage* from) status_t BArchivable::Perform(perform_code d, void* arg) { - // TODO: Check against original - return B_ERROR; + switch (d) { + case PERFORM_CODE_ALL_UNARCHIVED: + { + perform_data_all_unarchived* data = + (perform_data_all_unarchived*)arg; + + data->return_value = BArchivable::AllUnarchived(data->archive); + return B_OK; + } + + case PERFORM_CODE_ALL_ARCHIVED: + { + perform_data_all_archived* data = + (perform_data_all_archived*)arg; + + data->return_value = BArchivable::AllArchived(data->archive); + return B_OK; + } + } + return B_NAME_NOT_FOUND; } -void BArchivable::_ReservedArchivable1() {} -void BArchivable::_ReservedArchivable2() {} -void BArchivable::_ReservedArchivable3() {} +status_t +BArchivable::AllUnarchived(const BMessage* archive) +{ + return B_OK; +} + + +status_t +BArchivable::AllArchived(BMessage* archive) const +{ + return B_OK; +} + +// #pragma mark - + +BArchiver::BArchiver(BMessage* archive) + : + fManager(BManagerBase::ArchiveManager(archive)), + fArchive(archive), + fFinished(false) +{ + if (!fManager) + fManager = new BArchiveManager(this); +} + + +BArchiver::~BArchiver() +{ + if (!fFinished) + fManager->ArchiverLeaving(this); +} + + +status_t +BArchiver::AddArchivable(const char* name, BArchivable* archivable, bool deep) +{ + int32 token; + status_t err = GetTokenForArchivable(archivable, token, deep); + + if (err != B_OK) + return err; + + return fArchive->AddInt32(name, token); +} + + +status_t +BArchiver::GetTokenForArchivable(BArchivable* archivable, + int32& _token, bool deep) +{ + status_t err = B_OK; + + if (!IsArchived(archivable)) + err = fManager->ArchiveObject(archivable, deep); + + if (err == B_OK) + return fManager->GetTokenForArchivable(archivable, _token); + + return err; +} + + +bool +BArchiver::IsArchived(BArchivable* archivable) +{ + return fManager->IsArchived(archivable); +} + + +status_t +BArchiver::Finish() +{ + if (fFinished) + debugger("Finish() called multiple times on same BArchiver."); + + fFinished = true; + return fManager->ArchiverLeaving(this); +} + + +BMessage* +BArchiver::ArchiveMessage() const +{ + return fArchive; +} + + +void +BArchiver::RegisterArchivable(const BArchivable* archivable) +{ + fManager->RegisterArchivable(archivable); +} + + +// #pragma mark - + + +BUnarchiver::BUnarchiver(const BMessage* archive) + : + fManager(BManagerBase::UnarchiveManager(archive)), + fArchive(archive), + fFinished(false) +{ +} + + +BUnarchiver::~BUnarchiver() +{ + if (!fFinished && fManager) + fManager->UnarchiverLeaving(this); +} + + +status_t +BUnarchiver::GetArchivable(int32 token, BArchivable** archivable) +{ + _CallDebuggerIfManagerNull(); + + if (archivable == NULL) + return B_BAD_VALUE; + + return fManager->ArchivableForToken(archivable, token); +} + + +status_t +BUnarchiver::FindArchivable(const char* name, BArchivable** archivable) +{ + return FindArchivable(name, 0, archivable); +} + + +status_t +BUnarchiver::FindArchivable(const char* name, + int32 index, BArchivable** archivable) +{ + + int32 token; + status_t err = fArchive->FindInt32(name, index, &token); + if (err != B_OK) + return err; + + return GetArchivable(token, 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); +} + + +bool +BUnarchiver::IsInstantiated(int32 token) +{ + return fManager->IsInstantiated(token); +} + +bool +BUnarchiver::IsInstantiated(const char* field, int32 index) +{ + int32 token; + if (fArchive->FindInt32(field, index, &token) == B_OK) + return IsInstantiated(token); + return false; +} + +status_t +BUnarchiver::Finish() +{ + if (fFinished) + debugger("Finish() called multiple times on same BArchiver."); + + fFinished = true; + return fManager->UnarchiverLeaving(this); +} + + +const BMessage* +BUnarchiver::ArchiveMessage() const +{ + return fArchive; +} + + +bool +BUnarchiver::IsArchiveManaged(BMessage* archive) +{ + // managed child archives will return here + if (BManagerBase::ManagerPointer(archive)) + return true; + + // managed top level archives return here + int32 dummy; + if (archive->FindInt32(kArchiveCountField, &dummy) == B_OK) + return true; + + return false; +} + + +BMessage* +BUnarchiver::PrepareArchive(BMessage*& archive) +{ + // this check allows PrepareArchive to be + // called on new or old-style archives + if (BUnarchiver::IsArchiveManaged(archive)) { + BUnarchiveManager* manager = BManagerBase::UnarchiveManager(archive); + if (!manager) + manager = new BUnarchiveManager(archive); + manager->Acquire(); + } + return archive; +} + + +void +BUnarchiver::RegisterArchivable(BArchivable* archivable) +{ + _CallDebuggerIfManagerNull(); + fManager->RegisterArchivable(archivable); +} + + +void +BUnarchiver::_CallDebuggerIfManagerNull() +{ + if (!fManager) + debugger("BUnarchiver used with legacy or unprepared archive."); +} // #pragma mark - @@ -475,3 +744,61 @@ find_instantiation_func(BMessage* archive) return find_instantiation_func(name, signature); } +// BArchivable binary compatability +#if __GNUC__ == 2 + +extern "C" status_t +_ReservedArchivable1__11BArchivable(BArchivable* archivable, + const BMessage* archive) +{ + // AllUnarchived + perform_data_all_unarchived performData; + performData.archive = archive; + + archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData); + return performData.return_value; +} + +extern "C" status_t +_ReservedArchivable2__11BArchivable(BArchivable* archivable, + BMessage* archive) +{ + // AllArchived + perform_data_all_archived performData; + performData.archive = archive; + + archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData); + return performData.return_value; +} + +#elif __GNUC__ > 2 + +extern "C" status_t +_ZN11BArchivable20_ReservedArchivable1Ev(BArchivable* archivable, + const BMessage* archive) +{ + // AllUnarchived + perform_data_all_unarchived performData; + performData.archive = archive; + + archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData); + return performData.return_value; +} + +extern "C" status_t +_ZN11BArchivable20_ReservedArchivable2Ev(BArchivable* archivable, + BMessage* archive) +{ + // AllArchived + perform_data_all_archived performData; + performData.archive = archive; + + archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData); + return performData.return_value; +} + +#endif // _GNUC__ > 2 + +void BArchivable::_ReservedArchivable3() {} + + diff --git a/src/kits/support/ArchivingManagers.cpp b/src/kits/support/ArchivingManagers.cpp new file mode 100644 index 0000000000..780d5e40f6 --- /dev/null +++ b/src/kits/support/ArchivingManagers.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2010, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alex Wilson (yourpalal2@gmail.com) + */ + + +#include +#include + +#include "ArchivingManagers.h" + + +namespace BPrivate { +namespace Archiving { + const char* kArchiveCountField = "_managed_archive_count"; + const char* kArchivableField = "_managed_archivable"; + const char* kTokenField = "_managed_token"; +} } + + +using namespace BPrivate::Archiving; + + +BArchiveManager* +BManagerBase::ArchiveManager(const BMessage* archive) +{ + BManagerBase* manager = ManagerPointer(archive); + if (!manager) + return NULL; + + if (manager->fType == ARCHIVE_MANAGER) + return static_cast(manager); + + debugger("Overlapping managed unarchive/archive sessions."); + return NULL; +} + + +BUnarchiveManager* +BManagerBase::UnarchiveManager(const BMessage* archive) +{ + BManagerBase* manager = ManagerPointer(archive); + if (!manager) + return NULL; + + if (manager->fType == UNARCHIVE_MANAGER) + return static_cast(manager); + + debugger("More calls to BUnarchiver::PrepareMessage()" + " than BUnarchivers created."); + + return NULL; +} + + +// #pragma mark - + + +struct BArchiveManager::ArchiveInfo { + ArchiveInfo() + : + token(-1), + archive(NULL) + { + } + + + ~ArchiveInfo() + { + delete archive; + } + + + int32 token; + BMessage* archive; +}; + + +BArchiveManager::BArchiveManager(const BArchiver* creator) + : + BManagerBase(creator->ArchiveMessage(), BManagerBase::ARCHIVE_MANAGER), + fTokenMap(), + fCreator(creator) +{ +} + + +BArchiveManager::~BArchiveManager() +{ + fTopLevelArchive->AddInt32(kArchiveCountField, fTokenMap.size()); +} + + +status_t +BArchiveManager::GetTokenForArchivable(BArchivable* archivable, int32& _token) +{ + if (!archivable) { + _token = -42; + return B_OK; + } + + TokenMap::iterator it = fTokenMap.find(archivable); + + if (it == fTokenMap.end()) + return B_ENTRY_NOT_FOUND; + + _token = it->second.token; + return B_OK; +} + +status_t +BArchiveManager::ArchiveObject(BArchivable* archivable, bool deep) +{ + if (IsArchived(archivable)){ + debugger("BArchivable requested to be archived" + " was previously archived."); + } + + ArchiveInfo& info = fTokenMap[archivable]; + + info.archive = new BMessage(); + info.token = fTokenMap.size() - 1; + + MarkArchive(info.archive); + status_t err = archivable->Archive(info.archive, deep); + + if (err != B_OK) + fTokenMap.erase(archivable); + // info.archive gets deleted here + + return err; +} + + +bool +BArchiveManager::IsArchived(BArchivable* archivable) +{ + if (!archivable) + return true; + + return (fTokenMap.find(archivable) != fTokenMap.end()); +} + + +status_t +BArchiveManager::ArchiverLeaving(const BArchiver* archiver) +{ + if (archiver == fCreator) { + + // first, we must sort the objects into the order they were archived in + typedef std::pair archivePair ; + archivePair pairs[fTokenMap.size()]; + + for(TokenMap::iterator it = fTokenMap.begin(), end = fTokenMap.end(); + it != end; it++) { + + ArchiveInfo& info = it->second; + pairs[info.token].first = info.archive; + pairs[info.token].second = it->first; + + // make sure fTopLevelArchive isn't deleted + if (info.archive == fTopLevelArchive) + info.archive = NULL; + } + + status_t err = B_ERROR; + int32 count = fTokenMap.size(); + for (int32 i = 0; i < count; i++) { + + const archivePair& pair = pairs[i]; + err = pair.second->AllArchived(pair.first); + + if (err == B_OK && i > 0) { + err = fTopLevelArchive->AddMessage(kArchivableField, + pair.first); + } + + if (err != B_OK) { + syslog(LOG_ERR, "AllArchived failed for object of type %s.", + typeid(*pairs[i].second).name()); + break; + } + } + + delete this; + return err; + } + + return B_OK; +} + + +void +BArchiveManager::RegisterArchivable(const BArchivable* archivable) +{ + if (fTokenMap.size() == 0) { + ArchiveInfo& info = fTokenMap[archivable]; + info.archive = fTopLevelArchive; + info.token = 0; + } +} + + +// #pragma mark - + + +struct BUnarchiveManager::ArchiveInfo { + ArchiveInfo() + : + archivable(NULL), + archive() + { + } + + bool + operator<(const ArchiveInfo& other) + { + return archivable < other.archivable; + } + + BArchivable* archivable; + BMessage archive; +}; + + +// #pragma mark - + +BUnarchiveManager::BUnarchiveManager(BMessage* archive) + : + BManagerBase(archive, BManagerBase::UNARCHIVE_MANAGER), + fObjects(NULL), + fObjectCount(0), + fTokenInProgress(0), + fRefCount(0) +{ + archive->FindInt32(kArchiveCountField, &fObjectCount); + fObjects = new ArchiveInfo[fObjectCount]; + + // fObjects[0] is a placeholder for the object that started + // this unarchiving session. + for (int32 i = 0; i < fObjectCount - 1; i++) { + BMessage* into = &fObjects[i + 1].archive; + status_t err = archive->FindMessage(kArchivableField, i, into); + MarkArchive(into); + + if (err != B_OK) + syslog(LOG_ERR, "Failed to find managed archivable"); + } +} + + +BUnarchiveManager::~BUnarchiveManager() +{ + delete[] fObjects; +} + + +status_t +BUnarchiveManager::ArchivableForToken(BArchivable** _archivable, int32 token) +{ + if (!_archivable || token > fObjectCount) + return B_BAD_VALUE; + + if (token < 0) { + *_archivable = NULL; + return B_OK; + } + + status_t err = B_OK; + if (!fObjects[token].archivable) { + if (fRefCount > 0) + err = _InstantiateObjectForToken(token); + else { + syslog(LOG_ERR, "Object requested from AllUnarchived()" + " was not previously instantiated"); + err = B_ERROR; + } + } + + *_archivable = fObjects[token].archivable; + return err; +} + + +bool +BUnarchiveManager::IsInstantiated(int32 token) +{ + if (token < 0 || token >= fObjectCount) + return false; + return fObjects[token].archivable; +} + + +void +BUnarchiveManager::RegisterArchivable(BArchivable* archivable) +{ + if (!archivable) + debugger("Cannot register NULL pointer"); + + fObjects[fTokenInProgress].archivable = archivable; +} + + +status_t +BUnarchiveManager::UnarchiverLeaving(const BUnarchiver* unarchiver) +{ + if (--fRefCount == 0) { + + fRefCount = -1; + // make sure we de not end up here again! + + BArchivable* archivable = fObjects[0].archivable; + status_t err = archivable->AllUnarchived(fTopLevelArchive); + + for (int32 i = 1; i < fObjectCount; i++) { + if (err != B_OK) + break; + + archivable = fObjects[i].archivable; + err = archivable->AllUnarchived(&fObjects[i].archive); + } + + if (err != B_OK) { + syslog(LOG_ERR, "AllUnarchived failed for object of type %s.", + typeid(*archivable).name()); + } + + delete this; + return err; + } + + return B_OK; +} + + +void +BUnarchiveManager::Acquire() +{ + if (fRefCount >= 0) + fRefCount++; +} + + +status_t +BUnarchiveManager::_InstantiateObjectForToken(int32 token) +{ + fTokenInProgress = token; + if(!instantiate_object(&fObjects[token].archive)) + return B_ERROR; + return B_OK; +} + diff --git a/src/kits/support/ArchivingManagers.h b/src/kits/support/ArchivingManagers.h new file mode 100644 index 0000000000..5d0bfa10ca --- /dev/null +++ b/src/kits/support/ArchivingManagers.h @@ -0,0 +1,150 @@ +/* + * Copyright 2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _ARCHIVING_MANAGERS_H +#define _ARCHIVING_MANAGERS_H + + +#include + +#include +#include +#include + +#include + +namespace BPrivate { +namespace Archiving { + +extern const char* kArchiveCountField; +extern const char* kArchivableField; +extern const char* kTokenField; + +class BManagerBase { +public: + enum manager_type { + ARCHIVE_MANAGER, + UNARCHIVE_MANAGER + }; + + BManagerBase(BMessage* topLevelArchive, manager_type type) + : + fTopLevelArchive(topLevelArchive), + fType(type) + { + MarkArchive(topLevelArchive); + } + + + static BManagerBase* + ManagerPointer(const BMessage* constArchive) + { + BMessage* archive = const_cast(constArchive); + + return static_cast( + BMessage::Private(archive).ArchivingPointer()); + } + + + static void + SetManagerPointer(BMessage* archive, BManagerBase* manager) + { + BMessage::Private(archive).SetArchivingPointer(manager); + } + + + void + MarkArchive(BMessage* archive) + { + BManagerBase* manager = ManagerPointer(archive); + if (manager != NULL) + debugger("Overlapping managed archiving/unarchiving sessions!"); + + SetManagerPointer(archive, this); + } + + + void + UnmarkArchive(BMessage* archive) + { + BManagerBase* manager = ManagerPointer(archive); + if (manager == this) + SetManagerPointer(archive, NULL); + else + debugger("Overlapping managed archiving/unarchiving sessions!"); + } + + + static BArchiveManager* ArchiveManager(const BMessage* archive); + static BUnarchiveManager* UnarchiveManager(const BMessage* archive); + +protected: + + ~BManagerBase() + { + UnmarkArchive(fTopLevelArchive); + } + BMessage* fTopLevelArchive; + manager_type fType; +}; + + +class BArchiveManager: public BManagerBase { +public: + BArchiveManager(const BArchiver* creator); + + status_t GetTokenForArchivable(BArchivable* archivable, + int32& _token); + + status_t ArchiveObject(BArchivable* archivable, bool deep); + + bool IsArchived(BArchivable* archivable); + + status_t ArchiverLeaving(const BArchiver* archiver); + void Acquire(); + void RegisterArchivable(const BArchivable* archivable); + +private: + ~BArchiveManager(); + + struct ArchiveInfo; + typedef std::map TokenMap; + + TokenMap fTokenMap; + const BArchiver* fCreator; +}; + + + + +class BUnarchiveManager: public BManagerBase { +public: + BUnarchiveManager(BMessage* topLevelArchive); + + status_t ArchivableForToken(BArchivable** archivable, + int32 token); + + bool IsInstantiated(int32 token); + + void RegisterArchivable(BArchivable* archivable); + status_t UnarchiverLeaving(const BUnarchiver* archiver); + void Acquire(); + +private: + ~BUnarchiveManager(); + status_t _ExtractArchiveAt(int32 index); + status_t _InstantiateObjectForToken(int32 token); + + struct ArchiveInfo; + ArchiveInfo* fObjects; + int32 fObjectCount; + int32 fTokenInProgress; + int32 fRefCount; +}; + + +} // namespace Archiving +} // namespace BPrivate + +#endif diff --git a/src/kits/support/Jamfile b/src/kits/support/Jamfile index 42bd958e41..119f7cd2d2 100644 --- a/src/kits/support/Jamfile +++ b/src/kits/support/Jamfile @@ -6,6 +6,7 @@ UsePrivateHeaders app interface media shared support ; MergeObject support_kit.o : Archivable.cpp + ArchivingManagers.cpp Beep.cpp BlockCache.cpp ByteOrder.cpp