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