1/* 2 * Copyright 2010 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Alex Wilson, yourpalal2@gmail.com 7 */ 8 9 10#include "ArchivingManagers.h" 11 12#include <syslog.h> 13#include <typeinfo> 14 15#include <StackOrHeapArray.h> 16 17 18namespace BPrivate { 19namespace Archiving { 20 const char* kArchivableField = "_managed_archivable"; 21 const char* kManagedField = "_managed_archive"; 22} 23} 24 25 26using namespace BPrivate::Archiving; 27 28 29BArchiveManager* 30BManagerBase::ArchiveManager(const BMessage* archive) 31{ 32 BManagerBase* manager = ManagerPointer(archive); 33 if (!manager) 34 return NULL; 35 36 if (manager->fType == ARCHIVE_MANAGER) 37 return static_cast<BArchiveManager*>(manager); 38 39 debugger("Overlapping managed unarchive/archive sessions."); 40 return NULL; 41} 42 43 44BUnarchiveManager* 45BManagerBase::UnarchiveManager(const BMessage* archive) 46{ 47 BManagerBase* manager = ManagerPointer(archive); 48 if (!manager) 49 return NULL; 50 51 if (manager->fType == UNARCHIVE_MANAGER) 52 return static_cast<BUnarchiveManager*>(manager); 53 54 debugger("More calls to BUnarchiver::PrepareArchive()" 55 " than BUnarchivers created."); 56 57 return NULL; 58} 59 60 61// #pragma mark - 62 63 64struct BArchiveManager::ArchiveInfo { 65 ArchiveInfo() 66 : 67 token(-1), 68 archive(NULL) 69 { 70 } 71 72 73 ~ArchiveInfo() 74 { 75 delete archive; 76 } 77 78 79 int32 token; 80 BMessage* archive; 81}; 82 83 84BArchiveManager::BArchiveManager(const BArchiver* creator) 85 : 86 BManagerBase(creator->ArchiveMessage(), BManagerBase::ARCHIVE_MANAGER), 87 fTokenMap(), 88 fCreator(creator), 89 fError(B_OK) 90{ 91} 92 93 94BArchiveManager::~BArchiveManager() 95{ 96 fTopLevelArchive->AddBool(kManagedField, true); 97} 98 99 100status_t 101BArchiveManager::GetTokenForArchivable(BArchivable* archivable, int32& _token) 102{ 103 if (!archivable) { 104 _token = NULL_TOKEN; 105 return B_OK; 106 } 107 108 TokenMap::iterator it = fTokenMap.find(archivable); 109 110 if (it == fTokenMap.end()) 111 return B_ENTRY_NOT_FOUND; 112 113 _token = it->second.token; 114 return B_OK; 115} 116 117 118status_t 119BArchiveManager::ArchiveObject(BArchivable* archivable, 120 bool deep, int32& _token) 121{ 122 if (!archivable) { 123 _token = NULL_TOKEN; 124 return B_OK; 125 } 126 127 ArchiveInfo& info = fTokenMap[archivable]; 128 129 status_t err = B_OK; 130 131 if (!info.archive) { 132 info.archive = new BMessage(); 133 info.token = fTokenMap.size() - 1; 134 135 MarkArchive(info.archive); 136 err = archivable->Archive(info.archive, deep); 137 } 138 139 if (err != B_OK) { 140 fTokenMap.erase(archivable); 141 // info.archive gets deleted here 142 _token = NULL_TOKEN; 143 } else 144 _token = info.token; 145 146 return err; 147} 148 149 150bool 151BArchiveManager::IsArchived(BArchivable* archivable) 152{ 153 if (!archivable) 154 return true; 155 156 return fTokenMap.find(archivable) != fTokenMap.end(); 157} 158 159 160status_t 161BArchiveManager::ArchiverLeaving(const BArchiver* archiver, status_t err) 162{ 163 if (fError == B_OK) 164 fError = err; 165 166 if (archiver == fCreator && fError == B_OK) { 167 // first, we must sort the objects into the order they were archived in 168 typedef std::pair<BMessage*, const BArchivable*> ArchivePair; 169 BStackOrHeapArray<ArchivePair, 64> pairs(fTokenMap.size()); 170 171 for(TokenMap::iterator it = fTokenMap.begin(), end = fTokenMap.end(); 172 it != end; it++) { 173 ArchiveInfo& info = it->second; 174 pairs[info.token].first = info.archive; 175 pairs[info.token].second = it->first; 176 177 // make sure fTopLevelArchive isn't deleted 178 if (info.archive == fTopLevelArchive) 179 info.archive = NULL; 180 } 181 182 int32 count = fTokenMap.size(); 183 for (int32 i = 0; i < count; i++) { 184 const ArchivePair& pair = pairs[i]; 185 fError = pair.second->AllArchived(pair.first); 186 187 if (fError == B_OK && i > 0) { 188 fError = fTopLevelArchive->AddMessage(kArchivableField, 189 pair.first); 190 } 191 192 if (fError != B_OK) { 193 syslog(LOG_ERR, "AllArchived failed for object of type %s.", 194 typeid(*pairs[i].second).name()); 195 break; 196 } 197 } 198 } 199 200 status_t result = fError; 201 if (archiver == fCreator) 202 delete this; 203 204 return result; 205} 206 207 208void 209BArchiveManager::RegisterArchivable(const BArchivable* archivable) 210{ 211 if (fTokenMap.size() == 0) { 212 ArchiveInfo& info = fTokenMap[archivable]; 213 info.archive = fTopLevelArchive; 214 info.token = 0; 215 } 216} 217 218 219// #pragma mark - 220 221 222struct BUnarchiveManager::ArchiveInfo { 223 ArchiveInfo() 224 : 225 archivable(NULL), 226 archive(), 227 adopted(false) 228 { 229 } 230 231 bool 232 operator<(const ArchiveInfo& other) 233 { 234 return archivable < other.archivable; 235 } 236 237 BArchivable* archivable; 238 BMessage archive; 239 bool adopted; 240}; 241 242 243// #pragma mark - 244 245 246BUnarchiveManager::BUnarchiveManager(BMessage* archive) 247 : 248 BManagerBase(archive, BManagerBase::UNARCHIVE_MANAGER), 249 fObjects(NULL), 250 fObjectCount(0), 251 fTokenInProgress(0), 252 fRefCount(0), 253 fError(B_OK) 254{ 255 archive->GetInfo(kArchivableField, NULL, &fObjectCount); 256 fObjectCount++; 257 // root object needs a spot too 258 fObjects = new ArchiveInfo[fObjectCount]; 259 260 // fObjects[0] is a placeholder for the object that started 261 // this unarchiving session. 262 for (int32 i = 0; i < fObjectCount - 1; i++) { 263 BMessage* into = &fObjects[i + 1].archive; 264 status_t err = archive->FindMessage(kArchivableField, i, into); 265 MarkArchive(into); 266 267 if (err != B_OK) 268 syslog(LOG_ERR, "Failed to find managed archivable"); 269 } 270} 271 272 273BUnarchiveManager::~BUnarchiveManager() 274{ 275 delete[] fObjects; 276} 277 278 279status_t 280BUnarchiveManager::GetArchivableForToken(int32 token, 281 BUnarchiver::ownership_policy owning, BArchivable*& _archivable) 282{ 283 if (token >= fObjectCount) 284 return B_BAD_VALUE; 285 286 if (token < 0) { 287 _archivable = NULL; 288 return B_OK; 289 } 290 291 status_t err = B_OK; 292 ArchiveInfo& info = fObjects[token]; 293 if (!info.archivable) { 294 if (fRefCount > 0) { 295 fTokenInProgress = token; 296 if(!instantiate_object(&info.archive)) 297 err = B_ERROR; 298 } else { 299 syslog(LOG_ERR, "Object requested from AllUnarchived()" 300 " was not previously instantiated"); 301 err = B_ERROR; 302 } 303 } 304 305 if (owning == BUnarchiver::B_ASSUME_OWNERSHIP) 306 info.adopted = true; 307 308 _archivable = info.archivable; 309 return err; 310} 311 312 313bool 314BUnarchiveManager::IsInstantiated(int32 token) 315{ 316 if (token < 0 || token >= fObjectCount) 317 return false; 318 return fObjects[token].archivable; 319} 320 321 322void 323BUnarchiveManager::RegisterArchivable(BArchivable* archivable) 324{ 325 if (!archivable) 326 debugger("Cannot register NULL pointer"); 327 328 fObjects[fTokenInProgress].archivable = archivable; 329 archivable->fArchivingToken = fTokenInProgress; 330} 331 332 333status_t 334BUnarchiveManager::UnarchiverLeaving(const BUnarchiver* unarchiver, 335 status_t err) 336{ 337 if (--fRefCount >= 0 && fError == B_OK) 338 fError = err; 339 340 if (fRefCount != 0) 341 return fError; 342 343 if (fError == B_OK) { 344 BArchivable* archivable = fObjects[0].archivable; 345 if (archivable) { 346 fError = archivable->AllUnarchived(fTopLevelArchive); 347 archivable->fArchivingToken = NULL_TOKEN; 348 } 349 350 for (int32 i = 1; i < fObjectCount && fError == B_OK; i++) { 351 archivable = fObjects[i].archivable; 352 if (archivable) { 353 fError = archivable->AllUnarchived(&fObjects[i].archive); 354 archivable->fArchivingToken = NULL_TOKEN; 355 } 356 } 357 if (fError != B_OK) { 358 syslog(LOG_ERR, "Error in AllUnarchived" 359 " method of object of type %s", typeid(*archivable).name()); 360 } 361 } 362 363 if (fError != B_OK) { 364 syslog(LOG_ERR, "An error occured during unarchival, cleaning up."); 365 for (int32 i = 1; i < fObjectCount; i++) { 366 if (!fObjects[i].adopted) 367 delete fObjects[i].archivable; 368 } 369 } 370 371 status_t result = fError; 372 delete this; 373 return result; 374} 375 376 377void 378BUnarchiveManager::RelinquishOwnership(BArchivable* archivable) 379{ 380 int32 token = NULL_TOKEN; 381 if (archivable) 382 token = archivable->fArchivingToken; 383 384 if (token < 0 || token >= fObjectCount 385 || fObjects[token].archivable != archivable) 386 return; 387 388 fObjects[token].adopted = false; 389} 390 391 392void 393BUnarchiveManager::AssumeOwnership(BArchivable* archivable) 394{ 395 int32 token = NULL_TOKEN; 396 if (archivable) 397 token = archivable->fArchivingToken; 398 399 if (token < 0 || token >= fObjectCount 400 || fObjects[token].archivable != archivable) 401 return; 402 403 fObjects[token].adopted = true; 404} 405 406 407void 408BUnarchiveManager::Acquire() 409{ 410 if (fRefCount >= 0) 411 fRefCount++; 412} 413