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 15 namespace BPrivate { 16 namespace Archiving { 17 const char* kArchivableField = "_managed_archivable"; 18 const char* kManagedField = "_managed_archive"; 19 } 20 } 21 22 23 using namespace BPrivate::Archiving; 24 25 26 BArchiveManager* 27 BManagerBase::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 41 BUnarchiveManager* 42 BManagerBase::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 61 struct 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 81 BArchiveManager::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 91 BArchiveManager::~BArchiveManager() 92 { 93 fTopLevelArchive->AddBool(kManagedField, true); 94 } 95 96 97 status_t 98 BArchiveManager::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 115 status_t 116 BArchiveManager::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 147 bool 148 BArchiveManager::IsArchived(BArchivable* archivable) 149 { 150 if (!archivable) 151 return true; 152 153 return fTokenMap.find(archivable) != fTokenMap.end(); 154 } 155 156 157 status_t 158 BArchiveManager::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 if (archiver == fCreator) 198 delete this; 199 200 return fError; 201 } 202 203 204 void 205 BArchiveManager::RegisterArchivable(const BArchivable* archivable) 206 { 207 if (fTokenMap.size() == 0) { 208 ArchiveInfo& info = fTokenMap[archivable]; 209 info.archive = fTopLevelArchive; 210 info.token = 0; 211 } 212 } 213 214 215 // #pragma mark - 216 217 218 struct BUnarchiveManager::ArchiveInfo { 219 ArchiveInfo() 220 : 221 archivable(NULL), 222 archive(), 223 adopted(false) 224 { 225 } 226 227 bool 228 operator<(const ArchiveInfo& other) 229 { 230 return archivable < other.archivable; 231 } 232 233 BArchivable* archivable; 234 BMessage archive; 235 bool adopted; 236 }; 237 238 239 // #pragma mark - 240 241 242 BUnarchiveManager::BUnarchiveManager(BMessage* archive) 243 : 244 BManagerBase(archive, BManagerBase::UNARCHIVE_MANAGER), 245 fObjects(NULL), 246 fObjectCount(0), 247 fTokenInProgress(0), 248 fRefCount(0), 249 fError(B_OK) 250 { 251 archive->GetInfo(kArchivableField, NULL, &fObjectCount); 252 fObjectCount++; 253 // root object needs a spot too 254 fObjects = new ArchiveInfo[fObjectCount]; 255 256 // fObjects[0] is a placeholder for the object that started 257 // this unarchiving session. 258 for (int32 i = 0; i < fObjectCount - 1; i++) { 259 BMessage* into = &fObjects[i + 1].archive; 260 status_t err = archive->FindMessage(kArchivableField, i, into); 261 MarkArchive(into); 262 263 if (err != B_OK) 264 syslog(LOG_ERR, "Failed to find managed archivable"); 265 } 266 } 267 268 269 BUnarchiveManager::~BUnarchiveManager() 270 { 271 delete[] fObjects; 272 } 273 274 275 status_t 276 BUnarchiveManager::GetArchivableForToken(int32 token, 277 BUnarchiver::ownership_policy owning, BArchivable*& _archivable) 278 { 279 if (token >= fObjectCount) 280 return B_BAD_VALUE; 281 282 if (token < 0) { 283 _archivable = NULL; 284 return B_OK; 285 } 286 287 status_t err = B_OK; 288 ArchiveInfo& info = fObjects[token]; 289 if (!info.archivable) { 290 if (fRefCount > 0) { 291 fTokenInProgress = token; 292 if(!instantiate_object(&info.archive)) 293 err = B_ERROR; 294 } else { 295 syslog(LOG_ERR, "Object requested from AllUnarchived()" 296 " was not previously instantiated"); 297 err = B_ERROR; 298 } 299 } 300 301 if (!info.adopted && owning == BUnarchiver::B_ASSUME_OWNERSHIP) 302 info.adopted = true; 303 else if (info.adopted && owning == BUnarchiver::B_ASSUME_OWNERSHIP) 304 debugger("Cannot assume ownership of an object that is already owned"); 305 306 _archivable = info.archivable; 307 return err; 308 } 309 310 311 bool 312 BUnarchiveManager::IsInstantiated(int32 token) 313 { 314 if (token < 0 || token >= fObjectCount) 315 return false; 316 return fObjects[token].archivable; 317 } 318 319 320 void 321 BUnarchiveManager::RegisterArchivable(BArchivable* archivable) 322 { 323 if (!archivable) 324 debugger("Cannot register NULL pointer"); 325 326 fObjects[fTokenInProgress].archivable = archivable; 327 archivable->fArchivingToken = fTokenInProgress; 328 } 329 330 331 status_t 332 BUnarchiveManager::UnarchiverLeaving(const BUnarchiver* unarchiver, 333 status_t err) 334 { 335 if (--fRefCount >= 0 && fError == B_OK) 336 fError = err; 337 338 if (fRefCount != 0) 339 return fError; 340 341 if (fError == B_OK) { 342 BArchivable* archivable = fObjects[0].archivable; 343 if (archivable) { 344 fError = archivable->AllUnarchived(fTopLevelArchive); 345 archivable->fArchivingToken = NULL_TOKEN; 346 } 347 348 for (int32 i = 1; i < fObjectCount && fError == B_OK; i++) { 349 archivable = fObjects[i].archivable; 350 if (archivable) { 351 fError = archivable->AllUnarchived(&fObjects[i].archive); 352 archivable->fArchivingToken = NULL_TOKEN; 353 } 354 } 355 if (fError != B_OK) { 356 syslog(LOG_ERR, "Error in AllUnarchived" 357 " method of object of type %s", typeid(*archivable).name()); 358 } 359 } 360 361 if (fError != B_OK) { 362 syslog(LOG_ERR, "An error occured during unarchival, cleaning up."); 363 for (int32 i = 1; i < fObjectCount; i++) { 364 if (!fObjects[i].adopted) 365 delete fObjects[i].archivable; 366 } 367 } 368 369 delete this; 370 return fError; 371 } 372 373 374 void 375 BUnarchiveManager::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 389 void 390 BUnarchiveManager::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 if (!fObjects[token].adopted) 401 fObjects[token].adopted = true; 402 else { 403 debugger("Cannot assume ownership of an object that is already owned"); 404 } 405 } 406 407 408 void 409 BUnarchiveManager::Acquire() 410 { 411 if (fRefCount >= 0) 412 fRefCount++; 413 } 414