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