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