1 /* 2 * Copyright 2001-2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 3 * Copyright 2013 Haiku, Inc. 4 * All Rights Reserved. Distributed under the terms of the MIT License. 5 * 6 * Authors: 7 * John Scipione, jscipione@gmail.com 8 * Ingo Weinhold, bonefish@cs.tu-berlin.de 9 */ 10 11 12 #include <Resources.h> 13 14 #include <new> 15 #include <stdio.h> 16 #include <stdlib.h> 17 18 #include "ResourceFile.h" 19 #include "ResourceItem.h" 20 #include "ResourcesContainer.h" 21 22 23 using namespace BPrivate::Storage; 24 using namespace std; 25 26 27 // debugging 28 //#define DBG(x) x 29 #define DBG(x) 30 #define OUT printf 31 32 33 // Creates an unitialized BResources object. 34 BResources::BResources() 35 : 36 fFile(), 37 fContainer(NULL), 38 fResourceFile(NULL), 39 fReadOnly(false) 40 { 41 fContainer = new(nothrow) ResourcesContainer; 42 } 43 44 45 // Creates a BResources object that represents the resources of the 46 // supplied file. 47 BResources::BResources(const BFile* file, bool clobber) 48 : 49 fFile(), 50 fContainer(NULL), 51 fResourceFile(NULL), 52 fReadOnly(false) 53 { 54 fContainer = new(nothrow) ResourcesContainer; 55 SetTo(file, clobber); 56 } 57 58 59 // Creates a BResources object that represents the resources of the 60 // file referenced by the supplied path. 61 BResources::BResources(const char* path, bool clobber) 62 : 63 fFile(), 64 fContainer(NULL), 65 fResourceFile(NULL), 66 fReadOnly(false) 67 { 68 fContainer = new(nothrow) ResourcesContainer; 69 SetTo(path, clobber); 70 } 71 72 73 // Creates a BResources object that represents the resources of the 74 // file referenced by the supplied ref. 75 BResources::BResources(const entry_ref* ref, bool clobber) 76 : 77 fFile(), 78 fContainer(NULL), 79 fResourceFile(NULL), 80 fReadOnly(false) 81 { 82 fContainer = new(nothrow) ResourcesContainer; 83 SetTo(ref, clobber); 84 } 85 86 87 // Frees all resources associated with this object 88 BResources::~BResources() 89 { 90 Unset(); 91 delete fContainer; 92 } 93 94 95 // Initialized the BResources object to represent the resources of 96 // the supplied file. 97 status_t 98 BResources::SetTo(const BFile* file, bool clobber) 99 { 100 Unset(); 101 status_t error = B_OK; 102 if (file) { 103 error = file->InitCheck(); 104 if (error == B_OK) { 105 fFile = *file; 106 error = fFile.InitCheck(); 107 } 108 if (error == B_OK) { 109 fReadOnly = !fFile.IsWritable(); 110 fResourceFile = new(nothrow) ResourceFile; 111 if (fResourceFile) 112 error = fResourceFile->SetTo(&fFile, clobber); 113 else 114 error = B_NO_MEMORY; 115 } 116 if (error == B_OK) { 117 if (fContainer) 118 error = fResourceFile->InitContainer(*fContainer); 119 else 120 error = B_NO_MEMORY; 121 } 122 } 123 if (error != B_OK) { 124 delete fResourceFile; 125 fResourceFile = NULL; 126 if (fContainer) 127 fContainer->MakeEmpty(); 128 } 129 return error; 130 } 131 132 133 // Initialized the BResources object to represent the resources of 134 // the file referred to by the supplied path. 135 status_t 136 BResources::SetTo(const char* path, bool clobber) 137 { 138 if (!path) 139 return B_BAD_VALUE; 140 141 // open file 142 BFile file; 143 status_t error = file.SetTo(path, B_READ_WRITE); 144 if (error != B_OK && error != B_ENTRY_NOT_FOUND) 145 error = file.SetTo(path, B_READ_ONLY); 146 if (error != B_OK) { 147 Unset(); 148 return error; 149 } 150 151 // delegate the actual work 152 return SetTo(&file, clobber); 153 } 154 155 156 // Initialized the BResources object to represent the resources of the 157 // file referenced by the supplied ref. 158 status_t 159 BResources::SetTo(const entry_ref* ref, bool clobber) 160 { 161 if (!ref) 162 return B_BAD_VALUE; 163 164 // open file 165 BFile file; 166 status_t error = file.SetTo(ref, B_READ_WRITE); 167 if (error != B_OK && error != B_ENTRY_NOT_FOUND) 168 error = file.SetTo(ref, B_READ_ONLY); 169 if (error != B_OK) { 170 Unset(); 171 return error; 172 } 173 174 // delegate the actual work 175 return SetTo(&file, clobber); 176 } 177 178 179 // Initialized the BResources object to represent the resources of 180 // the file from which the specified image has been loaded. 181 status_t 182 BResources::SetToImage(image_id image, bool clobber) 183 { 184 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 185 // get an image info 186 image_info info; 187 status_t error = get_image_info(image, &info); 188 if (error != B_OK) { 189 Unset(); 190 return error; 191 } 192 193 // delegate the actual work 194 return SetTo(info.name, clobber); 195 #else // HAIKU_TARGET_PLATFORM_HAIKU 196 return B_NOT_SUPPORTED; 197 #endif 198 } 199 200 201 // Initialized the BResources object to represent the resources of 202 // the file from which the specified pointer has been loaded. 203 status_t 204 BResources::SetToImage(const void* codeOrDataPointer, bool clobber) 205 { 206 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 207 // iterate through the images and find the one in question 208 addr_t address = (addr_t)codeOrDataPointer; 209 image_info info; 210 int32 cookie = 0; 211 212 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 213 if (address == 0 214 ? info.type == B_APP_IMAGE 215 : (((addr_t)info.text <= address 216 && address - (addr_t)info.text < (addr_t)info.text_size) 217 || ((addr_t)info.data <= address 218 && address - (addr_t)info.data < (addr_t)info.data_size))) { 219 return SetTo(info.name, clobber); 220 } 221 } 222 223 return B_ENTRY_NOT_FOUND; 224 #else // HAIKU_TARGET_PLATFORM_HAIKU 225 return B_NOT_SUPPORTED; 226 #endif 227 } 228 229 230 // Returns the BResources object to an uninitialized state. 231 void 232 BResources::Unset() 233 { 234 if (fContainer && fContainer->IsModified()) 235 Sync(); 236 delete fResourceFile; 237 fResourceFile = NULL; 238 fFile.Unset(); 239 if (fContainer) 240 fContainer->MakeEmpty(); 241 else 242 fContainer = new(nothrow) ResourcesContainer; 243 fReadOnly = false; 244 } 245 246 247 // Gets the initialization status of the object. 248 status_t 249 BResources::InitCheck() const 250 { 251 return (fContainer ? B_OK : B_NO_MEMORY); 252 } 253 254 255 // Gets a reference to the internal BFile object. 256 const BFile& 257 BResources::File() const 258 { 259 return fFile; 260 } 261 262 263 // Loads a resource identified by type and id into memory. 264 const void* 265 BResources::LoadResource(type_code type, int32 id, size_t* _size) 266 { 267 // find the resource 268 status_t error = InitCheck(); 269 ResourceItem* resource = NULL; 270 if (error == B_OK) { 271 resource = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 272 if (!resource) 273 error = B_ENTRY_NOT_FOUND; 274 } 275 // load it, if necessary 276 if (error == B_OK && !resource->IsLoaded() && fResourceFile) 277 error = fResourceFile->ReadResource(*resource); 278 // return the result 279 const void *result = NULL; 280 if (error == B_OK) { 281 result = resource->Data(); 282 if (_size) 283 *_size = resource->DataSize(); 284 } 285 return result; 286 } 287 288 289 // Loads a resource identified by type and name into memory. 290 const void* 291 BResources::LoadResource(type_code type, const char* name, size_t* _size) 292 { 293 // find the resource 294 status_t error = InitCheck(); 295 ResourceItem* resource = NULL; 296 if (error == B_OK) { 297 resource = fContainer->ResourceAt(fContainer->IndexOf(type, name)); 298 if (!resource) 299 error = B_ENTRY_NOT_FOUND; 300 } 301 // load it, if necessary 302 if (error == B_OK && !resource->IsLoaded() && fResourceFile) 303 error = fResourceFile->ReadResource(*resource); 304 // return the result 305 const void* result = NULL; 306 if (error == B_OK) { 307 result = resource->Data(); 308 if (_size) 309 *_size = resource->DataSize(); 310 } 311 return result; 312 } 313 314 315 // Loads all resources of the specified type into memory. 316 status_t 317 BResources::PreloadResourceType(type_code type) 318 { 319 status_t error = InitCheck(); 320 if (error == B_OK && fResourceFile) { 321 if (type == 0) 322 error = fResourceFile->ReadResources(*fContainer); 323 else { 324 int32 count = fContainer->CountResources(); 325 int32 errorCount = 0; 326 for (int32 i = 0; i < count; i++) { 327 ResourceItem *resource = fContainer->ResourceAt(i); 328 if (resource->Type() == type) { 329 if (fResourceFile->ReadResource(*resource) != B_OK) 330 errorCount++; 331 } 332 } 333 error = -errorCount; 334 } 335 } 336 return error; 337 } 338 339 340 // Writes all changes to the resources to the file. 341 status_t 342 BResources::Sync() 343 { 344 status_t error = InitCheck(); 345 if (error == B_OK) 346 error = fFile.InitCheck(); 347 if (error == B_OK) { 348 if (fReadOnly) 349 error = B_NOT_ALLOWED; 350 else if (!fResourceFile) 351 error = B_FILE_ERROR; 352 } 353 if (error == B_OK) 354 error = fResourceFile->ReadResources(*fContainer); 355 if (error == B_OK) 356 error = fResourceFile->WriteResources(*fContainer); 357 return error; 358 } 359 360 361 // Adds the resources of fromFile to the internal file of the 362 // BResources object. 363 status_t 364 BResources::MergeFrom(BFile* fromFile) 365 { 366 status_t error = (fromFile ? B_OK : B_BAD_VALUE); 367 if (error == B_OK) 368 error = InitCheck(); 369 if (error == B_OK) { 370 ResourceFile resourceFile; 371 error = resourceFile.SetTo(fromFile); 372 ResourcesContainer container; 373 if (error == B_OK) 374 error = resourceFile.InitContainer(container); 375 if (error == B_OK) 376 error = resourceFile.ReadResources(container); 377 if (error == B_OK) 378 fContainer->AssimilateResources(container); 379 } 380 return error; 381 } 382 383 384 // Writes the resources to a new file. 385 status_t 386 BResources::WriteTo(BFile* file) 387 { 388 status_t error = (file ? B_OK : B_BAD_VALUE); 389 if (error == B_OK) 390 error = InitCheck(); 391 // make sure, that all resources are loaded 392 if (error == B_OK && fResourceFile) { 393 error = fResourceFile->ReadResources(*fContainer); 394 fResourceFile->Unset(); 395 } 396 // set the new file, but keep the old container 397 if (error == B_OK) { 398 ResourcesContainer *container = fContainer; 399 fContainer = new(nothrow) ResourcesContainer; 400 if (fContainer) { 401 error = SetTo(file, false); 402 delete fContainer; 403 } else 404 error = B_NO_MEMORY; 405 fContainer = container; 406 } 407 // write the resources 408 if (error == B_OK && fResourceFile) 409 error = fResourceFile->WriteResources(*fContainer); 410 return error; 411 } 412 413 414 // Adds a new resource to the file. 415 status_t 416 BResources::AddResource(type_code type, int32 id, const void* data, 417 size_t length, const char* name) 418 { 419 status_t error = (data ? B_OK : B_BAD_VALUE); 420 if (error == B_OK) 421 error = InitCheck(); 422 if (error == B_OK) 423 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 424 if (error == B_OK) { 425 ResourceItem* item = new(nothrow) ResourceItem; 426 if (!item) 427 error = B_NO_MEMORY; 428 if (error == B_OK) { 429 item->SetIdentity(type, id, name); 430 ssize_t written = item->WriteAt(0, data, length); 431 if (written < 0) 432 error = written; 433 else if (written != (ssize_t)length) 434 error = B_ERROR; 435 } 436 if (error == B_OK) { 437 if (!fContainer->AddResource(item)) 438 error = B_NO_MEMORY; 439 } 440 if (error != B_OK) 441 delete item; 442 } 443 return error; 444 } 445 446 447 // Returns whether the file contains a resource with the specified 448 // type and id. 449 bool 450 BResources::HasResource(type_code type, int32 id) 451 { 452 return (InitCheck() == B_OK && fContainer->IndexOf(type, id) >= 0); 453 } 454 455 456 // Returns whether the file contains a resource with the specified 457 // type and name. 458 bool 459 BResources::HasResource(type_code type, const char* name) 460 { 461 return (InitCheck() == B_OK && fContainer->IndexOf(type, name) >= 0); 462 } 463 464 465 // Gets information about a resource identified by byindex. 466 bool 467 BResources::GetResourceInfo(int32 byIndex, type_code* typeFound, 468 int32* idFound, const char** nameFound, size_t* lengthFound) 469 { 470 ResourceItem* item = NULL; 471 if (InitCheck() == B_OK) 472 item = fContainer->ResourceAt(byIndex); 473 if (item) { 474 if (typeFound) 475 *typeFound = item->Type(); 476 if (idFound) 477 *idFound = item->ID(); 478 if (nameFound) 479 *nameFound = item->Name(); 480 if (lengthFound) 481 *lengthFound = item->DataSize(); 482 } 483 return item; 484 } 485 486 487 // Gets information about a resource identified by byType and andIndex. 488 bool 489 BResources::GetResourceInfo(type_code byType, int32 andIndex, int32* idFound, 490 const char** nameFound, size_t* lengthFound) 491 { 492 ResourceItem* item = NULL; 493 if (InitCheck() == B_OK) { 494 item = fContainer->ResourceAt(fContainer->IndexOfType(byType, 495 andIndex)); 496 } 497 if (item) { 498 if (idFound) 499 *idFound = item->ID(); 500 if (nameFound) 501 *nameFound = item->Name(); 502 if (lengthFound) 503 *lengthFound = item->DataSize(); 504 } 505 return item; 506 } 507 508 509 // Gets information about a resource identified by byType and andID. 510 bool 511 BResources::GetResourceInfo(type_code byType, int32 andID, 512 const char** nameFound, size_t* lengthFound) 513 { 514 ResourceItem* item = NULL; 515 if (InitCheck() == B_OK) 516 item = fContainer->ResourceAt(fContainer->IndexOf(byType, andID)); 517 if (item) { 518 if (nameFound) 519 *nameFound = item->Name(); 520 if (lengthFound) 521 *lengthFound = item->DataSize(); 522 } 523 return item; 524 } 525 526 527 // Gets information about a resource identified by byType and andName. 528 bool 529 BResources::GetResourceInfo(type_code byType, const char* andName, 530 int32* idFound, size_t* lengthFound) 531 { 532 ResourceItem* item = NULL; 533 if (InitCheck() == B_OK) 534 item = fContainer->ResourceAt(fContainer->IndexOf(byType, andName)); 535 if (item) { 536 if (idFound) 537 *idFound = item->ID(); 538 if (lengthFound) 539 *lengthFound = item->DataSize(); 540 } 541 return item; 542 } 543 544 545 // Gets information about a resource identified by byPointer. 546 bool 547 BResources::GetResourceInfo(const void* byPointer, type_code* typeFound, 548 int32* idFound, size_t* lengthFound, const char** nameFound) 549 { 550 ResourceItem* item = NULL; 551 if (InitCheck() == B_OK) 552 item = fContainer->ResourceAt(fContainer->IndexOf(byPointer)); 553 if (item) { 554 if (typeFound) 555 *typeFound = item->Type(); 556 if (idFound) 557 *idFound = item->ID(); 558 if (nameFound) 559 *nameFound = item->Name(); 560 if (lengthFound) 561 *lengthFound = item->DataSize(); 562 } 563 return item; 564 } 565 566 567 // Removes a resource identified by its data pointer. 568 status_t 569 BResources::RemoveResource(const void* resource) 570 { 571 status_t error = (resource ? B_OK : B_BAD_VALUE); 572 if (error == B_OK) 573 error = InitCheck(); 574 if (error == B_OK) 575 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 576 if (error == B_OK) { 577 ResourceItem* item 578 = fContainer->RemoveResource(fContainer->IndexOf(resource)); 579 if (item) 580 delete item; 581 else 582 error = B_BAD_VALUE; 583 } 584 return error; 585 } 586 587 588 // Removes a resource identified by type and id. 589 status_t 590 BResources::RemoveResource(type_code type, int32 id) 591 { 592 status_t error = InitCheck(); 593 if (error == B_OK) 594 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 595 if (error == B_OK) { 596 ResourceItem* item 597 = fContainer->RemoveResource(fContainer->IndexOf(type, id)); 598 if (item) 599 delete item; 600 else 601 error = B_BAD_VALUE; 602 } 603 return error; 604 } 605 606 607 // #pragma mark - deprecated methods 608 609 610 // Writes data into an existing resource 611 // (deprecated, use AddResource() instead). 612 status_t 613 BResources::WriteResource(type_code type, int32 id, const void* data, 614 off_t offset, size_t length) 615 { 616 status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE); 617 if (error == B_OK) 618 error = InitCheck(); 619 if (error == B_OK) 620 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 621 622 if (error != B_OK) 623 return error; 624 625 ResourceItem *item = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 626 if (!item) 627 return B_BAD_VALUE; 628 629 if (fResourceFile) { 630 error = fResourceFile->ReadResource(*item); 631 if (error != B_OK) 632 return error; 633 } 634 635 ssize_t written = item->WriteAt(offset, data, length); 636 637 if (written < 0) 638 error = written; 639 else if (written != (ssize_t)length) 640 error = B_ERROR; 641 642 return error; 643 } 644 645 646 // Reads data from an existing resource 647 // (deprecated, use LoadResource() instead). 648 status_t 649 BResources::ReadResource(type_code type, int32 id, void* data, off_t offset, 650 size_t length) 651 { 652 status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE); 653 if (error == B_OK) 654 error = InitCheck(); 655 ResourceItem* item = NULL; 656 if (error == B_OK) { 657 item = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 658 if (!item) 659 error = B_BAD_VALUE; 660 } 661 if (error == B_OK && fResourceFile) 662 error = fResourceFile->ReadResource(*item); 663 if (error == B_OK) { 664 if (item) { 665 ssize_t read = item->ReadAt(offset, data, length); 666 if (read < 0) 667 error = read; 668 } else 669 error = B_BAD_VALUE; 670 } 671 return error; 672 } 673 674 675 // Finds a resource by type and id and returns a pointer to a copy of 676 // its data (deprecated, use LoadResource() instead). 677 void* 678 BResources::FindResource(type_code type, int32 id, size_t* lengthFound) 679 { 680 void* result = NULL; 681 size_t size = 0; 682 const void* data = LoadResource(type, id, &size); 683 if (data != NULL) { 684 if ((result = malloc(size))) 685 memcpy(result, data, size); 686 } 687 if (lengthFound) 688 *lengthFound = size; 689 return result; 690 } 691 692 693 // Finds a resource by type and name and returns a pointer to a copy of 694 // its data (deprecated, use LoadResource() instead). 695 void* 696 BResources::FindResource(type_code type, const char* name, size_t* lengthFound) 697 { 698 void* result = NULL; 699 size_t size = 0; 700 const void *data = LoadResource(type, name, &size); 701 if (data != NULL) { 702 if ((result = malloc(size))) 703 memcpy(result, data, size); 704 } 705 if (lengthFound) 706 *lengthFound = size; 707 return result; 708 } 709 710 711 // FBC 712 void BResources::_ReservedResources1() {} 713 void BResources::_ReservedResources2() {} 714 void BResources::_ReservedResources3() {} 715 void BResources::_ReservedResources4() {} 716 void BResources::_ReservedResources5() {} 717 void BResources::_ReservedResources6() {} 718 void BResources::_ReservedResources7() {} 719 void BResources::_ReservedResources8() {} 720