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
This commit is contained in:
parent
8fbd792dd8
commit
e5150e2847
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
23
headers/private/binary_compatibility/Support.h
Normal file
23
headers/private/binary_compatibility/Support.h
Normal file
@ -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 <binary_compatibility/Global.h>
|
||||
|
||||
|
||||
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_ */
|
@ -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;
|
||||
|
||||
|
@ -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 <Roster.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <binary_compatibility/Support.h>
|
||||
|
||||
#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() {}
|
||||
|
||||
|
||||
|
355
src/kits/support/ArchivingManagers.cpp
Normal file
355
src/kits/support/ArchivingManagers.cpp
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Alex Wilson (yourpalal2@gmail.com)
|
||||
*/
|
||||
|
||||
|
||||
#include <syslog.h>
|
||||
#include <typeinfo>
|
||||
|
||||
#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<BArchiveManager*>(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<BUnarchiveManager*>(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<BMessage*, const BArchivable*> 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;
|
||||
}
|
||||
|
150
src/kits/support/ArchivingManagers.h
Normal file
150
src/kits/support/ArchivingManagers.h
Normal file
@ -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 <map>
|
||||
|
||||
#include <String.h>
|
||||
#include <ObjectList.h>
|
||||
#include <MessagePrivate.h>
|
||||
|
||||
#include <Archivable.h>
|
||||
|
||||
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<BMessage*>(constArchive);
|
||||
|
||||
return static_cast<BManagerBase*>(
|
||||
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<const BArchivable*, ArchiveInfo> 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
|
@ -6,6 +6,7 @@ UsePrivateHeaders app interface media shared support ;
|
||||
|
||||
MergeObject <libbe>support_kit.o :
|
||||
Archivable.cpp
|
||||
ArchivingManagers.cpp
|
||||
Beep.cpp
|
||||
BlockCache.cpp
|
||||
ByteOrder.cpp
|
||||
|
Loading…
Reference in New Issue
Block a user