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