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 status_t result = fError; 198 if (archiver == fCreator) 199 delete this; 200 201 return result; 202 } 203 204 205 void 206 BArchiveManager::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 219 struct 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 243 BUnarchiveManager::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 270 BUnarchiveManager::~BUnarchiveManager() 271 { 272 delete[] fObjects; 273 } 274 275 276 status_t 277 BUnarchiveManager::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 310 bool 311 BUnarchiveManager::IsInstantiated(int32 token) 312 { 313 if (token < 0 || token >= fObjectCount) 314 return false; 315 return fObjects[token].archivable; 316 } 317 318 319 void 320 BUnarchiveManager::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 330 status_t 331 BUnarchiveManager::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 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 fObjects[token].adopted = true; 401 } 402 403 404 void 405 BUnarchiveManager::Acquire() 406 { 407 if (fRefCount >= 0) 408 fRefCount++; 409 } 410