headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / storage / Resources.cpp
blobb644f35256509fa7005e7fd6353231763d5b5cb2
1 /*
2 * Copyright 2001-2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * Copyright 2013 Haiku, Inc.
4 * All Rights Reserved. Distributed under the terms of the MIT License.
6 * Authors:
7 * John Scipione, jscipione@gmail.com
8 * Ingo Weinhold, bonefish@cs.tu-berlin.de
9 */
12 #include <Resources.h>
14 #include <new>
15 #include <stdio.h>
16 #include <stdlib.h>
18 #include "ResourceFile.h"
19 #include "ResourceItem.h"
20 #include "ResourcesContainer.h"
23 using namespace BPrivate::Storage;
24 using namespace std;
27 // debugging
28 //#define DBG(x) x
29 #define DBG(x)
30 #define OUT printf
33 // Creates an unitialized BResources object.
34 BResources::BResources()
36 fFile(),
37 fContainer(NULL),
38 fResourceFile(NULL),
39 fReadOnly(false)
41 fContainer = new(nothrow) ResourcesContainer;
45 // Creates a BResources object that represents the resources of the
46 // supplied file.
47 BResources::BResources(const BFile* file, bool clobber)
49 fFile(),
50 fContainer(NULL),
51 fResourceFile(NULL),
52 fReadOnly(false)
54 fContainer = new(nothrow) ResourcesContainer;
55 SetTo(file, clobber);
59 // Creates a BResources object that represents the resources of the
60 // file referenced by the supplied path.
61 BResources::BResources(const char* path, bool clobber)
63 fFile(),
64 fContainer(NULL),
65 fResourceFile(NULL),
66 fReadOnly(false)
68 fContainer = new(nothrow) ResourcesContainer;
69 SetTo(path, clobber);
73 // Creates a BResources object that represents the resources of the
74 // file referenced by the supplied ref.
75 BResources::BResources(const entry_ref* ref, bool clobber)
77 fFile(),
78 fContainer(NULL),
79 fResourceFile(NULL),
80 fReadOnly(false)
82 fContainer = new(nothrow) ResourcesContainer;
83 SetTo(ref, clobber);
87 // Frees all resources associated with this object
88 BResources::~BResources()
90 Unset();
91 delete fContainer;
95 // Initialized the BResources object to represent the resources of
96 // the supplied file.
97 status_t
98 BResources::SetTo(const BFile* file, bool clobber)
100 Unset();
101 status_t error = B_OK;
102 if (file) {
103 error = file->InitCheck();
104 if (error == B_OK) {
105 fFile = *file;
106 error = fFile.InitCheck();
108 if (error == B_OK) {
109 fReadOnly = !fFile.IsWritable();
110 fResourceFile = new(nothrow) ResourceFile;
111 if (fResourceFile)
112 error = fResourceFile->SetTo(&fFile, clobber);
113 else
114 error = B_NO_MEMORY;
116 if (error == B_OK) {
117 if (fContainer)
118 error = fResourceFile->InitContainer(*fContainer);
119 else
120 error = B_NO_MEMORY;
123 if (error != B_OK) {
124 delete fResourceFile;
125 fResourceFile = NULL;
126 if (fContainer)
127 fContainer->MakeEmpty();
129 return error;
133 // Initialized the BResources object to represent the resources of
134 // the file referred to by the supplied path.
135 status_t
136 BResources::SetTo(const char* path, bool clobber)
138 if (!path)
139 return B_BAD_VALUE;
141 // open file
142 BFile file;
143 status_t error = file.SetTo(path, B_READ_WRITE);
144 if (error != B_OK && error != B_ENTRY_NOT_FOUND)
145 error = file.SetTo(path, B_READ_ONLY);
146 if (error != B_OK) {
147 Unset();
148 return error;
151 // delegate the actual work
152 return SetTo(&file, clobber);
156 // Initialized the BResources object to represent the resources of the
157 // file referenced by the supplied ref.
158 status_t
159 BResources::SetTo(const entry_ref* ref, bool clobber)
161 if (!ref)
162 return B_BAD_VALUE;
164 // open file
165 BFile file;
166 status_t error = file.SetTo(ref, B_READ_WRITE);
167 if (error != B_OK && error != B_ENTRY_NOT_FOUND)
168 error = file.SetTo(ref, B_READ_ONLY);
169 if (error != B_OK) {
170 Unset();
171 return error;
174 // delegate the actual work
175 return SetTo(&file, clobber);
179 // Initialized the BResources object to represent the resources of
180 // the file from which the specified image has been loaded.
181 status_t
182 BResources::SetToImage(image_id image, bool clobber)
184 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
185 // get an image info
186 image_info info;
187 status_t error = get_image_info(image, &info);
188 if (error != B_OK) {
189 Unset();
190 return error;
193 // delegate the actual work
194 return SetTo(info.name, clobber);
195 #else // HAIKU_TARGET_PLATFORM_HAIKU
196 return B_NOT_SUPPORTED;
197 #endif
201 // Initialized the BResources object to represent the resources of
202 // the file from which the specified pointer has been loaded.
203 status_t
204 BResources::SetToImage(const void* codeOrDataPointer, bool clobber)
206 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
207 // iterate through the images and find the one in question
208 addr_t address = (addr_t)codeOrDataPointer;
209 image_info info;
210 int32 cookie = 0;
212 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
213 if (address == 0
214 ? info.type == B_APP_IMAGE
215 : (((addr_t)info.text <= address
216 && address - (addr_t)info.text < (addr_t)info.text_size)
217 || ((addr_t)info.data <= address
218 && address - (addr_t)info.data < (addr_t)info.data_size))) {
219 return SetTo(info.name, clobber);
223 return B_ENTRY_NOT_FOUND;
224 #else // HAIKU_TARGET_PLATFORM_HAIKU
225 return B_NOT_SUPPORTED;
226 #endif
230 // Returns the BResources object to an uninitialized state.
231 void
232 BResources::Unset()
234 if (fContainer && fContainer->IsModified())
235 Sync();
236 delete fResourceFile;
237 fResourceFile = NULL;
238 fFile.Unset();
239 if (fContainer)
240 fContainer->MakeEmpty();
241 else
242 fContainer = new(nothrow) ResourcesContainer;
243 fReadOnly = false;
247 // Gets the initialization status of the object.
248 status_t
249 BResources::InitCheck() const
251 return (fContainer ? B_OK : B_NO_MEMORY);
255 // Gets a reference to the internal BFile object.
256 const BFile&
257 BResources::File() const
259 return fFile;
263 // Loads a resource identified by type and id into memory.
264 const void*
265 BResources::LoadResource(type_code type, int32 id, size_t* _size)
267 // find the resource
268 status_t error = InitCheck();
269 ResourceItem* resource = NULL;
270 if (error == B_OK) {
271 resource = fContainer->ResourceAt(fContainer->IndexOf(type, id));
272 if (!resource)
273 error = B_ENTRY_NOT_FOUND;
275 // load it, if necessary
276 if (error == B_OK && !resource->IsLoaded() && fResourceFile)
277 error = fResourceFile->ReadResource(*resource);
278 // return the result
279 const void *result = NULL;
280 if (error == B_OK) {
281 result = resource->Data();
282 if (_size)
283 *_size = resource->DataSize();
285 return result;
289 // Loads a resource identified by type and name into memory.
290 const void*
291 BResources::LoadResource(type_code type, const char* name, size_t* _size)
293 // find the resource
294 status_t error = InitCheck();
295 ResourceItem* resource = NULL;
296 if (error == B_OK) {
297 resource = fContainer->ResourceAt(fContainer->IndexOf(type, name));
298 if (!resource)
299 error = B_ENTRY_NOT_FOUND;
301 // load it, if necessary
302 if (error == B_OK && !resource->IsLoaded() && fResourceFile)
303 error = fResourceFile->ReadResource(*resource);
304 // return the result
305 const void* result = NULL;
306 if (error == B_OK) {
307 result = resource->Data();
308 if (_size)
309 *_size = resource->DataSize();
311 return result;
315 // Loads all resources of the specified type into memory.
316 status_t
317 BResources::PreloadResourceType(type_code type)
319 status_t error = InitCheck();
320 if (error == B_OK && fResourceFile) {
321 if (type == 0)
322 error = fResourceFile->ReadResources(*fContainer);
323 else {
324 int32 count = fContainer->CountResources();
325 int32 errorCount = 0;
326 for (int32 i = 0; i < count; i++) {
327 ResourceItem *resource = fContainer->ResourceAt(i);
328 if (resource->Type() == type) {
329 if (fResourceFile->ReadResource(*resource) != B_OK)
330 errorCount++;
333 error = -errorCount;
336 return error;
340 // Writes all changes to the resources to the file.
341 status_t
342 BResources::Sync()
344 status_t error = InitCheck();
345 if (error == B_OK)
346 error = fFile.InitCheck();
347 if (error == B_OK) {
348 if (fReadOnly)
349 error = B_NOT_ALLOWED;
350 else if (!fResourceFile)
351 error = B_FILE_ERROR;
353 if (error == B_OK)
354 error = fResourceFile->ReadResources(*fContainer);
355 if (error == B_OK)
356 error = fResourceFile->WriteResources(*fContainer);
357 return error;
361 // Adds the resources of fromFile to the internal file of the
362 // BResources object.
363 status_t
364 BResources::MergeFrom(BFile* fromFile)
366 status_t error = (fromFile ? B_OK : B_BAD_VALUE);
367 if (error == B_OK)
368 error = InitCheck();
369 if (error == B_OK) {
370 ResourceFile resourceFile;
371 error = resourceFile.SetTo(fromFile);
372 ResourcesContainer container;
373 if (error == B_OK)
374 error = resourceFile.InitContainer(container);
375 if (error == B_OK)
376 error = resourceFile.ReadResources(container);
377 if (error == B_OK)
378 fContainer->AssimilateResources(container);
380 return error;
384 // Writes the resources to a new file.
385 status_t
386 BResources::WriteTo(BFile* file)
388 status_t error = (file ? B_OK : B_BAD_VALUE);
389 if (error == B_OK)
390 error = InitCheck();
391 // make sure, that all resources are loaded
392 if (error == B_OK && fResourceFile) {
393 error = fResourceFile->ReadResources(*fContainer);
394 fResourceFile->Unset();
396 // set the new file, but keep the old container
397 if (error == B_OK) {
398 ResourcesContainer *container = fContainer;
399 fContainer = new(nothrow) ResourcesContainer;
400 if (fContainer) {
401 error = SetTo(file, false);
402 delete fContainer;
403 } else
404 error = B_NO_MEMORY;
405 fContainer = container;
407 // write the resources
408 if (error == B_OK && fResourceFile)
409 error = fResourceFile->WriteResources(*fContainer);
410 return error;
414 // Adds a new resource to the file.
415 status_t
416 BResources::AddResource(type_code type, int32 id, const void* data,
417 size_t length, const char* name)
419 status_t error = (data ? B_OK : B_BAD_VALUE);
420 if (error == B_OK)
421 error = InitCheck();
422 if (error == B_OK)
423 error = (fReadOnly ? B_NOT_ALLOWED : B_OK);
424 if (error == B_OK) {
425 ResourceItem* item = new(nothrow) ResourceItem;
426 if (!item)
427 error = B_NO_MEMORY;
428 if (error == B_OK) {
429 item->SetIdentity(type, id, name);
430 ssize_t written = item->WriteAt(0, data, length);
431 if (written < 0)
432 error = written;
433 else if (written != (ssize_t)length)
434 error = B_ERROR;
436 if (error == B_OK) {
437 if (!fContainer->AddResource(item))
438 error = B_NO_MEMORY;
440 if (error != B_OK)
441 delete item;
443 return error;
447 // Returns whether the file contains a resource with the specified
448 // type and id.
449 bool
450 BResources::HasResource(type_code type, int32 id)
452 return (InitCheck() == B_OK && fContainer->IndexOf(type, id) >= 0);
456 // Returns whether the file contains a resource with the specified
457 // type and name.
458 bool
459 BResources::HasResource(type_code type, const char* name)
461 return (InitCheck() == B_OK && fContainer->IndexOf(type, name) >= 0);
465 // Gets information about a resource identified by byindex.
466 bool
467 BResources::GetResourceInfo(int32 byIndex, type_code* typeFound,
468 int32* idFound, const char** nameFound, size_t* lengthFound)
470 ResourceItem* item = NULL;
471 if (InitCheck() == B_OK)
472 item = fContainer->ResourceAt(byIndex);
473 if (item) {
474 if (typeFound)
475 *typeFound = item->Type();
476 if (idFound)
477 *idFound = item->ID();
478 if (nameFound)
479 *nameFound = item->Name();
480 if (lengthFound)
481 *lengthFound = item->DataSize();
483 return item;
487 // Gets information about a resource identified by byType and andIndex.
488 bool
489 BResources::GetResourceInfo(type_code byType, int32 andIndex, int32* idFound,
490 const char** nameFound, size_t* lengthFound)
492 ResourceItem* item = NULL;
493 if (InitCheck() == B_OK) {
494 item = fContainer->ResourceAt(fContainer->IndexOfType(byType,
495 andIndex));
497 if (item) {
498 if (idFound)
499 *idFound = item->ID();
500 if (nameFound)
501 *nameFound = item->Name();
502 if (lengthFound)
503 *lengthFound = item->DataSize();
505 return item;
509 // Gets information about a resource identified by byType and andID.
510 bool
511 BResources::GetResourceInfo(type_code byType, int32 andID,
512 const char** nameFound, size_t* lengthFound)
514 ResourceItem* item = NULL;
515 if (InitCheck() == B_OK)
516 item = fContainer->ResourceAt(fContainer->IndexOf(byType, andID));
517 if (item) {
518 if (nameFound)
519 *nameFound = item->Name();
520 if (lengthFound)
521 *lengthFound = item->DataSize();
523 return item;
527 // Gets information about a resource identified by byType and andName.
528 bool
529 BResources::GetResourceInfo(type_code byType, const char* andName,
530 int32* idFound, size_t* lengthFound)
532 ResourceItem* item = NULL;
533 if (InitCheck() == B_OK)
534 item = fContainer->ResourceAt(fContainer->IndexOf(byType, andName));
535 if (item) {
536 if (idFound)
537 *idFound = item->ID();
538 if (lengthFound)
539 *lengthFound = item->DataSize();
541 return item;
545 // Gets information about a resource identified by byPointer.
546 bool
547 BResources::GetResourceInfo(const void* byPointer, type_code* typeFound,
548 int32* idFound, size_t* lengthFound, const char** nameFound)
550 ResourceItem* item = NULL;
551 if (InitCheck() == B_OK)
552 item = fContainer->ResourceAt(fContainer->IndexOf(byPointer));
553 if (item) {
554 if (typeFound)
555 *typeFound = item->Type();
556 if (idFound)
557 *idFound = item->ID();
558 if (nameFound)
559 *nameFound = item->Name();
560 if (lengthFound)
561 *lengthFound = item->DataSize();
563 return item;
567 // Removes a resource identified by its data pointer.
568 status_t
569 BResources::RemoveResource(const void* resource)
571 status_t error = (resource ? B_OK : B_BAD_VALUE);
572 if (error == B_OK)
573 error = InitCheck();
574 if (error == B_OK)
575 error = (fReadOnly ? B_NOT_ALLOWED : B_OK);
576 if (error == B_OK) {
577 ResourceItem* item
578 = fContainer->RemoveResource(fContainer->IndexOf(resource));
579 if (item)
580 delete item;
581 else
582 error = B_BAD_VALUE;
584 return error;
588 // Removes a resource identified by type and id.
589 status_t
590 BResources::RemoveResource(type_code type, int32 id)
592 status_t error = InitCheck();
593 if (error == B_OK)
594 error = (fReadOnly ? B_NOT_ALLOWED : B_OK);
595 if (error == B_OK) {
596 ResourceItem* item
597 = fContainer->RemoveResource(fContainer->IndexOf(type, id));
598 if (item)
599 delete item;
600 else
601 error = B_BAD_VALUE;
603 return error;
607 // #pragma mark - deprecated methods
610 // Writes data into an existing resource
611 // (deprecated, use AddResource() instead).
612 status_t
613 BResources::WriteResource(type_code type, int32 id, const void* data,
614 off_t offset, size_t length)
616 status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE);
617 if (error == B_OK)
618 error = InitCheck();
619 if (error == B_OK)
620 error = (fReadOnly ? B_NOT_ALLOWED : B_OK);
622 if (error != B_OK)
623 return error;
625 ResourceItem *item = fContainer->ResourceAt(fContainer->IndexOf(type, id));
626 if (!item)
627 return B_BAD_VALUE;
629 if (fResourceFile) {
630 error = fResourceFile->ReadResource(*item);
631 if (error != B_OK)
632 return error;
635 ssize_t written = item->WriteAt(offset, data, length);
637 if (written < 0)
638 error = written;
639 else if (written != (ssize_t)length)
640 error = B_ERROR;
642 return error;
646 // Reads data from an existing resource
647 // (deprecated, use LoadResource() instead).
648 status_t
649 BResources::ReadResource(type_code type, int32 id, void* data, off_t offset,
650 size_t length)
652 status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE);
653 if (error == B_OK)
654 error = InitCheck();
655 ResourceItem* item = NULL;
656 if (error == B_OK) {
657 item = fContainer->ResourceAt(fContainer->IndexOf(type, id));
658 if (!item)
659 error = B_BAD_VALUE;
661 if (error == B_OK && fResourceFile)
662 error = fResourceFile->ReadResource(*item);
663 if (error == B_OK) {
664 if (item) {
665 ssize_t read = item->ReadAt(offset, data, length);
666 if (read < 0)
667 error = read;
668 } else
669 error = B_BAD_VALUE;
671 return error;
675 // Finds a resource by type and id and returns a pointer to a copy of
676 // its data (deprecated, use LoadResource() instead).
677 void*
678 BResources::FindResource(type_code type, int32 id, size_t* lengthFound)
680 void* result = NULL;
681 size_t size = 0;
682 const void* data = LoadResource(type, id, &size);
683 if (data != NULL) {
684 if ((result = malloc(size)))
685 memcpy(result, data, size);
687 if (lengthFound)
688 *lengthFound = size;
689 return result;
693 // Finds a resource by type and name and returns a pointer to a copy of
694 // its data (deprecated, use LoadResource() instead).
695 void*
696 BResources::FindResource(type_code type, const char* name, size_t* lengthFound)
698 void* result = NULL;
699 size_t size = 0;
700 const void *data = LoadResource(type, name, &size);
701 if (data != NULL) {
702 if ((result = malloc(size)))
703 memcpy(result, data, size);
705 if (lengthFound)
706 *lengthFound = size;
707 return result;
711 // FBC
712 void BResources::_ReservedResources1() {}
713 void BResources::_ReservedResources2() {}
714 void BResources::_ReservedResources3() {}
715 void BResources::_ReservedResources4() {}
716 void BResources::_ReservedResources5() {}
717 void BResources::_ReservedResources6() {}
718 void BResources::_ReservedResources7() {}
719 void BResources::_ReservedResources8() {}