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