1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All rights reserved.
33*/
34
35
36#include "AttributeStream.h"
37
38#include <Debug.h>
39#include <Node.h>
40
41#include "Utilities.h"
42
43
44// ToDo:
45// lazy Rewind from Drive, only if data is available
46// BMessage node
47// partial feeding (part, not the whole buffer)
48
49
50//	#pragma mark - AttributeInfo
51
52
53AttributeInfo::AttributeInfo()
54	:
55	fName("")
56{
57	fInfo.type = B_RAW_TYPE;
58	fInfo.size = 0;
59}
60
61
62AttributeInfo::AttributeInfo(const AttributeInfo& other)
63	:
64	fName(other.fName),
65	fInfo(other.fInfo)
66
67{
68}
69
70
71AttributeInfo::AttributeInfo(const char* name, attr_info info)
72	:
73	fName(name),
74	fInfo(info)
75{
76}
77
78
79AttributeInfo::AttributeInfo(const char* name, uint32 type, off_t size)
80	:
81	fName(name)
82{
83	fInfo.type = type;
84	fInfo.size = size;
85}
86
87
88const char*
89AttributeInfo::Name() const
90{
91	return fName.String();
92}
93
94
95uint32
96AttributeInfo::Type() const
97{
98	return fInfo.type;
99}
100
101
102off_t
103AttributeInfo::Size() const
104{
105	return fInfo.size;
106}
107
108
109void
110AttributeInfo::SetTo(const AttributeInfo& other)
111{
112	fName = other.fName;
113	fInfo = other.fInfo;
114}
115
116
117void
118AttributeInfo::SetTo(const char* name, attr_info info)
119{
120	fName = name;
121	fInfo = info;
122}
123
124
125void
126AttributeInfo::SetTo(const char* name, uint32 type, off_t size)
127{
128	fName = name;
129	fInfo.type = type;
130	fInfo.size = size;
131}
132
133
134//	#pragma mark - AttributeStreamNode
135
136
137AttributeStreamNode::AttributeStreamNode()
138	:
139	fReadFrom(NULL),
140	fWriteTo(NULL)
141{
142}
143
144
145AttributeStreamNode::~AttributeStreamNode()
146{
147	Detach();
148}
149
150
151AttributeStreamNode&
152AttributeStreamNode::operator<<(AttributeStreamNode &source)
153{
154	fReadFrom = &source;
155	fReadFrom->fWriteTo = this;
156	if (fReadFrom->CanFeed())
157		fReadFrom->Start();
158
159	return source;
160}
161
162
163void
164AttributeStreamNode::Rewind()
165{
166	if (fReadFrom != NULL)
167		fReadFrom->Rewind();
168}
169
170
171void
172AttributeStreamFileNode::MakeEmpty()
173{
174	TRESPASS();
175}
176
177
178off_t
179AttributeStreamNode::Contains(const char* name, uint32 type)
180{
181	if (fReadFrom == NULL)
182		return 0;
183
184	return fReadFrom->Contains(name, type);
185}
186
187
188off_t
189AttributeStreamNode::Read(const char* name, const char* foreignName,
190	uint32 type, off_t size, void* buffer, void (*swapFunc)(void*))
191{
192	if (fReadFrom == NULL)
193		return 0;
194
195	return fReadFrom->Read(name, foreignName, type, size, buffer, swapFunc);
196}
197
198
199off_t
200AttributeStreamNode::Write(const char* name, const char* foreignName,
201	uint32 type, off_t size, const void* buffer)
202{
203	if (fWriteTo == NULL)
204		return 0;
205
206	return fWriteTo->Write(name, foreignName, type, size, buffer);
207}
208
209
210bool
211AttributeStreamNode::Drive()
212{
213	ASSERT(CanFeed());
214	if (fReadFrom == NULL)
215		return false;
216
217	Rewind();
218	return true;
219}
220
221
222const AttributeInfo*
223AttributeStreamNode::Next()
224{
225	if (fReadFrom != NULL)
226		return fReadFrom->Next();
227
228	return NULL;
229}
230
231
232const char*
233AttributeStreamNode::Get()
234{
235	ASSERT(fReadFrom != NULL);
236
237	return fReadFrom->Get();
238}
239
240
241bool
242AttributeStreamNode::Fill(char* buffer) const
243{
244	ASSERT(fReadFrom != NULL);
245
246	return fReadFrom->Fill(buffer);
247}
248
249
250bool
251AttributeStreamNode::Start()
252{
253	if (fWriteTo == NULL) {
254		// we are at the head of the stream, start drivin'
255		return Drive();
256	}
257
258	return fWriteTo->Start();
259}
260
261
262void
263AttributeStreamNode::Detach()
264{
265	AttributeStreamNode* tmpFrom = fReadFrom;
266	AttributeStreamNode* tmpTo = fWriteTo;
267	fReadFrom = NULL;
268	fWriteTo = NULL;
269
270	if (tmpFrom != NULL)
271		tmpFrom->Detach();
272
273	if (tmpTo != NULL)
274		tmpTo->Detach();
275}
276
277
278//	#pragma mark - AttributeStreamFileNode
279
280
281AttributeStreamFileNode::AttributeStreamFileNode()
282	:
283	fNode(NULL)
284{
285}
286
287
288AttributeStreamFileNode::AttributeStreamFileNode(BNode* node)
289	:
290	fNode(node)
291{
292	ASSERT(fNode != NULL);
293}
294
295
296void
297AttributeStreamFileNode::Rewind()
298{
299	_inherited::Rewind();
300	fNode->RewindAttrs();
301}
302
303
304void
305AttributeStreamFileNode::SetTo(BNode* node)
306{
307	fNode = node;
308}
309
310
311off_t
312AttributeStreamFileNode::Contains(const char* name, uint32 type)
313{
314	ThrowOnAssert(fNode != NULL);
315
316	attr_info info;
317	if (fNode->GetAttrInfo(name, &info) != B_OK)
318		return 0;
319
320	if (info.type != type)
321		return 0;
322
323	return info.size;
324}
325
326
327off_t
328AttributeStreamFileNode::Read(const char* name, const char* foreignName,
329	uint32 type, off_t size, void* buffer, void (*swapFunc)(void*))
330{
331	if (name != NULL
332		&& fNode->ReadAttr(name, type, 0, buffer, (size_t)size) == size) {
333		return size;
334	}
335
336	// didn't find the attribute under the native name, try the foreign name
337	if (foreignName != NULL && fNode->ReadAttr(foreignName, type, 0, buffer,
338			(size_t)size) == size) {
339		// foreign attribute, swap the data
340		if (swapFunc != NULL)
341			(swapFunc)(buffer);
342
343		return size;
344	}
345
346	return 0;
347}
348
349
350off_t
351AttributeStreamFileNode::Write(const char* name, const char* foreignName,
352	uint32 type, off_t size, const void* buffer)
353{
354	ThrowOnAssert(fNode != NULL);
355
356	off_t result = fNode->WriteAttr(name, type, 0, buffer, (size_t)size);
357	if (result == size && foreignName != NULL) {
358		// the write operation worked fine, remove the foreign attribute
359		// to not let stale data hang around
360		fNode->RemoveAttr(foreignName);
361	}
362
363	return result;
364}
365
366
367bool
368AttributeStreamFileNode::Drive()
369{
370	if (!_inherited::Drive())
371		return false;
372
373	ThrowOnAssert(fNode != NULL);
374
375	const AttributeInfo* attr;
376	while ((attr = fReadFrom->Next()) != 0) {
377		const char* data = fReadFrom->Get();
378		off_t result = fNode->WriteAttr(attr->Name(), attr->Type(), 0,
379			data, (size_t)attr->Size());
380		if (result < attr->Size())
381			return true;
382	}
383
384	return true;
385}
386
387
388const char*
389AttributeStreamFileNode::Get()
390{
391	ASSERT(fNode != NULL);
392	TRESPASS();
393
394	return NULL;
395}
396
397
398bool
399AttributeStreamFileNode::Fill(char* buffer) const
400{
401	ThrowOnAssert(fNode != NULL);
402
403	return fNode->ReadAttr(fCurrentAttr.Name(), fCurrentAttr.Type(), 0,
404		buffer, (size_t)fCurrentAttr.Size()) == (ssize_t)fCurrentAttr.Size();
405}
406
407
408const AttributeInfo*
409AttributeStreamFileNode::Next()
410{
411	ASSERT(fReadFrom == NULL);
412	ThrowOnAssert(fNode != NULL);
413
414	char attrName[256];
415	if (fNode->GetNextAttrName(attrName) != B_OK)
416		return NULL;
417
418	attr_info info;
419	if (fNode->GetAttrInfo(attrName, &info) != B_OK)
420		return NULL;
421
422	fCurrentAttr.SetTo(attrName, info);
423
424	return &fCurrentAttr;
425}
426
427
428//	#pragma mark - AttributeStreamMemoryNode
429
430
431AttributeStreamMemoryNode::AttributeStreamMemoryNode()
432	:
433	fAttributes(5, true),
434	fCurrentIndex(-1)
435{
436}
437
438
439void
440AttributeStreamMemoryNode::MakeEmpty()
441{
442	fAttributes.MakeEmpty();
443}
444
445
446void
447AttributeStreamMemoryNode::Rewind()
448{
449	_inherited::Rewind();
450	fCurrentIndex = -1;
451}
452
453
454int32
455AttributeStreamMemoryNode::Find(const char* name, uint32 type) const
456{
457	int32 count = fAttributes.CountItems();
458	for (int32 index = 0; index < count; index++) {
459		if (strcmp(fAttributes.ItemAt(index)->fAttr.Name(), name) == 0
460			&& fAttributes.ItemAt(index)->fAttr.Type() == type) {
461			return index;
462		}
463	}
464
465	return -1;
466}
467
468
469off_t
470AttributeStreamMemoryNode::Contains(const char* name, uint32 type)
471{
472	int32 index = Find(name, type);
473
474	return index < 0 ? 0 : fAttributes.ItemAt(index)->fAttr.Size();
475}
476
477
478off_t
479AttributeStreamMemoryNode::Read(const char* name,
480	const char* DEBUG_ONLY(foreignName), uint32 type, off_t bufferSize,
481	void* buffer, void (*DEBUG_ONLY(swapFunc))(void*))
482{
483	ASSERT(foreignName == NULL);
484	ASSERT(swapFunc == NULL);
485
486	AttrNode* attrNode = NULL;
487
488	int32 index = Find(name, type);
489	if (index < 0) {
490		if (fReadFrom == NULL)
491			return 0;
492
493		off_t size = fReadFrom->Contains(name, type);
494		if (size == 0)
495			return 0;
496
497		attrNode = BufferingGet(name, type, size);
498		if (attrNode == NULL)
499			return 0;
500	} else
501		attrNode = fAttributes.ItemAt(index);
502
503	if (attrNode->fAttr.Size() > bufferSize)
504		return 0;
505
506	memcpy(buffer, attrNode->fData, (size_t)attrNode->fAttr.Size());
507
508	return attrNode->fAttr.Size();
509}
510
511
512off_t
513AttributeStreamMemoryNode::Write(const char* name, const char*, uint32 type,
514	off_t size, const void* buffer)
515{
516	char* newBuffer = new char[size];
517	memcpy(newBuffer, buffer, (size_t)size);
518
519	AttrNode* attrNode = new AttrNode(name, type, size, newBuffer);
520	fAttributes.AddItem(attrNode);
521
522	return size;
523}
524
525
526bool
527AttributeStreamMemoryNode::Drive()
528{
529	if (!_inherited::Drive())
530		return false;
531
532	while (BufferingGet())
533		;
534
535	return true;
536}
537
538
539AttributeStreamMemoryNode::AttrNode*
540AttributeStreamMemoryNode::BufferingGet(const char* name, uint32 type,
541	off_t size)
542{
543	char* newBuffer = new char[size];
544	if (!fReadFrom->Fill(newBuffer)) {
545		delete[] newBuffer;
546		return NULL;
547	}
548
549	AttrNode* attrNode = new AttrNode(name, type, size, newBuffer);
550	fAttributes.AddItem(attrNode);
551
552	return fAttributes.LastItem();
553}
554
555
556AttributeStreamMemoryNode::AttrNode*
557AttributeStreamMemoryNode::BufferingGet()
558{
559	if (fReadFrom == NULL)
560		return NULL;
561
562	const AttributeInfo* attr = fReadFrom->Next();
563	if (attr == NULL)
564		return NULL;
565
566	return BufferingGet(attr->Name(), attr->Type(), attr->Size());
567}
568
569
570const AttributeInfo*
571AttributeStreamMemoryNode::Next()
572{
573	if (fReadFrom != NULL) {
574		// the buffer is in the middle of the stream, get
575		// one buffer at a time
576		BufferingGet();
577	}
578
579	if (fCurrentIndex + 1 >= fAttributes.CountItems())
580		return NULL;
581
582	return &fAttributes.ItemAt(++fCurrentIndex)->fAttr;
583}
584
585
586const char*
587AttributeStreamMemoryNode::Get()
588{
589	ASSERT(fCurrentIndex < fAttributes.CountItems());
590
591	return fAttributes.ItemAt(fCurrentIndex)->fData;
592}
593
594
595bool
596AttributeStreamMemoryNode::Fill(char* buffer) const
597{
598	ASSERT(fCurrentIndex < fAttributes.CountItems());
599	memcpy(buffer, fAttributes.ItemAt(fCurrentIndex)->fData,
600		(size_t)fAttributes.ItemAt(fCurrentIndex)->fAttr.Size());
601
602	return true;
603}
604
605
606//	#pragma mark - AttributeStreamTemplateNode
607
608
609AttributeStreamTemplateNode::AttributeStreamTemplateNode(
610	const AttributeTemplate* attrTemplates, int32 count)
611	:
612	fAttributes(attrTemplates),
613	fCurrentIndex(-1),
614	fCount(count)
615{
616}
617
618
619off_t
620AttributeStreamTemplateNode::Contains(const char* name, uint32 type)
621{
622	int32 index = Find(name, type);
623	if (index < 0)
624		return 0;
625
626	return fAttributes[index].fSize;
627}
628
629
630void
631AttributeStreamTemplateNode::Rewind()
632{
633	fCurrentIndex = -1;
634}
635
636
637const AttributeInfo*
638AttributeStreamTemplateNode::Next()
639{
640	if (fCurrentIndex + 1 >= fCount)
641		return NULL;
642
643	++fCurrentIndex;
644
645	fCurrentAttr.SetTo(fAttributes[fCurrentIndex].fAttributeName,
646		fAttributes[fCurrentIndex].fAttributeType,
647		fAttributes[fCurrentIndex].fSize);
648
649	return &fCurrentAttr;
650}
651
652
653const char*
654AttributeStreamTemplateNode::Get()
655{
656	ASSERT(fCurrentIndex < fCount);
657
658	return fAttributes[fCurrentIndex].fBits;
659}
660
661
662bool
663AttributeStreamTemplateNode::Fill(char* buffer) const
664{
665	ASSERT(fCurrentIndex < fCount);
666	memcpy(buffer, fAttributes[fCurrentIndex].fBits,
667		(size_t)fAttributes[fCurrentIndex].fSize);
668
669	return true;
670}
671
672
673int32
674AttributeStreamTemplateNode::Find(const char* name, uint32 type) const
675{
676	for (int32 index = 0; index < fCount; index++) {
677		if (fAttributes[index].fAttributeType == type &&
678			strcmp(name, fAttributes[index].fAttributeName) == 0) {
679			return index;
680		}
681	}
682
683	return -1;
684}
685
686
687//	#pragma mark - AttributeStreamFilterNode
688
689
690bool
691AttributeStreamFilterNode::Reject(const char*, uint32, off_t)
692{
693	// simple pass everything filter
694	return false;
695}
696
697
698const AttributeInfo*
699AttributeStreamFilterNode::Next()
700{
701	if (fReadFrom == NULL)
702		return NULL;
703
704	for (;;) {
705		const AttributeInfo* attr = fReadFrom->Next();
706		if (attr == NULL)
707			break;
708
709		if (!Reject(attr->Name(), attr->Type(), attr->Size()))
710			return attr;
711	}
712
713	return NULL;
714}
715
716
717off_t
718AttributeStreamFilterNode::Contains(const char* name, uint32 type)
719{
720	if (fReadFrom == NULL)
721		return 0;
722
723	off_t size = fReadFrom->Contains(name, type);
724
725	if (!Reject(name, type, size))
726		return size;
727
728	return 0;
729}
730
731
732off_t
733AttributeStreamFilterNode::Read(const char* name, const char* foreignName,
734	uint32 type, off_t size, void* buffer, void (*swapFunc)(void*))
735{
736	if (fReadFrom == NULL)
737		return 0;
738
739	if (!Reject(name, type, size)) {
740		return fReadFrom->Read(name, foreignName, type, size, buffer,
741			swapFunc);
742	}
743
744	return 0;
745}
746
747
748off_t
749AttributeStreamFilterNode::Write(const char* name, const char* foreignName,
750	uint32 type, off_t size, const void* buffer)
751{
752	if (fWriteTo == NULL)
753		return 0;
754
755	if (!Reject(name, type, size))
756		return fWriteTo->Write(name, foreignName, type, size, buffer);
757
758	return size;
759}
760
761
762//	#pragma mark - NamesToAcceptAttrFilter
763
764
765NamesToAcceptAttrFilter::NamesToAcceptAttrFilter(const char** nameList)
766	:
767	fNameList(nameList)
768{
769}
770
771
772bool
773NamesToAcceptAttrFilter::Reject(const char* name, uint32, off_t)
774{
775	for (int32 index = 0; ; index++) {
776		if (fNameList[index] == NULL)
777			break;
778
779		if (strcmp(name, fNameList[index]) == 0) {
780			//PRINT(("filter passing through %s\n", name));
781			return false;
782		}
783	}
784
785	//PRINT(("filter rejecting %s\n", name));
786	return true;
787}
788
789
790//	#pragma mark - SelectiveAttributeTransformer
791
792
793SelectiveAttributeTransformer::SelectiveAttributeTransformer(
794	const char* attributeName,
795	bool (*transformFunc)(const char* , uint32 , off_t, void*, void*),
796	void* params)
797	:
798	fAttributeNameToTransform(attributeName),
799	fTransformFunc(transformFunc),
800	fTransformParams(params),
801	fTransformedBuffers(10, false)
802{
803}
804
805
806SelectiveAttributeTransformer::~SelectiveAttributeTransformer()
807{
808	for (int32 index = fTransformedBuffers.CountItems() - 1; index >= 0;
809			index--) {
810		delete[] fTransformedBuffers.ItemAt(index);
811	}
812}
813
814
815void
816SelectiveAttributeTransformer::Rewind()
817{
818	for (int32 index = fTransformedBuffers.CountItems() - 1; index >= 0;
819			index--) {
820		delete[] fTransformedBuffers.ItemAt(index);
821	}
822
823	fTransformedBuffers.MakeEmpty();
824}
825
826
827off_t
828SelectiveAttributeTransformer::Read(const char* name, const char* foreignName,
829	uint32 type, off_t size, void* buffer, void (*swapFunc)(void*))
830{
831	if (fReadFrom == NULL)
832		return 0;
833
834	off_t result = fReadFrom->Read(name, foreignName, type, size, buffer,
835		swapFunc);
836
837	if (WillTransform(name, type, size, (const char*)buffer))
838		ApplyTransformer(name, type, size, (char*)buffer);
839
840	return result;
841}
842
843
844bool
845SelectiveAttributeTransformer::WillTransform(const char* name, uint32, off_t,
846	const char*) const
847{
848	return strcmp(name, fAttributeNameToTransform) == 0;
849}
850
851
852bool
853SelectiveAttributeTransformer::ApplyTransformer(const char* name, uint32 type,
854	off_t size, char* data)
855{
856	return (fTransformFunc)(name, type, size, data, fTransformParams);
857}
858
859char*
860SelectiveAttributeTransformer::CopyAndApplyTransformer(const char* name,
861	uint32 type, off_t size, const char* data)
862{
863	char* result = NULL;
864
865	if (data != NULL) {
866		result = new char[size];
867		memcpy(result, data, (size_t)size);
868	}
869
870	if (!(fTransformFunc)(name, type, size, result, fTransformParams)) {
871		delete[] result;
872		return NULL;
873	}
874
875	return result;
876}
877
878
879const AttributeInfo*
880SelectiveAttributeTransformer::Next()
881{
882	const AttributeInfo* result = fReadFrom->Next();
883
884	if (result == NULL)
885		return NULL;
886
887	fCurrentAttr.SetTo(*result);
888	return result;
889}
890
891
892const char*
893SelectiveAttributeTransformer::Get()
894{
895	if (fReadFrom == NULL)
896		return NULL;
897
898	const char* result = fReadFrom->Get();
899
900	if (!WillTransform(fCurrentAttr.Name(), fCurrentAttr.Type(),
901			fCurrentAttr.Size(), result)) {
902		return result;
903	}
904
905	char* transformedData = CopyAndApplyTransformer(fCurrentAttr.Name(),
906		fCurrentAttr.Type(), fCurrentAttr.Size(), result);
907
908	// enlist for proper disposal when our job is done
909	if (transformedData != NULL) {
910		fTransformedBuffers.AddItem(transformedData);
911		return transformedData;
912	}
913
914	return result;
915}
916