btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / deskbar / ResourceSet.cpp
blobf80f082cca480426306a28f40f877e703ae90e08
1 /*
2 Open Tracker License
4 Terms and Conditions
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
32 holders.
33 All rights reserved.
37 #define USE_RESOURCES 1
39 #include "ResourceSet.h"
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <ctype.h>
45 #include <Application.h>
46 #include <Autolock.h>
47 #include <Bitmap.h>
48 #include <DataIO.h>
49 #include <Debug.h>
50 #include <Entry.h>
51 #include <File.h>
52 #include <Path.h>
53 #include <String.h>
55 #if USE_RESOURCES
56 #include <Resources.h>
57 #endif
59 #if USE_RESOURCES
60 #define RESOURCES_ONLY(x) x
61 #else
62 #define RESOURCES_ONLY(x)
63 #endif
66 namespace TResourcePrivate {
67 class TypeObject {
68 public:
69 TypeObject()
70 : fDeleteOK(false)
74 virtual ~TypeObject()
76 if (!fDeleteOK)
77 debugger("deleting object owned by BResourceSet");
80 void Delete()
82 fDeleteOK = true;
85 private:
86 TypeObject(const TypeObject &);
87 TypeObject &operator=(const TypeObject &);
88 bool operator==(const TypeObject &);
89 bool operator!=(const TypeObject &);
91 bool fDeleteOK;
94 class BitmapTypeItem : public BBitmap, public TypeObject {
95 public:
96 BitmapTypeItem(BRect bounds, uint32 flags, color_space depth,
97 int32 bytesPerRow = B_ANY_BYTES_PER_ROW, screen_id screenID
98 = B_MAIN_SCREEN_ID)
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)
110 : BBitmap(data)
114 virtual ~BitmapTypeItem()
119 class StringBlockTypeItem : public TStringBlock, public TypeObject {
120 public:
121 StringBlockTypeItem(BDataIO* data)
122 : TStringBlock(data)
126 StringBlockTypeItem(const void* block, size_t size)
127 : TStringBlock(block, size)
131 virtual ~StringBlockTypeItem()
136 class TypeItem {
137 public:
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)
146 : fID(id),
147 fName(name),
148 fData(NULL),
149 fSize(0),
150 fObject(NULL),
151 fOwnData(true),
152 fSourceIsFile(false)
154 off_t size;
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 ) {
159 free(fData);
160 fData = NULL;
161 fSize = 0;
166 virtual ~TypeItem()
168 if (fOwnData) {
169 free(fData);
170 fData = NULL;
171 fSize = 0;
173 SetObject(NULL);
176 int32 ID() const
178 return fID;
181 const char* Name() const
183 return fName.String();
186 const void* Data() const
188 return fData;
191 size_t Size() const
193 return fSize;
196 void SetObject(TypeObject* object)
198 if (object == fObject)
199 return;
200 if (fObject)
201 fObject->Delete();
202 fObject = object;
205 TypeObject* Object() const
207 return fObject;
210 void SetSourceIsFile(bool state)
212 fSourceIsFile = state;
215 bool SourceIsFile() const
217 return fSourceIsFile;
220 private:
221 int32 fID;
222 BString fName;
223 void* fData;
224 size_t fSize;
225 TypeObject* fObject;
226 bool fOwnData;
227 bool fSourceIsFile;
230 static bool FreeTypeItemFunc(void* item)
232 delete reinterpret_cast<TypeItem*>(item);
233 return false;
236 class TypeList {
237 public:
238 TypeList(type_code type)
239 : fType(type)
243 virtual ~TypeList()
245 fItems.DoForEach(FreeTypeItemFunc);
246 fItems.MakeEmpty();
249 type_code Type() const
251 return fType;
254 TypeItem* FindItemByID(int32 id)
256 for (int32 i = fItems.CountItems() - 1; i >= 0; i--) {
257 TypeItem* it = (TypeItem*)fItems.ItemAt(i);
258 if (it->ID() == id)
259 return it;
261 return NULL;
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)
269 return it;
271 return NULL;
274 void AddItem(TypeItem* item)
276 fItems.AddItem(item);
279 private:
280 type_code fType;
281 BList fItems;
285 using namespace TResourcePrivate;
287 // #pragma mark -
288 // ----------------------------- TStringBlock -----------------------------
291 TStringBlock::TStringBlock(BDataIO* data)
292 : fNumEntries(0),
293 fIndex(0),
294 fStrings(NULL),
295 fOwnData(true)
297 fStrings = (char*)malloc(1024);
298 size_t pos = 0;
299 ssize_t amount;
300 while ((amount = data->Read(fStrings + pos, 1024)) == 1024) {
301 pos += amount;
302 fStrings = (char*)realloc(fStrings, pos + 1024);
304 if (amount > 0)
305 pos += amount;
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)
315 fNumEntries(0),
316 fIndex(0),
317 fStrings(NULL),
318 fOwnData(false)
320 fIndex = (size_t*)const_cast<void*>(block);
321 fStrings = (char*)const_cast<void*>(block);
323 // Figure out how many entries there are.
324 size_t last_off = 0;
325 while (fIndex[fNumEntries] > last_off && fIndex[fNumEntries] < size ) {
326 last_off = fIndex[fNumEntries];
327 fNumEntries++;
332 TStringBlock::~TStringBlock()
334 if (fOwnData) {
335 free(fIndex);
336 free(fStrings);
338 fIndex = 0;
339 fStrings = NULL;
343 const char*
344 TStringBlock::String(size_t index) const
346 if (index >= fNumEntries)
347 return NULL;
349 return fStrings + fIndex[index];
353 size_t
354 TStringBlock::PreIndex(char* strings, ssize_t len)
356 size_t count = 0;
357 char* orig = strings;
358 char* end = strings + len;
359 bool in_cr = false;
360 bool first = true;
361 bool skipping = false;
363 while (orig < end) {
364 if (*orig == '\n' || *orig == '\r' || *orig == 0) {
365 if (!in_cr && *orig == '\r')
366 in_cr = true;
367 if (in_cr && *orig == '\n') {
368 orig++;
369 continue;
371 first = true;
372 skipping = false;
373 *strings = 0;
374 count++;
375 } else if (first && *orig == '#') {
376 skipping = true;
377 first = false;
378 orig++;
379 continue;
380 } else if (skipping) {
381 orig++;
382 continue;
383 } else if (*orig == '\\' && (orig + 1) < end) {
384 orig++;
385 switch (*orig) {
386 case '\\':
387 *strings = '\\';
388 break;
390 case '\n':
391 *strings = '\n';
392 break;
394 case '\r':
395 *strings = '\r';
396 break;
398 case '\t':
399 *strings = '\t';
400 break;
402 default:
403 *strings = *orig;
404 break;
406 } else
407 *strings = *orig;
409 orig++;
410 strings++;
412 return count;
416 void
417 TStringBlock::MakeIndex(const char* strings, ssize_t len,
418 size_t indexLength, size_t* resultingIndex)
420 *resultingIndex++ = 0;
421 indexLength--;
423 ssize_t pos = 0;
424 while (pos < len && indexLength > 0) {
425 if (strings[pos] == 0 ) {
426 *resultingIndex++ = (size_t)pos + 1;
427 indexLength--;
429 pos++;
434 // #pragma mark -
437 #if USE_RESOURCES
438 static bool
439 FreeResourcesFunc(void* item)
441 delete reinterpret_cast<BResources*>(item);
442 return false;
444 #endif
447 static bool
448 FreePathFunc(void* item)
450 delete reinterpret_cast<BPath*>(item);
451 return false;
455 static bool
456 FreeTypeFunc(void* item)
458 delete reinterpret_cast<TypeList*>(item);
459 return false;
463 // #pragma mark -
464 // ----------------------------- TResourceSet -----------------------------
467 TResourceSet::TResourceSet()
472 TResourceSet::~TResourceSet()
474 BAutolock lock(&fLock);
475 #if USE_RESOURCES
476 fResources.DoForEach(FreeResourcesFunc);
477 fResources.MakeEmpty();
478 #endif
479 fDirectories.DoForEach(FreePathFunc);
480 fDirectories.MakeEmpty();
481 fTypes.DoForEach(FreeTypeFunc);
482 fTypes.MakeEmpty();
486 status_t
487 TResourceSet::AddResources(BResources* RESOURCES_ONLY(resources))
489 #if USE_RESOURCES
490 if (!resources)
491 return B_BAD_VALUE;
493 BAutolock lock(&fLock);
494 status_t err = fResources.AddItem(resources) ? B_OK : B_ERROR;
495 if (err != B_OK)
496 delete resources;
497 return err;
498 #else
499 return B_ERROR;
500 #endif
504 status_t
505 TResourceSet::AddDirectory(const char* fullPath)
507 if (!fullPath)
508 return B_BAD_VALUE;
510 BPath* path = new BPath(fullPath);
511 status_t err = path->InitCheck();
512 if (err != B_OK) {
513 delete path;
514 return err;
517 BAutolock lock(&fLock);
518 err = fDirectories.AddItem(path) ? B_OK : B_ERROR;
519 if (err != B_OK)
520 delete path;
522 return err;
526 status_t
527 TResourceSet::AddEnvDirectory(const char* in, const char* defaultValue)
529 BString buf;
530 status_t err = ExpandString(&buf, in);
532 if (err != B_OK) {
533 if (defaultValue)
534 return AddDirectory(defaultValue);
535 return err;
538 return AddDirectory(buf.String());
542 status_t
543 TResourceSet::ExpandString(BString* out, const char* in)
545 const char* start = in;
547 while (*in) {
548 if (*in == '$') {
549 if (start < in)
550 out->Append(start, (int32)(in - start));
552 in++;
553 char variableName[1024];
554 size_t i = 0;
555 if (*in == '{') {
556 in++;
557 while (*in && *in != '}' && i < sizeof(variableName) - 1)
558 variableName[i++] = *in++;
560 if (*in)
561 in++;
563 } else {
564 while ((isalnum(*in) || *in == '_')
565 && i < sizeof(variableName) - 1)
566 variableName[i++] = *in++;
569 start = in;
570 variableName[i] = '\0';
572 const char* val = getenv(variableName);
573 if (!val) {
574 PRINT(("Error: env var %s not found.\n", &variableName[0]));
575 return B_NAME_NOT_FOUND;
578 status_t err = ExpandString(out, val);
579 if (err != B_OK)
580 return err;
582 } else if (*in == '\\') {
583 if (start < in)
584 out->Append(start, (int32)(in - start));
585 in++;
586 start = in;
587 in++;
588 } else
589 in++;
592 if (start < in)
593 out->Append(start, (int32)(in - start));
595 return B_OK;
599 const void*
600 TResourceSet::FindResource(type_code type, int32 id, size_t* outSize)
602 TypeItem* item = FindItemID(type, id);
604 if (outSize)
605 *outSize = item ? item->Size() : 0;
607 return item ? item->Data() : NULL;
611 const void*
612 TResourceSet::FindResource(type_code type, const char* name, size_t* outSize)
614 TypeItem* item = FindItemName(type, name);
616 if (outSize)
617 *outSize = item ? item->Size() : 0;
619 return item ? item->Data() : NULL;
623 const BBitmap*
624 TResourceSet::FindBitmap(type_code type, int32 id)
626 return ReturnBitmapItem(type, FindItemID(type, id));
630 const BBitmap*
631 TResourceSet::FindBitmap(type_code type, const char* name)
633 return ReturnBitmapItem(type, FindItemName(type, name));
637 const TStringBlock*
638 TResourceSet::FindStringBlock(type_code type, int32 id)
640 return ReturnStringBlockItem(FindItemID(type, id));
644 const TStringBlock*
645 TResourceSet::FindStringBlock(type_code type, const char* name)
647 return ReturnStringBlockItem(FindItemName(type, name));
651 const char*
652 TResourceSet::FindString(type_code type, int32 id, uint32 index)
654 const TStringBlock* stringBlock = FindStringBlock(type, id);
656 if (!stringBlock)
657 return NULL;
659 return stringBlock->String(index);
663 const char*
664 TResourceSet::FindString(type_code type, const char* name, uint32 index)
666 const TStringBlock* stringBlock = FindStringBlock(type, name);
668 if (!stringBlock)
669 return NULL;
671 return stringBlock->String(index);
675 TypeList*
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)
683 return list;
686 return NULL;
690 TypeItem*
691 TResourceSet::FindItemID(type_code type, int32 id)
693 TypeList* list = FindTypeList(type);
694 TypeItem* item = NULL;
696 if (list)
697 item = list->FindItemByID(id);
699 if (!item)
700 item = LoadResource(type, id, 0, &list);
702 return item;
706 TypeItem*
707 TResourceSet::FindItemName(type_code type, const char* name)
709 TypeList* list = FindTypeList(type);
710 TypeItem* item = NULL;
712 if (list)
713 item = list->FindItemByName(name);
715 if (!item)
716 item = LoadResource(type, -1, name, &list);
718 return item;
722 TypeItem*
723 TResourceSet::LoadResource(type_code type, int32 id, const char* name,
724 TypeList** inOutList)
726 TypeItem* item = NULL;
728 if (name) {
729 BEntry entry;
731 // If a named resource, first look in directories.
732 fLock.Lock();
733 for (int32 i = fDirectories.CountItems() - 1; i >= 0; i--) {
734 BPath* dir = (BPath*)fDirectories.ItemAt(i);
735 if (dir) {
736 fLock.Unlock();
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);
745 fLock.Lock();
748 fLock.Unlock();
751 #if USE_RESOURCES
752 if (!item) {
753 // Look through resource objects for data.
754 fLock.Lock();
755 for (int32 i = fResources.CountItems() - 1; i >= 0; i--) {
756 BResources* resource = (BResources*)fResources.ItemAt(i);
757 if (resource) {
758 const void* data = NULL;
759 size_t size = 0;
760 if (id >= 0)
761 data = resource->LoadResource(type, id, &size);
762 else if (name != NULL)
763 data = resource->LoadResource(type, name, &size);
765 if (data && size) {
766 item = new TypeItem(id, name, data, size);
767 item->SetSourceIsFile(false);
771 fLock.Unlock();
773 #endif
775 if (item) {
776 TypeList* list = inOutList ? *inOutList : NULL;
777 if (!list) {
778 // Don't currently have a list for this type -- check if there is
779 // already one.
780 list = FindTypeList(type);
783 BAutolock lock(&fLock);
785 if (!list) {
786 // Need to make a new list for this type.
787 list = new TypeList(type);
788 fTypes.AddItem(list);
790 if (inOutList)
791 *inOutList = list;
793 list->AddItem(item);
796 return item;
800 BBitmap*
801 TResourceSet::ReturnBitmapItem(type_code, TypeItem* from)
803 if (!from)
804 return NULL;
806 TypeObject* obj = from->Object();
807 BitmapTypeItem* bitmap = dynamic_cast<BitmapTypeItem*>(obj);
808 if (bitmap)
809 return bitmap;
811 // Can't change an existing object.
812 if (obj)
813 return NULL;
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);
820 BMessage archive;
821 if (archive.Unflatten(&stream) == B_OK) {
822 bitmap = new BitmapTypeItem(&archive);
823 if (bitmap && bitmap->InitCheck() != B_OK) {
824 bitmap->Delete();
825 // allows us to delete this bitmap...
826 delete bitmap;
827 bitmap = NULL;
831 if (bitmap) {
832 BAutolock lock(&fLock);
833 if (from->Object() != NULL) {
834 // Whoops! Someone snuck in under us.
835 bitmap->Delete();
836 delete bitmap;
837 bitmap = dynamic_cast<BitmapTypeItem*>(from->Object());
838 } else
839 from->SetObject(bitmap);
842 return bitmap;
846 TStringBlock*
847 TResourceSet::ReturnStringBlockItem(TypeItem* from)
849 if (!from)
850 return NULL;
852 TypeObject* obj = from->Object();
853 StringBlockTypeItem* stringBlock = dynamic_cast<StringBlockTypeItem*>(obj);
854 if (stringBlock)
855 return stringBlock;
857 // Can't change an existing object.
858 if (obj)
859 return NULL;
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);
865 } else
866 stringBlock = new StringBlockTypeItem(from->Data(), from->Size());
868 if (stringBlock) {
869 BAutolock lock(&fLock);
870 if (from->Object() != NULL) {
871 // Whoops! Someone snuck in under us.
872 delete stringBlock;
873 stringBlock = dynamic_cast<StringBlockTypeItem*>(from->Object());
874 } else
875 from->SetObject(stringBlock);
878 return stringBlock;
882 // #pragma mark -
885 namespace TResourcePrivate {
886 TResourceSet* gResources = NULL;
887 BLocker gResourceLocker;
891 TResourceSet*
892 AppResSet()
894 // If already have it, return immediately.
895 if (gResources)
896 return gResources;
898 // Don't have 'em, lock access to make 'em.
899 if (!gResourceLocker.Lock())
900 return NULL;
901 if (gResources) {
902 // Whoops, somebody else already did. Oh well.
903 gResourceLocker.Unlock();
904 return gResources;
907 // Make 'em.
908 gResources = new TResourceSet;
909 gResources->AddResources(BApplication::AppResources());
910 gResourceLocker.Unlock();
911 return gResources;