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 if (!codeOrDataPointer) 208 return B_BAD_VALUE; 209 210 // iterate through the images and find the one in question 211 addr_t address = (addr_t)codeOrDataPointer; 212 image_info info; 213 int32 cookie = 0; 214 215 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 216 if (((addr_t)info.text <= address 217 && address - (addr_t)info.text < (addr_t)info.text_size) 218 || ((addr_t)info.data <= address 219 && address - (addr_t)info.data < (addr_t)info.data_size)) { 220 return SetTo(info.name, clobber); 221 } 222 } 223 224 return B_ENTRY_NOT_FOUND; 225 #else // HAIKU_TARGET_PLATFORM_HAIKU 226 return B_NOT_SUPPORTED; 227 #endif 228 } 229 230 231 // Returns the BResources object to an uninitialized state. 232 void 233 BResources::Unset() 234 { 235 if (fContainer && fContainer->IsModified()) 236 Sync(); 237 delete fResourceFile; 238 fResourceFile = NULL; 239 fFile.Unset(); 240 if (fContainer) 241 fContainer->MakeEmpty(); 242 else 243 fContainer = new(nothrow) ResourcesContainer; 244 fReadOnly = false; 245 } 246 247 248 // Gets the initialization status of the object. 249 status_t 250 BResources::InitCheck() const 251 { 252 return (fContainer ? B_OK : B_NO_MEMORY); 253 } 254 255 256 // Gets a reference to the internal BFile object. 257 const BFile& 258 BResources::File() const 259 { 260 return fFile; 261 } 262 263 264 // Loads a resource identified by type and id into memory. 265 const void* 266 BResources::LoadResource(type_code type, int32 id, size_t* _size) 267 { 268 // find the resource 269 status_t error = InitCheck(); 270 ResourceItem* resource = NULL; 271 if (error == B_OK) { 272 resource = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 273 if (!resource) 274 error = B_ENTRY_NOT_FOUND; 275 } 276 // load it, if necessary 277 if (error == B_OK && !resource->IsLoaded() && fResourceFile) 278 error = fResourceFile->ReadResource(*resource); 279 // return the result 280 const void *result = NULL; 281 if (error == B_OK) { 282 result = resource->Data(); 283 if (_size) 284 *_size = resource->DataSize(); 285 } 286 return result; 287 } 288 289 290 // Loads a resource identified by type and name into memory. 291 const void* 292 BResources::LoadResource(type_code type, const char* name, size_t* _size) 293 { 294 // find the resource 295 status_t error = InitCheck(); 296 ResourceItem* resource = NULL; 297 if (error == B_OK) { 298 resource = fContainer->ResourceAt(fContainer->IndexOf(type, name)); 299 if (!resource) 300 error = B_ENTRY_NOT_FOUND; 301 } 302 // load it, if necessary 303 if (error == B_OK && !resource->IsLoaded() && fResourceFile) 304 error = fResourceFile->ReadResource(*resource); 305 // return the result 306 const void* result = NULL; 307 if (error == B_OK) { 308 result = resource->Data(); 309 if (_size) 310 *_size = resource->DataSize(); 311 } 312 return result; 313 } 314 315 316 // Loads all resources of the specified type into memory. 317 status_t 318 BResources::PreloadResourceType(type_code type) 319 { 320 status_t error = InitCheck(); 321 if (error == B_OK && fResourceFile) { 322 if (type == 0) 323 error = fResourceFile->ReadResources(*fContainer); 324 else { 325 int32 count = fContainer->CountResources(); 326 int32 errorCount = 0; 327 for (int32 i = 0; i < count; i++) { 328 ResourceItem *resource = fContainer->ResourceAt(i); 329 if (resource->Type() == type) { 330 if (fResourceFile->ReadResource(*resource) != B_OK) 331 errorCount++; 332 } 333 } 334 error = -errorCount; 335 } 336 } 337 return error; 338 } 339 340 341 // Writes all changes to the resources to the file. 342 status_t 343 BResources::Sync() 344 { 345 status_t error = InitCheck(); 346 if (error == B_OK) 347 error = fFile.InitCheck(); 348 if (error == B_OK) { 349 if (fReadOnly) 350 error = B_NOT_ALLOWED; 351 else if (!fResourceFile) 352 error = B_FILE_ERROR; 353 } 354 if (error == B_OK) 355 error = fResourceFile->ReadResources(*fContainer); 356 if (error == B_OK) 357 error = fResourceFile->WriteResources(*fContainer); 358 return error; 359 } 360 361 362 // Adds the resources of fromFile to the internal file of the 363 // BResources object. 364 status_t 365 BResources::MergeFrom(BFile* fromFile) 366 { 367 status_t error = (fromFile ? B_OK : B_BAD_VALUE); 368 if (error == B_OK) 369 error = InitCheck(); 370 if (error == B_OK) { 371 ResourceFile resourceFile; 372 error = resourceFile.SetTo(fromFile); 373 ResourcesContainer container; 374 if (error == B_OK) 375 error = resourceFile.InitContainer(container); 376 if (error == B_OK) 377 error = resourceFile.ReadResources(container); 378 if (error == B_OK) 379 fContainer->AssimilateResources(container); 380 } 381 return error; 382 } 383 384 385 // Writes the resources to a new file. 386 status_t 387 BResources::WriteTo(BFile* file) 388 { 389 status_t error = (file ? B_OK : B_BAD_VALUE); 390 if (error == B_OK) 391 error = InitCheck(); 392 // make sure, that all resources are loaded 393 if (error == B_OK && fResourceFile) { 394 error = fResourceFile->ReadResources(*fContainer); 395 fResourceFile->Unset(); 396 } 397 // set the new file, but keep the old container 398 if (error == B_OK) { 399 ResourcesContainer *container = fContainer; 400 fContainer = new(nothrow) ResourcesContainer; 401 if (fContainer) { 402 error = SetTo(file, false); 403 delete fContainer; 404 } else 405 error = B_NO_MEMORY; 406 fContainer = container; 407 } 408 // write the resources 409 if (error == B_OK && fResourceFile) 410 error = fResourceFile->WriteResources(*fContainer); 411 return error; 412 } 413 414 415 // Adds a new resource to the file. 416 status_t 417 BResources::AddResource(type_code type, int32 id, const void* data, 418 size_t length, const char* name) 419 { 420 status_t error = (data ? B_OK : B_BAD_VALUE); 421 if (error == B_OK) 422 error = InitCheck(); 423 if (error == B_OK) 424 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 425 if (error == B_OK) { 426 ResourceItem* item = new(nothrow) ResourceItem; 427 if (!item) 428 error = B_NO_MEMORY; 429 if (error == B_OK) { 430 item->SetIdentity(type, id, name); 431 ssize_t written = item->WriteAt(0, data, length); 432 if (written < 0) 433 error = written; 434 else if (written != (ssize_t)length) 435 error = B_ERROR; 436 } 437 if (error == B_OK) { 438 if (!fContainer->AddResource(item)) 439 error = B_NO_MEMORY; 440 } 441 if (error != B_OK) 442 delete item; 443 } 444 return error; 445 } 446 447 448 // Returns whether the file contains a resource with the specified 449 // type and id. 450 bool 451 BResources::HasResource(type_code type, int32 id) 452 { 453 return (InitCheck() == B_OK && fContainer->IndexOf(type, id) >= 0); 454 } 455 456 457 // Returns whether the file contains a resource with the specified 458 // type and name. 459 bool 460 BResources::HasResource(type_code type, const char* name) 461 { 462 return (InitCheck() == B_OK && fContainer->IndexOf(type, name) >= 0); 463 } 464 465 466 // Gets information about a resource identified by byindex. 467 bool 468 BResources::GetResourceInfo(int32 byIndex, type_code* typeFound, 469 int32* idFound, const char** nameFound, size_t* lengthFound) 470 { 471 ResourceItem* item = NULL; 472 if (InitCheck() == B_OK) 473 item = fContainer->ResourceAt(byIndex); 474 if (item) { 475 if (typeFound) 476 *typeFound = item->Type(); 477 if (idFound) 478 *idFound = item->ID(); 479 if (nameFound) 480 *nameFound = item->Name(); 481 if (lengthFound) 482 *lengthFound = item->DataSize(); 483 } 484 return item; 485 } 486 487 488 // Gets information about a resource identified by byType and andIndex. 489 bool 490 BResources::GetResourceInfo(type_code byType, int32 andIndex, int32* idFound, 491 const char** nameFound, size_t* lengthFound) 492 { 493 ResourceItem* item = NULL; 494 if (InitCheck() == B_OK) { 495 item = fContainer->ResourceAt(fContainer->IndexOfType(byType, 496 andIndex)); 497 } 498 if (item) { 499 if (idFound) 500 *idFound = item->ID(); 501 if (nameFound) 502 *nameFound = item->Name(); 503 if (lengthFound) 504 *lengthFound = item->DataSize(); 505 } 506 return item; 507 } 508 509 510 // Gets information about a resource identified by byType and andID. 511 bool 512 BResources::GetResourceInfo(type_code byType, int32 andID, 513 const char** nameFound, size_t* lengthFound) 514 { 515 ResourceItem* item = NULL; 516 if (InitCheck() == B_OK) 517 item = fContainer->ResourceAt(fContainer->IndexOf(byType, andID)); 518 if (item) { 519 if (nameFound) 520 *nameFound = item->Name(); 521 if (lengthFound) 522 *lengthFound = item->DataSize(); 523 } 524 return item; 525 } 526 527 528 // Gets information about a resource identified by byType and andName. 529 bool 530 BResources::GetResourceInfo(type_code byType, const char* andName, 531 int32* idFound, size_t* lengthFound) 532 { 533 ResourceItem* item = NULL; 534 if (InitCheck() == B_OK) 535 item = fContainer->ResourceAt(fContainer->IndexOf(byType, andName)); 536 if (item) { 537 if (idFound) 538 *idFound = item->ID(); 539 if (lengthFound) 540 *lengthFound = item->DataSize(); 541 } 542 return item; 543 } 544 545 546 // Gets information about a resource identified by byPointer. 547 bool 548 BResources::GetResourceInfo(const void* byPointer, type_code* typeFound, 549 int32* idFound, size_t* lengthFound, const char** nameFound) 550 { 551 ResourceItem* item = NULL; 552 if (InitCheck() == B_OK) 553 item = fContainer->ResourceAt(fContainer->IndexOf(byPointer)); 554 if (item) { 555 if (typeFound) 556 *typeFound = item->Type(); 557 if (idFound) 558 *idFound = item->ID(); 559 if (nameFound) 560 *nameFound = item->Name(); 561 if (lengthFound) 562 *lengthFound = item->DataSize(); 563 } 564 return item; 565 } 566 567 568 // Removes a resource identified by its data pointer. 569 status_t 570 BResources::RemoveResource(const void* resource) 571 { 572 status_t error = (resource ? B_OK : B_BAD_VALUE); 573 if (error == B_OK) 574 error = InitCheck(); 575 if (error == B_OK) 576 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 577 if (error == B_OK) { 578 ResourceItem* item 579 = fContainer->RemoveResource(fContainer->IndexOf(resource)); 580 if (item) 581 delete item; 582 else 583 error = B_BAD_VALUE; 584 } 585 return error; 586 } 587 588 589 // Removes a resource identified by type and id. 590 status_t 591 BResources::RemoveResource(type_code type, int32 id) 592 { 593 status_t error = InitCheck(); 594 if (error == B_OK) 595 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 596 if (error == B_OK) { 597 ResourceItem* item 598 = fContainer->RemoveResource(fContainer->IndexOf(type, id)); 599 if (item) 600 delete item; 601 else 602 error = B_BAD_VALUE; 603 } 604 return error; 605 } 606 607 608 // #pragma mark - deprecated methods 609 610 611 // Writes data into an existing resource 612 // (deprecated, use AddResource() instead). 613 status_t 614 BResources::WriteResource(type_code type, int32 id, const void* data, 615 off_t offset, size_t length) 616 { 617 status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE); 618 if (error == B_OK) 619 error = InitCheck(); 620 if (error == B_OK) 621 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 622 ResourceItem *item = NULL; 623 if (error == B_OK) { 624 item = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 625 if (!item) 626 error = B_BAD_VALUE; 627 } 628 if (error == B_OK && fResourceFile) 629 error = fResourceFile->ReadResource(*item); 630 if (error == B_OK) { 631 if (item) { 632 ssize_t written = item->WriteAt(offset, data, length); 633 if (written < 0) 634 error = written; 635 else if (written != (ssize_t)length) 636 error = B_ERROR; 637 } 638 } 639 return error; 640 } 641 642 643 // Reads data from an existing resource 644 // (deprecated, use LoadResource() instead). 645 status_t 646 BResources::ReadResource(type_code type, int32 id, void* data, off_t offset, 647 size_t length) 648 { 649 status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE); 650 if (error == B_OK) 651 error = InitCheck(); 652 ResourceItem* item = NULL; 653 if (error == B_OK) { 654 item = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 655 if (!item) 656 error = B_BAD_VALUE; 657 } 658 if (error == B_OK && fResourceFile) 659 error = fResourceFile->ReadResource(*item); 660 if (error == B_OK) { 661 if (item) { 662 ssize_t read = item->ReadAt(offset, data, length); 663 if (read < 0) 664 error = read; 665 } else 666 error = B_BAD_VALUE; 667 } 668 return error; 669 } 670 671 672 // Finds a resource by type and id and returns a pointer to a copy of 673 // its data (deprecated, use LoadResource() instead). 674 void* 675 BResources::FindResource(type_code type, int32 id, size_t* lengthFound) 676 { 677 void* result = NULL; 678 size_t size = 0; 679 const void* data = LoadResource(type, id, &size); 680 if (data != NULL) { 681 if ((result = malloc(size))) 682 memcpy(result, data, size); 683 } 684 if (lengthFound) 685 *lengthFound = size; 686 return result; 687 } 688 689 690 // Finds a resource by type and name and returns a pointer to a copy of 691 // its data (deprecated, use LoadResource() instead). 692 void* 693 BResources::FindResource(type_code type, const char* name, size_t* lengthFound) 694 { 695 void* result = NULL; 696 size_t size = 0; 697 const void *data = LoadResource(type, name, &size); 698 if (data != NULL) { 699 if ((result = malloc(size))) 700 memcpy(result, data, size); 701 } 702 if (lengthFound) 703 *lengthFound = size; 704 return result; 705 } 706 707 708 // FBC 709 void BResources::_ReservedResources1() {} 710 void BResources::_ReservedResources2() {} 711 void BResources::_ReservedResources3() {} 712 void BResources::_ReservedResources4() {} 713 void BResources::_ReservedResources5() {} 714 void BResources::_ReservedResources6() {} 715 void BResources::_ReservedResources7() {} 716 void BResources::_ReservedResources8() {} 717