1 /* 2 * Copyright 2001-2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 3 * All Rights Reserved. Distributed under the terms of the MIT License. 4 */ 5 /*! 6 \file Resources.cpp 7 BResources implementation. 8 9 BResources delegates most of the work to ResourcesContainer and 10 ResourceFile. The first one manages a collections of ResourceItem's, 11 the actual resources, whereas the latter provides the file I/O 12 functionality. 13 An InitCheck() method is not needed, since a BResources object will 14 never be invalid. It always serves as a resources container, even if 15 it is not associated with a file. It is always possible to WriteTo() 16 the resources BResources contains to a file (a valid one of course). 17 */ 18 #include <Resources.h> 19 20 #include <new> 21 #include <stdio.h> 22 #include <stdlib.h> 23 24 #include "ResourceFile.h" 25 #include "ResourceItem.h" 26 #include "ResourcesContainer.h" 27 28 using namespace BPrivate::Storage; 29 using namespace std; 30 31 // debugging 32 //#define DBG(x) x 33 #define DBG(x) 34 #define OUT printf 35 36 // constructor 37 /*! \brief Creates an unitialized BResources object. 38 */ 39 BResources::BResources() 40 : 41 fFile(), 42 fContainer(NULL), 43 fResourceFile(NULL), 44 fReadOnly(false) 45 { 46 fContainer = new(nothrow) ResourcesContainer; 47 } 48 49 // constructor 50 /*! \brief Creates a BResources object that represents the resources of the 51 supplied file. 52 If the \a clobber argument is \c true, the data of the file are erased 53 and it is turned into an empty resource file. Otherwise \a file 54 must refer either to a resource file or to an executable (ELF or PEF 55 binary). If the file has been opened \c B_READ_ONLY, only read access 56 to its resources is possible. 57 The BResources object makes a copy of \a file, that is the caller remains 58 owner of the BFile object. 59 \param file the file 60 \param clobber if \c true, the file's resources are truncated to size 0 61 */ 62 BResources::BResources(const BFile* file, bool clobber) 63 : 64 fFile(), 65 fContainer(NULL), 66 fResourceFile(NULL), 67 fReadOnly(false) 68 { 69 fContainer = new(nothrow) ResourcesContainer; 70 SetTo(file, clobber); 71 } 72 73 // constructor 74 /*! \brief Creates a BResources object that represents the resources of the 75 supplied file. 76 If the \a clobber argument is \c true, the data of the file are erased 77 and it is turned into an empty resource file. Otherwise \a path 78 must refer either to a resource file or to an executable (ELF or PEF 79 binary). 80 \param path a path referring to the file 81 \param clobber if \c true, the file's resources are truncated to size 0 82 */ 83 BResources::BResources(const char* path, bool clobber) 84 : 85 fFile(), 86 fContainer(NULL), 87 fResourceFile(NULL), 88 fReadOnly(false) 89 { 90 fContainer = new(nothrow) ResourcesContainer; 91 SetTo(path, clobber); 92 } 93 94 // constructor 95 /*! \brief Creates a BResources object that represents the resources of the 96 supplied file. 97 If the \a clobber argument is \c true, the data of the file are erased 98 and it is turned into an empty resource file. Otherwise \a ref 99 must refer either to a resource file or to an executable (ELF or PEF 100 binary). 101 \param ref an entry_ref referring to the file 102 \param clobber if \c true, the file's resources are truncated to size 0 103 */ 104 BResources::BResources(const entry_ref* ref, bool clobber) 105 : 106 fFile(), 107 fContainer(NULL), 108 fResourceFile(NULL), 109 fReadOnly(false) 110 { 111 fContainer = new(nothrow) ResourcesContainer; 112 SetTo(ref, clobber); 113 } 114 115 // destructor 116 /*! \brief Frees all resources associated with this object 117 Calls Sync() before doing so to make sure that the changes are written 118 back to the file. 119 */ 120 BResources::~BResources() 121 { 122 Unset(); 123 delete fContainer; 124 } 125 126 // SetTo 127 /*! \brief Re-initialized the BResources object to represent the resources of 128 the supplied file. 129 What happens, if \a clobber is \c true, depends on the type of the file. 130 If the file is capable of containing resources, that is, is a resource 131 file or an executable (ELF or PEF), its resources are removed. Otherwise 132 the file's data are erased and it is turned into an empty resource file. 133 If \a clobber is \c false, \a file must refer to a file that is capable 134 of containing resources. 135 If the file has been opened \c B_READ_ONLY, only read access 136 to its resources is possible. 137 The BResources object makes a copy of \a file, that is the caller remains 138 owner of the BFile object. 139 \param file the file 140 \param clobber if \c true, the file's resources are truncated to size 0 141 \return 142 - \c B_OK: Everything went fine. 143 - \c B_BAD_VALUE: \c NULL or uninitialized \a file. 144 - \c B_ERROR: Failed to initialize the object (for whatever reason). 145 */ 146 status_t 147 BResources::SetTo(const BFile* file, bool clobber) 148 { 149 Unset(); 150 status_t error = B_OK; 151 if (file) { 152 error = file->InitCheck(); 153 if (error == B_OK) { 154 fFile = *file; 155 error = fFile.InitCheck(); 156 } 157 if (error == B_OK) { 158 fReadOnly = !fFile.IsWritable(); 159 fResourceFile = new(nothrow) ResourceFile; 160 if (fResourceFile) 161 error = fResourceFile->SetTo(&fFile, clobber); 162 else 163 error = B_NO_MEMORY; 164 } 165 if (error == B_OK) { 166 if (fContainer) 167 error = fResourceFile->InitContainer(*fContainer); 168 else 169 error = B_NO_MEMORY; 170 } 171 } 172 if (error != B_OK) { 173 delete fResourceFile; 174 fResourceFile = NULL; 175 if (fContainer) 176 fContainer->MakeEmpty(); 177 } 178 return error; 179 } 180 181 // SetTo 182 /*! \brief Re-initialized the BResources object to represent the resources of 183 the supplied file. 184 What happens, if \a clobber is \c true, depends on the type of the file. 185 If the file is capable of containing resources, that is, is a resource 186 file or an executable (ELF or PEF), its resources are removed. Otherwise 187 the file's data are erased and it is turned into an empty resource file. 188 If \a clobber is \c false, \a path must refer to a file that is capable 189 of containing resources. 190 \param path a path referring to the file 191 \param clobber if \c true, the file's resources are truncated to size 0 192 \return 193 - \c B_OK: Everything went fine. 194 - \c B_BAD_VALUE: \c NULL \a path. 195 - \c B_ENTRY_NOT_FOUND: The file couldn't be found. 196 - \c B_ERROR: Failed to initialize the object (for whatever reason). 197 */ 198 status_t 199 BResources::SetTo(const char* path, bool clobber) 200 { 201 if (!path) 202 return B_BAD_VALUE; 203 204 // open file 205 BFile file; 206 status_t error = file.SetTo(path, B_READ_WRITE); 207 if (error != B_OK) { 208 Unset(); 209 return error; 210 } 211 212 // delegate the actual work 213 return SetTo(&file, clobber); 214 } 215 216 // SetTo 217 /*! \brief Re-initialized the BResources object to represent the resources of 218 the supplied file. 219 What happens, if \a clobber is \c true, depends on the type of the file. 220 If the file is capable of containing resources, that is, is a resource 221 file or an executable (ELF or PEF), its resources are removed. Otherwise 222 the file's data are erased and it is turned into an empty resource file. 223 If \a clobber is \c false, \a ref must refer to a file that is capable 224 of containing resources. 225 \param ref an entry_ref referring to the file 226 \param clobber if \c true, the file's resources are truncated to size 0 227 \return 228 - \c B_OK: Everything went fine. 229 - \c B_BAD_VALUE: \c NULL \a ref. 230 - \c B_ENTRY_NOT_FOUND: The file couldn't be found. 231 - \c B_ERROR: Failed to initialize the object (for whatever reason). 232 */ 233 status_t 234 BResources::SetTo(const entry_ref* ref, bool clobber) 235 { 236 if (!ref) 237 return B_BAD_VALUE; 238 239 // open file 240 BFile file; 241 status_t error = file.SetTo(ref, B_READ_WRITE); 242 if (error != B_OK) { 243 Unset(); 244 return error; 245 } 246 247 // delegate the actual work 248 return SetTo(&file, clobber); 249 } 250 251 // SetToImage 252 /*! \brief Re-initialized the BResources object to represent the resources of 253 the file from which the specified image has been loaded. 254 If \a clobber is \c true, the file's resources are removed. 255 \param image ID of a loaded image 256 \param clobber if \c true, the file's resources are truncated to size 0 257 \return 258 - \c B_OK: Everything went fine. 259 - \c B_ENTRY_NOT_FOUND: The file couldn't be found. 260 - \c B_ERROR: Failed to initialize the object (for whatever reason). 261 */ 262 status_t 263 BResources::SetToImage(image_id image, bool clobber) 264 { 265 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 266 // get an image info 267 image_info info; 268 status_t error = get_image_info(image, &info); 269 if (error != B_OK) { 270 Unset(); 271 return error; 272 } 273 274 // delegate the actual work 275 return SetTo(info.name, clobber); 276 #else // HAIKU_TARGET_PLATFORM_HAIKU 277 return B_NOT_SUPPORTED; 278 #endif 279 } 280 281 /*! \brief Re-initialized the BResources object to represent the resources of 282 the file from which the specified image has been loaded. 283 The image belongs to the current team and is identified by a pointer into 284 it's code (aka text) or data segment, i.e. any pointer to a function or a 285 static (or global) variable will do. 286 If \a clobber is \c true, the file's resources are removed. 287 \param codeOrDataPointer pointer into the text or data segment of the image 288 \param clobber if \c true, the file's resources are truncated to size 0 289 \return 290 - \c B_OK: Everything went fine. 291 - \c B_BAD_VALUE: \c NULL \a ref. 292 - \c B_ENTRY_NOT_FOUND: The image or the file couldn't be found. 293 - \c B_ERROR: Failed to initialize the object (for whatever reason). 294 */ 295 status_t 296 BResources::SetToImage(const void* codeOrDataPointer, bool clobber) 297 { 298 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 299 if (!codeOrDataPointer) 300 return B_BAD_VALUE; 301 302 // iterate through the images and find the one in question 303 addr_t address = (addr_t)codeOrDataPointer; 304 image_info info; 305 int32 cookie = 0; 306 307 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 308 if (((addr_t)info.text <= address 309 && address - (addr_t)info.text < (addr_t)info.text_size) 310 || ((addr_t)info.data <= address 311 && address - (addr_t)info.data < (addr_t)info.data_size)) { 312 return SetTo(info.name, clobber); 313 } 314 } 315 316 return B_ENTRY_NOT_FOUND; 317 #else // HAIKU_TARGET_PLATFORM_HAIKU 318 return B_NOT_SUPPORTED; 319 #endif 320 } 321 322 // Unset 323 /*! \brief Returns the BResources object to an uninitialized state. 324 If the object represented resources that had been modified, the data are 325 written back to the file. 326 \note This method extends the BeOS R5 API. 327 */ 328 void 329 BResources::Unset() 330 { 331 if (fContainer && fContainer->IsModified()) 332 Sync(); 333 delete fResourceFile; 334 fResourceFile = NULL; 335 fFile.Unset(); 336 if (fContainer) 337 fContainer->MakeEmpty(); 338 else 339 fContainer = new(nothrow) ResourcesContainer; 340 fReadOnly = false; 341 } 342 343 // InitCheck 344 /*! Returns the current initialization status. 345 Unlike other Storage Kit classes a BResources object is always properly 346 initialized, unless it couldn't allocate memory for some important 347 internal structures. Thus even after a call to SetTo() that reported an 348 error, InitCheck() is likely to return \c B_OK. 349 \return 350 - \c B_OK, if the objects is properly initialized, 351 - \c B_NO_MEMORY otherwise. 352 \note This method extends the BeOS R5 API. 353 */ 354 status_t 355 BResources::InitCheck() const 356 { 357 return (fContainer ? B_OK : B_NO_MEMORY); 358 } 359 360 // File 361 /*! \brief Returns a reference to the BResources' BFile object. 362 \return a reference to the object's BFile. 363 */ 364 const BFile& 365 BResources::File() const 366 { 367 return fFile; 368 } 369 370 // LoadResource 371 /*! \brief Loads a resource identified by type and ID into memory. 372 A resource is loaded into memory only once. A second call with the same 373 parameters will result in the same pointer. The BResources object is the 374 owner of the allocated memory and the pointer to it will be valid until 375 the object is destroyed or the resource is removed or modified. 376 \param type the type of the resource to be loaded 377 \param id the ID of the resource to be loaded 378 \param outSize a pointer to a variable into which the size of the resource 379 shall be written 380 \return A pointer to the resource data, if everything went fine, or 381 \c NULL, if the file does not have a resource that matchs the 382 parameters or an error occured. 383 */ 384 const void* 385 BResources::LoadResource(type_code type, int32 id, size_t* outSize) 386 { 387 // find the resource 388 status_t error = InitCheck(); 389 ResourceItem* resource = NULL; 390 if (error == B_OK) { 391 resource = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 392 if (!resource) 393 error = B_ENTRY_NOT_FOUND; 394 } 395 // load it, if necessary 396 if (error == B_OK && !resource->IsLoaded() && fResourceFile) 397 error = fResourceFile->ReadResource(*resource); 398 // return the result 399 const void *result = NULL; 400 if (error == B_OK) { 401 result = resource->Data(); 402 if (outSize) 403 *outSize = resource->DataSize(); 404 } 405 return result; 406 } 407 408 // LoadResource 409 /*! \brief Loads a resource identified by type and name into memory. 410 A resource is loaded into memory only once. A second call with the same 411 parameters will result in the same pointer. The BResources object is the 412 owner of the allocated memory and the pointer to it will be valid until 413 the object is destroyed or the resource is removed or modified. 414 \param type the type of the resource to be loaded 415 \param name the name of the resource to be loaded 416 \param outSize a pointer to a variable into which the size of the resource 417 shall be written 418 \return A pointer to the resource data, if everything went fine, or 419 \c NULL, if the file does not have a resource that matches the 420 parameters or an error occured. 421 \note Since a type and name pair may not identify a resource uniquely, 422 this method always returns the first resource that matches the 423 parameters, that is the one with the least index. 424 */ 425 const void * 426 BResources::LoadResource(type_code type, const char* name, size_t* outSize) 427 { 428 // find the resource 429 status_t error = InitCheck(); 430 ResourceItem* resource = NULL; 431 if (error == B_OK) { 432 resource = fContainer->ResourceAt(fContainer->IndexOf(type, name)); 433 if (!resource) 434 error = B_ENTRY_NOT_FOUND; 435 } 436 // load it, if necessary 437 if (error == B_OK && !resource->IsLoaded() && fResourceFile) 438 error = fResourceFile->ReadResource(*resource); 439 // return the result 440 const void* result = NULL; 441 if (error == B_OK) { 442 result = resource->Data(); 443 if (outSize) 444 *outSize = resource->DataSize(); 445 } 446 return result; 447 } 448 449 // PreloadResourceType 450 /*! \brief Loads all resources of a certain type into memory. 451 For performance reasons it might be useful to do that. If \a type is 452 0, all resources are loaded. 453 \param type of the resources to be loaded 454 \return 455 - \c B_OK: Everything went fine. 456 - \c B_BAD_FILE: The resource map is empty??? 457 - The negative of the number of errors occured. 458 */ 459 status_t 460 BResources::PreloadResourceType(type_code type) 461 { 462 status_t error = InitCheck(); 463 if (error == B_OK && fResourceFile) { 464 if (type == 0) 465 error = fResourceFile->ReadResources(*fContainer); 466 else { 467 int32 count = fContainer->CountResources(); 468 int32 errorCount = 0; 469 for (int32 i = 0; i < count; i++) { 470 ResourceItem *resource = fContainer->ResourceAt(i); 471 if (resource->Type() == type) { 472 if (fResourceFile->ReadResource(*resource) != B_OK) 473 errorCount++; 474 } 475 } 476 error = -errorCount; 477 } 478 } 479 return error; 480 } 481 482 // Sync 483 /*! \brief Writes all changes to the resources to the file. 484 Since AddResource() and RemoveResource() may change the resources only in 485 memory, this method can be used to make sure, that all changes are 486 actually written to the file. 487 The BResources object's destructor calls Sync() before cleaning up. 488 \return 489 - \c B_OK: Everything went fine. 490 - \c B_BAD_FILE: The resource map is empty??? 491 - \c B_NOT_ALLOWED: The file is opened read only. 492 - \c B_FILE_ERROR: A file error occured. 493 - \c B_IO_ERROR: An error occured while writing the resources. 494 \note When a resource is written to the file, its data are converted 495 to the endianess of the file, and when reading a resource, the 496 data are converted to the host's endianess. This does of course 497 only work for known types, i.e. those that swap_data() is able to 498 cope with. 499 */ 500 status_t 501 BResources::Sync() 502 { 503 status_t error = InitCheck(); 504 if (error == B_OK) 505 error = fFile.InitCheck(); 506 if (error == B_OK) { 507 if (fReadOnly) 508 error = B_NOT_ALLOWED; 509 else if (!fResourceFile) 510 error = B_FILE_ERROR; 511 } 512 if (error == B_OK) 513 error = fResourceFile->ReadResources(*fContainer); 514 if (error == B_OK) 515 error = fResourceFile->WriteResources(*fContainer); 516 return error; 517 } 518 519 // MergeFrom 520 /*! \brief Adds the resources of the supplied file to this file's resources. 521 \param fromFile the file whose resources shall be copied 522 \return 523 - \c B_OK: Everything went fine. 524 - \c B_BAD_VALUE: \c NULL \a fromFile. 525 - \c B_BAD_FILE: The resource map is empty??? 526 - \c B_FILE_ERROR: A file error occured. 527 - \c B_IO_ERROR: An error occured while writing the resources. 528 */ 529 status_t 530 BResources::MergeFrom(BFile* fromFile) 531 { 532 status_t error = (fromFile ? B_OK : B_BAD_VALUE); 533 if (error == B_OK) 534 error = InitCheck(); 535 if (error == B_OK) { 536 ResourceFile resourceFile; 537 error = resourceFile.SetTo(fromFile); 538 ResourcesContainer container; 539 if (error == B_OK) 540 error = resourceFile.InitContainer(container); 541 if (error == B_OK) 542 error = resourceFile.ReadResources(container); 543 if (error == B_OK) 544 fContainer->AssimilateResources(container); 545 } 546 return error; 547 } 548 549 // WriteTo 550 /*! \brief Writes the resources to a new file. 551 The resources formerly contained in the target file (if any) are erased. 552 When the method returns, the BResources object refers to the new file. 553 \param file the file the resources shall be written to. 554 \return 555 - \c B_OK: Everything went fine. 556 - a specific error code. 557 \note If the resources have been modified, but not Sync()ed, the old file 558 remains unmodified. 559 */ 560 status_t 561 BResources::WriteTo(BFile* file) 562 { 563 status_t error = (file ? B_OK : B_BAD_VALUE); 564 if (error == B_OK) 565 error = InitCheck(); 566 // make sure, that all resources are loaded 567 if (error == B_OK && fResourceFile) { 568 error = fResourceFile->ReadResources(*fContainer); 569 fResourceFile->Unset(); 570 } 571 // set the new file, but keep the old container 572 if (error == B_OK) { 573 ResourcesContainer *container = fContainer; 574 fContainer = new(nothrow) ResourcesContainer; 575 if (fContainer) { 576 error = SetTo(file, false); 577 delete fContainer; 578 } else 579 error = B_NO_MEMORY; 580 fContainer = container; 581 } 582 // write the resources 583 if (error == B_OK && fResourceFile) 584 error = fResourceFile->WriteResources(*fContainer); 585 return error; 586 } 587 588 // AddResource 589 /*! \brief Adds a new resource to the file. 590 If a resource with the same type and ID does already exist, it is 591 replaced. The caller keeps the ownership of the supplied chunk of memory 592 containing the resource data. 593 Supplying an empty name (\c "") is equivalent to supplying a \c NULL name. 594 \param type the type of the resource 595 \param id the ID of the resource 596 \param data the resource data 597 \param length the size of the data in bytes 598 \param name the name of the resource (may be \c NULL) 599 \return 600 - \c B_OK: Everything went fine. 601 - \c B_BAD_VALUE: \c NULL \a data 602 - \c B_NOT_ALLOWED: The file is opened read only. 603 - \c B_FILE_ERROR: A file error occured. 604 - \c B_NO_MEMORY: Not enough memory for that operation. 605 */ 606 status_t 607 BResources::AddResource(type_code type, int32 id, const void* data, 608 size_t length, const char* name) 609 { 610 status_t error = (data ? B_OK : B_BAD_VALUE); 611 if (error == B_OK) 612 error = InitCheck(); 613 if (error == B_OK) 614 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 615 if (error == B_OK) { 616 ResourceItem* item = new(nothrow) ResourceItem; 617 if (!item) 618 error = B_NO_MEMORY; 619 if (error == B_OK) { 620 item->SetIdentity(type, id, name); 621 ssize_t written = item->WriteAt(0, data, length); 622 if (written < 0) 623 error = written; 624 else if (written != (ssize_t)length) 625 error = B_ERROR; 626 } 627 if (error == B_OK) { 628 if (!fContainer->AddResource(item)) 629 error = B_NO_MEMORY; 630 } 631 if (error != B_OK) 632 delete item; 633 } 634 return error; 635 } 636 637 // HasResource 638 /*! \brief Returns whether the file contains a resource with a certain 639 type and ID. 640 \param type the resource type 641 \param id the ID of the resource 642 \return \c true, if the file contains a matching resource, \false otherwise 643 */ 644 bool 645 BResources::HasResource(type_code type, int32 id) 646 { 647 return (InitCheck() == B_OK && fContainer->IndexOf(type, id) >= 0); 648 } 649 650 // HasResource 651 /*! \brief Returns whether the file contains a resource with a certain 652 type and name. 653 \param type the resource type 654 \param name the name of the resource 655 \return \c true, if the file contains a matching resource, \false otherwise 656 */ 657 bool 658 BResources::HasResource(type_code type, const char* name) 659 { 660 return (InitCheck() == B_OK && fContainer->IndexOf(type, name) >= 0); 661 } 662 663 // GetResourceInfo 664 /*! \brief Returns information about a resource identified by an index. 665 \param byIndex the index of the resource in the file 666 \param typeFound a pointer to a variable the type of the found resource 667 shall be written into 668 \param idFound a pointer to a variable the ID of the found resource 669 shall be written into 670 \param nameFound a pointer to a variable the name pointer of the found 671 resource shall be written into 672 \param lengthFound a pointer to a variable the data size of the found 673 resource shall be written into 674 \return \c true, if a matching resource could be found, false otherwise 675 */ 676 bool 677 BResources::GetResourceInfo(int32 byIndex, type_code* typeFound, 678 int32* idFound, const char** nameFound, 679 size_t* lengthFound) 680 { 681 ResourceItem* item = NULL; 682 if (InitCheck() == B_OK) 683 item = fContainer->ResourceAt(byIndex); 684 if (item) { 685 if (typeFound) 686 *typeFound = item->Type(); 687 if (idFound) 688 *idFound = item->ID(); 689 if (nameFound) 690 *nameFound = item->Name(); 691 if (lengthFound) 692 *lengthFound = item->DataSize(); 693 } 694 return item; 695 } 696 697 // GetResourceInfo 698 /*! \brief Returns information about a resource identified by a type and an 699 index. 700 \param byType the resource type 701 \param andIndex the index into a array of resources of type \a byType 702 \param idFound a pointer to a variable the ID of the found resource 703 shall be written into 704 \param nameFound a pointer to a variable the name pointer of the found 705 resource shall be written into 706 \param lengthFound a pointer to a variable the data size of the found 707 resource shall be written into 708 \return \c true, if a matching resource could be found, false otherwise 709 */ 710 bool 711 BResources::GetResourceInfo(type_code byType, int32 andIndex, int32* idFound, 712 const char** nameFound, size_t* lengthFound) 713 { 714 ResourceItem* item = NULL; 715 if (InitCheck() == B_OK) { 716 item = fContainer->ResourceAt(fContainer->IndexOfType(byType, 717 andIndex)); 718 } 719 if (item) { 720 if (idFound) 721 *idFound = item->ID(); 722 if (nameFound) 723 *nameFound = item->Name(); 724 if (lengthFound) 725 *lengthFound = item->DataSize(); 726 } 727 return item; 728 } 729 730 // GetResourceInfo 731 /*! \brief Returns information about a resource identified by a type and an ID. 732 \param byType the resource type 733 \param andID the resource ID 734 \param nameFound a pointer to a variable the name pointer of the found 735 resource shall be written into 736 \param lengthFound a pointer to a variable the data size of the found 737 resource shall be written into 738 \return \c true, if a matching resource could be found, false otherwise 739 */ 740 bool 741 BResources::GetResourceInfo(type_code byType, int32 andID, 742 const char** nameFound, size_t* lengthFound) 743 { 744 ResourceItem* item = NULL; 745 if (InitCheck() == B_OK) 746 item = fContainer->ResourceAt(fContainer->IndexOf(byType, andID)); 747 if (item) { 748 if (nameFound) 749 *nameFound = item->Name(); 750 if (lengthFound) 751 *lengthFound = item->DataSize(); 752 } 753 return item; 754 } 755 756 // GetResourceInfo 757 /*! \brief Returns information about a resource identified by a type and a 758 name. 759 \param byType the resource type 760 \param andName the resource name 761 \param idFound a pointer to a variable the ID of the found resource 762 shall be written into 763 \param lengthFound a pointer to a variable the data size of the found 764 resource shall be written into 765 \return \c true, if a matching resource could be found, false otherwise 766 */ 767 bool 768 BResources::GetResourceInfo(type_code byType, const char* andName, 769 int32* idFound, size_t* lengthFound) 770 { 771 ResourceItem* item = NULL; 772 if (InitCheck() == B_OK) 773 item = fContainer->ResourceAt(fContainer->IndexOf(byType, andName)); 774 if (item) { 775 if (idFound) 776 *idFound = item->ID(); 777 if (lengthFound) 778 *lengthFound = item->DataSize(); 779 } 780 return item; 781 } 782 783 // GetResourceInfo 784 /*! \brief Returns information about a resource identified by a data pointer. 785 \param byPointer the pointer to the resource data (formely returned by 786 LoadResource()) 787 \param typeFound a pointer to a variable the type of the found resource 788 shall be written into 789 \param idFound a pointer to a variable the ID of the found resource 790 shall be written into 791 \param lengthFound a pointer to a variable the data size of the found 792 resource shall be written into 793 \param nameFound a pointer to a variable the name pointer of the found 794 resource shall be written into 795 \return \c true, if a matching resource could be found, false otherwise 796 */ 797 bool 798 BResources::GetResourceInfo(const void* byPointer, type_code* typeFound, 799 int32* idFound, size_t* lengthFound, 800 const char** nameFound) 801 { 802 ResourceItem* item = NULL; 803 if (InitCheck() == B_OK) 804 item = fContainer->ResourceAt(fContainer->IndexOf(byPointer)); 805 if (item) { 806 if (typeFound) 807 *typeFound = item->Type(); 808 if (idFound) 809 *idFound = item->ID(); 810 if (nameFound) 811 *nameFound = item->Name(); 812 if (lengthFound) 813 *lengthFound = item->DataSize(); 814 } 815 return item; 816 } 817 818 // RemoveResource 819 /*! \brief Removes a resource identified by its data pointer. 820 \param resource the pointer to the resource data (formely returned by 821 LoadResource()) 822 \return 823 - \c B_OK: Everything went fine. 824 - \c B_BAD_VALUE: \c NULL or invalid (not pointing to any resource data of 825 this file) \a resource. 826 - \c B_NOT_ALLOWED: The file is opened read only. 827 - \c B_FILE_ERROR: A file error occured. 828 - \c B_ERROR: An error occured while removing the resource. 829 */ 830 status_t 831 BResources::RemoveResource(const void* resource) 832 { 833 status_t error = (resource ? B_OK : B_BAD_VALUE); 834 if (error == B_OK) 835 error = InitCheck(); 836 if (error == B_OK) 837 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 838 if (error == B_OK) { 839 ResourceItem* item 840 = fContainer->RemoveResource(fContainer->IndexOf(resource)); 841 if (item) 842 delete item; 843 else 844 error = B_BAD_VALUE; 845 } 846 return error; 847 } 848 849 // RemoveResource 850 /*! \brief Removes a resource identified by type and ID. 851 \param type the type of the resource 852 \param id the ID of the resource 853 \return 854 - \c B_OK: Everything went fine. 855 - \c B_BAD_VALUE: No such resource. 856 - \c B_NOT_ALLOWED: The file is opened read only. 857 - \c B_FILE_ERROR: A file error occured. 858 - \c B_ERROR: An error occured while removing the resource. 859 */ 860 status_t 861 BResources::RemoveResource(type_code type, int32 id) 862 { 863 status_t error = InitCheck(); 864 if (error == B_OK) 865 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 866 if (error == B_OK) { 867 ResourceItem* item 868 = fContainer->RemoveResource(fContainer->IndexOf(type, id)); 869 if (item) 870 delete item; 871 else 872 error = B_BAD_VALUE; 873 } 874 return error; 875 } 876 877 878 // deprecated 879 880 // WriteResource 881 /*! \brief Writes data into an existing resource. 882 If writing the data would exceed the bounds of the resource, it is 883 enlarged respectively. If \a offset is past the end of the resource, 884 padding with unspecified data is inserted. 885 \param type the type of the resource 886 \param id the ID of the resource 887 \param data the data to be written 888 \param offset the byte offset relative to the beginning of the resource at 889 which the data shall be written 890 \param length the size of the data to be written 891 \return 892 - \c B_OK: Everything went fine. 893 - \c B_BAD_VALUE: \a type and \a id do not identify an existing resource or 894 \c NULL \a data. 895 - \c B_NO_MEMORY: Not enough memory for this operation. 896 - other error codes. 897 \deprecated Always use AddResource(). 898 */ 899 status_t 900 BResources::WriteResource(type_code type, int32 id, const void* data, 901 off_t offset, size_t length) 902 { 903 status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE); 904 if (error == B_OK) 905 error = InitCheck(); 906 if (error == B_OK) 907 error = (fReadOnly ? B_NOT_ALLOWED : B_OK); 908 ResourceItem *item = NULL; 909 if (error == B_OK) { 910 item = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 911 if (!item) 912 error = B_BAD_VALUE; 913 } 914 if (error == B_OK && fResourceFile) 915 error = fResourceFile->ReadResource(*item); 916 if (error == B_OK) { 917 if (item) { 918 ssize_t written = item->WriteAt(offset, data, length); 919 if (written < 0) 920 error = written; 921 else if (written != (ssize_t)length) 922 error = B_ERROR; 923 } 924 } 925 return error; 926 } 927 928 // ReadResource 929 /*! \brief Reads data from an existing resource. 930 If more data than existing are requested, this method does not fail. It 931 will then read only the existing data. As a consequence an offset past 932 the end of the resource will not cause the method to fail, but no data 933 will be read at all. 934 \param type the type of the resource 935 \param id the ID of the resource 936 \param data a pointer to a buffer into which the data shall be read 937 \param offset the byte offset relative to the beginning of the resource 938 from which the data shall be read 939 \param length the size of the data to be read 940 \return 941 - \c B_OK: Everything went fine. 942 - \c B_BAD_VALUE: \a type and \a id do not identify an existing resource or 943 \c NULL \a data. 944 - \c B_NO_MEMORY: Not enough memory for this operation. 945 - other error codes. 946 \deprecated Use LoadResource() only. 947 */ 948 status_t 949 BResources::ReadResource(type_code type, int32 id, void* data, off_t offset, 950 size_t length) 951 { 952 status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE); 953 if (error == B_OK) 954 error = InitCheck(); 955 ResourceItem* item = NULL; 956 if (error == B_OK) { 957 item = fContainer->ResourceAt(fContainer->IndexOf(type, id)); 958 if (!item) 959 error = B_BAD_VALUE; 960 } 961 if (error == B_OK && fResourceFile) 962 error = fResourceFile->ReadResource(*item); 963 if (error == B_OK) { 964 if (item) { 965 ssize_t read = item->ReadAt(offset, data, length); 966 if (read < 0) 967 error = read; 968 } else 969 error = B_BAD_VALUE; 970 } 971 return error; 972 } 973 974 // FindResource 975 /*! \brief Finds a resource by type and ID and returns a copy of its data. 976 The caller is responsible for free()ing the returned memory. 977 \param type the type of the resource 978 \param id the ID of the resource 979 \param lengthFound a pointer to a variable into which the size of the 980 resource data shall be written 981 \return 982 - a pointer to the resource data, if everything went fine, 983 - \c NULL, if an error occured. 984 \deprecated Use LoadResource(). 985 */ 986 void* 987 BResources::FindResource(type_code type, int32 id, size_t* lengthFound) 988 { 989 void* result = NULL; 990 size_t size = 0; 991 const void* data = LoadResource(type, id, &size); 992 if (data != NULL) { 993 if ((result = malloc(size))) 994 memcpy(result, data, size); 995 } 996 if (lengthFound) 997 *lengthFound = size; 998 return result; 999 } 1000 1001 // FindResource 1002 /*! \brief Finds a resource by type and name and returns a copy of its data. 1003 The caller is responsible for free()ing the returned memory. 1004 \param type the type of the resource 1005 \param name the name of the resource 1006 \param lengthFound a pointer to a variable into which the size of the 1007 resource data shall be written 1008 \return 1009 - a pointer to the resource data, if everything went fine, 1010 - \c NULL, if an error occured. 1011 \deprecated Use LoadResource(). 1012 */ 1013 void* 1014 BResources::FindResource(type_code type, const char* name, size_t* lengthFound) 1015 { 1016 void* result = NULL; 1017 size_t size = 0; 1018 const void *data = LoadResource(type, name, &size); 1019 if (data != NULL) { 1020 if ((result = malloc(size))) 1021 memcpy(result, data, size); 1022 } 1023 if (lengthFound) 1024 *lengthFound = size; 1025 return result; 1026 } 1027 1028 1029 // FBC 1030 void BResources::_ReservedResources1() {} 1031 void BResources::_ReservedResources2() {} 1032 void BResources::_ReservedResources3() {} 1033 void BResources::_ReservedResources4() {} 1034 void BResources::_ReservedResources5() {} 1035 void BResources::_ReservedResources6() {} 1036 void BResources::_ReservedResources7() {} 1037 void BResources::_ReservedResources8() {} 1038 1039 1040 1041 1042