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