[haiku-commits] r37431 - in haiku/trunk: headers/os/app headers/os/support headers/private/app headers/private/binary_compatibility src/kits/app ...

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 8 Jul 2010 16:54:25 +0200 (CEST)

Author: bonefish
Date: 2010-07-08 16:54:25 +0200 (Thu, 08 Jul 2010)
New Revision: 37431
Changeset: http://dev.haiku-os.org/changeset/37431/haiku

Added:
   haiku/trunk/headers/private/binary_compatibility/Support.h
   haiku/trunk/src/kits/support/ArchivingManagers.cpp
   haiku/trunk/src/kits/support/ArchivingManagers.h
Modified:
   haiku/trunk/headers/os/app/Message.h
   haiku/trunk/headers/os/support/Archivable.h
   haiku/trunk/headers/private/app/MessagePrivate.h
   haiku/trunk/headers/private/binary_compatibility/Global.h
   haiku/trunk/src/kits/app/Message.cpp
   haiku/trunk/src/kits/support/Archivable.cpp
   haiku/trunk/src/kits/support/Jamfile
Log:
Patch by Alex Wilson (compilation fixes by myself): Extended the archiving/
unarchiving protocol to support archival of arbitrary object graphs.


Modified: haiku/trunk/headers/os/app/Message.h
===================================================================
--- haiku/trunk/headers/os/app/Message.h        2010-07-08 13:11:53 UTC (rev 
37430)
+++ haiku/trunk/headers/os/app/Message.h        2010-07-08 14:54:25 UTC (rev 
37431)
@@ -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,8 +320,10 @@
                BMessage*               fQueueLink;
                        // fQueueLink is used by BMessageQueue to build a 
linked list
 
-               uint32                  fReserved[9];
+               void*                   fArchivingPointer;
 
+               uint32                  fReserved[8];
+
                                                // deprecated
                                                BMessage(BMessage *message);
 

Modified: haiku/trunk/headers/os/support/Archivable.h
===================================================================
--- haiku/trunk/headers/os/support/Archivable.h 2010-07-08 13:11:53 UTC (rev 
37430)
+++ haiku/trunk/headers/os/support/Archivable.h 2010-07-08 14:54:25 UTC (rev 
37431)
@@ -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,34 +12,116 @@
 
 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;
+};
+
+
 // global functions
 
 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,

Modified: haiku/trunk/headers/private/app/MessagePrivate.h
===================================================================
--- haiku/trunk/headers/private/app/MessagePrivate.h    2010-07-08 13:11:53 UTC 
(rev 37430)
+++ haiku/trunk/headers/private/app/MessagePrivate.h    2010-07-08 14:54:25 UTC 
(rev 37431)
@@ -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 @@
                                reply, sendTimeout, replyTimeout);
                }
 
+
+               void*
+               ArchivingPointer()
+               {
+                       return fMessage->fArchivingPointer;
+               }
+
+
+               void
+               SetArchivingPointer(void* pointer)
+               {
+                       fMessage->fArchivingPointer = pointer;
+               }
+
                // static methods
 
                static status_t

Modified: haiku/trunk/headers/private/binary_compatibility/Global.h
===================================================================
--- haiku/trunk/headers/private/binary_compatibility/Global.h   2010-07-08 
13:11:53 UTC (rev 37430)
+++ haiku/trunk/headers/private/binary_compatibility/Global.h   2010-07-08 
14:54:25 UTC (rev 37431)
@@ -21,9 +21,12 @@
        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
 };
 
 

Added: haiku/trunk/headers/private/binary_compatibility/Support.h
===================================================================
--- haiku/trunk/headers/private/binary_compatibility/Support.h                  
        (rev 0)
+++ haiku/trunk/headers/private/binary_compatibility/Support.h  2010-07-08 
14:54:25 UTC (rev 37431)
@@ -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_ */

Modified: haiku/trunk/src/kits/app/Message.cpp
===================================================================
--- haiku/trunk/src/kits/app/Message.cpp        2010-07-08 13:11:53 UTC (rev 
37430)
+++ haiku/trunk/src/kits/app/Message.cpp        2010-07-08 14:54:25 UTC (rev 
37431)
@@ -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 @@
        fOriginal = NULL;
        fQueueLink = NULL;
 
+       fArchivingPointer = NULL;
+
        if (initHeader)
                return _InitHeader();
 
@@ -394,6 +396,8 @@
        free(fData);
        fData = NULL;
 
+       fArchivingPointer = NULL;
+
        fFieldsAvailable = 0;
        fDataAvailable = 0;
 

Modified: haiku/trunk/src/kits/support/Archivable.cpp
===================================================================
--- haiku/trunk/src/kits/support/Archivable.cpp 2010-07-08 13:11:53 UTC (rev 
37430)
+++ haiku/trunk/src/kits/support/Archivable.cpp 2010-07-08 14:54:25 UTC (rev 
37431)
@@ -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@xxxxxxxxxxxxxx)
+ *             Alex Wilson (yourpalal2@xxxxxxxxx)
  */
 
 /*!    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 @@
 
                        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 @@
 
                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(BMessage* from)
 {
+       if (BUnarchiver::IsArchiveManaged(from)) {
+               BUnarchiver::PrepareArchive(from);
+               BUnarchiver(from).RegisterArchivable(this);
+       }
 }
 
 
@@ -225,6 +236,9 @@
                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,19 +259,274 @@
 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 -
+
+
 BArchivable*
 instantiate_object(BMessage* archive, image_id* _id)
 {
@@ -475,3 +744,61 @@
        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() {}
+
+

Added: haiku/trunk/src/kits/support/ArchivingManagers.cpp
===================================================================
--- haiku/trunk/src/kits/support/ArchivingManagers.cpp                          
(rev 0)
+++ haiku/trunk/src/kits/support/ArchivingManagers.cpp  2010-07-08 14:54:25 UTC 
(rev 37431)
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2010, Haiku, Inc.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Alex Wilson (yourpalal2@xxxxxxxxx)
+ */
+
+
+#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");

[... truncated: 224 lines follow ...]

Other related posts:

  • » [haiku-commits] r37431 - in haiku/trunk: headers/os/app headers/os/support headers/private/app headers/private/binary_compatibility src/kits/app ... - ingo_weinhold