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 18 namespace BPrivate { 19 namespace Archiving { 20 const char* kArchivableField = "_managed_archivable"; 21 const char* kManagedField = "_managed_archive"; 22 } 23 } 24 25 26 using namespace BPrivate::Archiving; 27 28 29 BArchiveManager* 30 BManagerBase::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 44 BUnarchiveManager* 45 BManagerBase::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 64 struct 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 84 BArchiveManager::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 94 BArchiveManager::~BArchiveManager() 95 { 96 fTopLevelArchive->AddBool(kManagedField, true); 97 } 98 99 100 status_t 101 BArchiveManager::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 118 status_t 119 BArchiveManager::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 150 bool 151 BArchiveManager::IsArchived(BArchivable* archivable) 152 { 153 if (!archivable) 154 return true; 155 156 return fTokenMap.find(archivable) != fTokenMap.end(); 157 } 158 159 160 status_t 161 BArchiveManager::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 208 void 209 BArchiveManager::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 222 struct 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 246 BUnarchiveManager::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 273 BUnarchiveManager::~BUnarchiveManager() 274 { 275 delete[] fObjects; 276 } 277 278 279 status_t 280 BUnarchiveManager::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 313 bool 314 BUnarchiveManager::IsInstantiated(int32 token) 315 { 316 if (token < 0 || token >= fObjectCount) 317 return false; 318 return fObjects[token].archivable; 319 } 320 321 322 void 323 BUnarchiveManager::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 333 status_t 334 BUnarchiveManager::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 377 void 378 BUnarchiveManager::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 392 void 393 BUnarchiveManager::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 407 void 408 BUnarchiveManager::Acquire() 409 { 410 if (fRefCount >= 0) 411 fRefCount++; 412 } 413