xref: /haiku/src/kits/storage/Resources.cpp (revision d374a27286b8a52974a97dba0d5966ea026a665d)
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