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