6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
37 #define USE_RESOURCES 1
39 #include "ResourceSet.h"
45 #include <Application.h>
56 #include <Resources.h>
60 #define RESOURCES_ONLY(x) x
62 #define RESOURCES_ONLY(x)
66 namespace TResourcePrivate
{
77 debugger("deleting object owned by BResourceSet");
86 TypeObject(const TypeObject
&);
87 TypeObject
&operator=(const TypeObject
&);
88 bool operator==(const TypeObject
&);
89 bool operator!=(const TypeObject
&);
94 class BitmapTypeItem
: public BBitmap
, public TypeObject
{
96 BitmapTypeItem(BRect bounds
, uint32 flags
, color_space depth
,
97 int32 bytesPerRow
= B_ANY_BYTES_PER_ROW
, screen_id screenID
99 : BBitmap(bounds
, flags
, depth
, bytesPerRow
, screenID
)
103 BitmapTypeItem(const BBitmap
* source
, bool accepts_views
= false,
104 bool need_contiguous
= false)
105 : BBitmap(source
, accepts_views
, need_contiguous
)
109 BitmapTypeItem(BMessage
* data
)
114 virtual ~BitmapTypeItem()
119 class StringBlockTypeItem
: public TStringBlock
, public TypeObject
{
121 StringBlockTypeItem(BDataIO
* data
)
126 StringBlockTypeItem(const void* block
, size_t size
)
127 : TStringBlock(block
, size
)
131 virtual ~StringBlockTypeItem()
138 TypeItem(int32 id
, const char* name
, const void* data
, size_t size
)
139 : fID(id
), fName(name
),
140 fData(const_cast<void*>(data
)), fSize(size
), fObject(0),
141 fOwnData(false), fSourceIsFile(false)
145 TypeItem(int32 id
, const char* name
, BFile
* file
)
155 if (file
->GetSize(&size
) == B_OK
) {
156 fSize
= (size_t)size
;
157 fData
= malloc(fSize
);
158 if (file
->ReadAt(0, fData
, fSize
) < B_OK
) {
181 const char* Name() const
183 return fName
.String();
186 const void* Data() const
196 void SetObject(TypeObject
* object
)
198 if (object
== fObject
)
205 TypeObject
* Object() const
210 void SetSourceIsFile(bool state
)
212 fSourceIsFile
= state
;
215 bool SourceIsFile() const
217 return fSourceIsFile
;
230 static bool FreeTypeItemFunc(void* item
)
232 delete reinterpret_cast<TypeItem
*>(item
);
238 TypeList(type_code type
)
245 fItems
.DoForEach(FreeTypeItemFunc
);
249 type_code
Type() const
254 TypeItem
* FindItemByID(int32 id
)
256 for (int32 i
= fItems
.CountItems() - 1; i
>= 0; i
--) {
257 TypeItem
* it
= (TypeItem
*)fItems
.ItemAt(i
);
264 TypeItem
* FindItemByName(const char* name
)
266 for (int32 i
= fItems
.CountItems() - 1; i
>= 0; i
--) {
267 TypeItem
* it
= (TypeItem
*)fItems
.ItemAt(i
);
268 if (strcmp(it
->Name(), name
) == 0)
274 void AddItem(TypeItem
* item
)
276 fItems
.AddItem(item
);
285 using namespace TResourcePrivate
;
288 // ----------------------------- TStringBlock -----------------------------
291 TStringBlock::TStringBlock(BDataIO
* data
)
297 fStrings
= (char*)malloc(1024);
300 while ((amount
= data
->Read(fStrings
+ pos
, 1024)) == 1024) {
302 fStrings
= (char*)realloc(fStrings
, pos
+ 1024);
307 fNumEntries
= PreIndex(fStrings
, amount
);
308 fIndex
= (size_t*)malloc(sizeof(size_t) * fNumEntries
);
309 MakeIndex(fStrings
, amount
, fNumEntries
, fIndex
);
313 TStringBlock::TStringBlock(const void* block
, size_t size
)
320 fIndex
= (size_t*)const_cast<void*>(block
);
321 fStrings
= (char*)const_cast<void*>(block
);
323 // Figure out how many entries there are.
325 while (fIndex
[fNumEntries
] > last_off
&& fIndex
[fNumEntries
] < size
) {
326 last_off
= fIndex
[fNumEntries
];
332 TStringBlock::~TStringBlock()
344 TStringBlock::String(size_t index
) const
346 if (index
>= fNumEntries
)
349 return fStrings
+ fIndex
[index
];
354 TStringBlock::PreIndex(char* strings
, ssize_t len
)
357 char* orig
= strings
;
358 char* end
= strings
+ len
;
361 bool skipping
= false;
364 if (*orig
== '\n' || *orig
== '\r' || *orig
== 0) {
365 if (!in_cr
&& *orig
== '\r')
367 if (in_cr
&& *orig
== '\n') {
375 } else if (first
&& *orig
== '#') {
380 } else if (skipping
) {
383 } else if (*orig
== '\\' && (orig
+ 1) < end
) {
417 TStringBlock::MakeIndex(const char* strings
, ssize_t len
,
418 size_t indexLength
, size_t* resultingIndex
)
420 *resultingIndex
++ = 0;
424 while (pos
< len
&& indexLength
> 0) {
425 if (strings
[pos
] == 0 ) {
426 *resultingIndex
++ = (size_t)pos
+ 1;
439 FreeResourcesFunc(void* item
)
441 delete reinterpret_cast<BResources
*>(item
);
448 FreePathFunc(void* item
)
450 delete reinterpret_cast<BPath
*>(item
);
456 FreeTypeFunc(void* item
)
458 delete reinterpret_cast<TypeList
*>(item
);
464 // ----------------------------- TResourceSet -----------------------------
467 TResourceSet::TResourceSet()
472 TResourceSet::~TResourceSet()
474 BAutolock
lock(&fLock
);
476 fResources
.DoForEach(FreeResourcesFunc
);
477 fResources
.MakeEmpty();
479 fDirectories
.DoForEach(FreePathFunc
);
480 fDirectories
.MakeEmpty();
481 fTypes
.DoForEach(FreeTypeFunc
);
487 TResourceSet::AddResources(BResources
* RESOURCES_ONLY(resources
))
493 BAutolock
lock(&fLock
);
494 status_t err
= fResources
.AddItem(resources
) ? B_OK
: B_ERROR
;
505 TResourceSet::AddDirectory(const char* fullPath
)
510 BPath
* path
= new BPath(fullPath
);
511 status_t err
= path
->InitCheck();
517 BAutolock
lock(&fLock
);
518 err
= fDirectories
.AddItem(path
) ? B_OK
: B_ERROR
;
527 TResourceSet::AddEnvDirectory(const char* in
, const char* defaultValue
)
530 status_t err
= ExpandString(&buf
, in
);
534 return AddDirectory(defaultValue
);
538 return AddDirectory(buf
.String());
543 TResourceSet::ExpandString(BString
* out
, const char* in
)
545 const char* start
= in
;
550 out
->Append(start
, (int32
)(in
- start
));
553 char variableName
[1024];
557 while (*in
&& *in
!= '}' && i
< sizeof(variableName
) - 1)
558 variableName
[i
++] = *in
++;
564 while ((isalnum(*in
) || *in
== '_')
565 && i
< sizeof(variableName
) - 1)
566 variableName
[i
++] = *in
++;
570 variableName
[i
] = '\0';
572 const char* val
= getenv(variableName
);
574 PRINT(("Error: env var %s not found.\n", &variableName
[0]));
575 return B_NAME_NOT_FOUND
;
578 status_t err
= ExpandString(out
, val
);
582 } else if (*in
== '\\') {
584 out
->Append(start
, (int32
)(in
- start
));
593 out
->Append(start
, (int32
)(in
- start
));
600 TResourceSet::FindResource(type_code type
, int32 id
, size_t* outSize
)
602 TypeItem
* item
= FindItemID(type
, id
);
605 *outSize
= item
? item
->Size() : 0;
607 return item
? item
->Data() : NULL
;
612 TResourceSet::FindResource(type_code type
, const char* name
, size_t* outSize
)
614 TypeItem
* item
= FindItemName(type
, name
);
617 *outSize
= item
? item
->Size() : 0;
619 return item
? item
->Data() : NULL
;
624 TResourceSet::FindBitmap(type_code type
, int32 id
)
626 return ReturnBitmapItem(type
, FindItemID(type
, id
));
631 TResourceSet::FindBitmap(type_code type
, const char* name
)
633 return ReturnBitmapItem(type
, FindItemName(type
, name
));
638 TResourceSet::FindStringBlock(type_code type
, int32 id
)
640 return ReturnStringBlockItem(FindItemID(type
, id
));
645 TResourceSet::FindStringBlock(type_code type
, const char* name
)
647 return ReturnStringBlockItem(FindItemName(type
, name
));
652 TResourceSet::FindString(type_code type
, int32 id
, uint32 index
)
654 const TStringBlock
* stringBlock
= FindStringBlock(type
, id
);
659 return stringBlock
->String(index
);
664 TResourceSet::FindString(type_code type
, const char* name
, uint32 index
)
666 const TStringBlock
* stringBlock
= FindStringBlock(type
, name
);
671 return stringBlock
->String(index
);
676 TResourceSet::FindTypeList(type_code type
)
678 BAutolock
lock(&fLock
);
680 for (int32 i
= fTypes
.CountItems() - 1; i
>= 0; i
--) {
681 TypeList
* list
= (TypeList
*)fTypes
.ItemAt(i
);
682 if (list
&& list
->Type() == type
)
691 TResourceSet::FindItemID(type_code type
, int32 id
)
693 TypeList
* list
= FindTypeList(type
);
694 TypeItem
* item
= NULL
;
697 item
= list
->FindItemByID(id
);
700 item
= LoadResource(type
, id
, 0, &list
);
707 TResourceSet::FindItemName(type_code type
, const char* name
)
709 TypeList
* list
= FindTypeList(type
);
710 TypeItem
* item
= NULL
;
713 item
= list
->FindItemByName(name
);
716 item
= LoadResource(type
, -1, name
, &list
);
723 TResourceSet::LoadResource(type_code type
, int32 id
, const char* name
,
724 TypeList
** inOutList
)
726 TypeItem
* item
= NULL
;
731 // If a named resource, first look in directories.
733 for (int32 i
= fDirectories
.CountItems() - 1; i
>= 0; i
--) {
734 BPath
* dir
= (BPath
*)fDirectories
.ItemAt(i
);
737 BPath
path(dir
->Path(), name
);
738 if (entry
.SetTo(path
.Path(), true) == B_OK
) {
739 BFile
file(&entry
, B_READ_ONLY
);
740 if (file
.InitCheck() == B_OK
) {
741 item
= new TypeItem(id
, name
, &file
);
742 item
->SetSourceIsFile(true);
753 // Look through resource objects for data.
755 for (int32 i
= fResources
.CountItems() - 1; i
>= 0; i
--) {
756 BResources
* resource
= (BResources
*)fResources
.ItemAt(i
);
758 const void* data
= NULL
;
761 data
= resource
->LoadResource(type
, id
, &size
);
762 else if (name
!= NULL
)
763 data
= resource
->LoadResource(type
, name
, &size
);
766 item
= new TypeItem(id
, name
, data
, size
);
767 item
->SetSourceIsFile(false);
776 TypeList
* list
= inOutList
? *inOutList
: NULL
;
778 // Don't currently have a list for this type -- check if there is
780 list
= FindTypeList(type
);
783 BAutolock
lock(&fLock
);
786 // Need to make a new list for this type.
787 list
= new TypeList(type
);
788 fTypes
.AddItem(list
);
801 TResourceSet::ReturnBitmapItem(type_code
, TypeItem
* from
)
806 TypeObject
* obj
= from
->Object();
807 BitmapTypeItem
* bitmap
= dynamic_cast<BitmapTypeItem
*>(obj
);
811 // Can't change an existing object.
815 // Don't have a bitmap in the item -- we'll try to create one.
816 BMemoryIO
stream(from
->Data(), from
->Size());
818 // Try to read as an archived bitmap.
819 stream
.Seek(0, SEEK_SET
);
821 if (archive
.Unflatten(&stream
) == B_OK
) {
822 bitmap
= new BitmapTypeItem(&archive
);
823 if (bitmap
&& bitmap
->InitCheck() != B_OK
) {
825 // allows us to delete this bitmap...
832 BAutolock
lock(&fLock
);
833 if (from
->Object() != NULL
) {
834 // Whoops! Someone snuck in under us.
837 bitmap
= dynamic_cast<BitmapTypeItem
*>(from
->Object());
839 from
->SetObject(bitmap
);
847 TResourceSet::ReturnStringBlockItem(TypeItem
* from
)
852 TypeObject
* obj
= from
->Object();
853 StringBlockTypeItem
* stringBlock
= dynamic_cast<StringBlockTypeItem
*>(obj
);
857 // Can't change an existing object.
861 // Don't have a string block in the item -- we'll create one.
862 if (from
->SourceIsFile() ) {
863 BMemoryIO
stream(from
->Data(), from
->Size());
864 stringBlock
= new StringBlockTypeItem(&stream
);
866 stringBlock
= new StringBlockTypeItem(from
->Data(), from
->Size());
869 BAutolock
lock(&fLock
);
870 if (from
->Object() != NULL
) {
871 // Whoops! Someone snuck in under us.
873 stringBlock
= dynamic_cast<StringBlockTypeItem
*>(from
->Object());
875 from
->SetObject(stringBlock
);
885 namespace TResourcePrivate
{
886 TResourceSet
* gResources
= NULL
;
887 BLocker gResourceLocker
;
894 // If already have it, return immediately.
898 // Don't have 'em, lock access to make 'em.
899 if (!gResourceLocker
.Lock())
902 // Whoops, somebody else already did. Oh well.
903 gResourceLocker
.Unlock();
908 gResources
= new TResourceSet
;
909 gResources
->AddResources(BApplication::AppResources());
910 gResourceLocker
.Unlock();