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