1/*
2    File:       IrIASService.cpp
3
4    Contains:   Implementation of IrDA's silly name server
5
6*/
7
8#include "IrIASService.h"
9#include "CListIterator.h"
10#include "CBuffer.h"
11#include "IrDALog.h"
12
13// consider splitting these into n-tables, one for each class?
14
15#if (hasTracing > 0 && hasIASServiceTracing > 0)
16
17enum tracecodes {
18    kLogServiceNew = 1,
19    kLogServiceFree,
20    kLogClassNew,
21    kLogClassFree,
22    kLogAttrNew,
23    kLogAttrFree,
24    kLogNamedListFree,
25    kLogElementNew,
26    kLogElementFree
27};
28
29static
30EventTraceCauseDesc TraceEvents[] = {
31    {kLogServiceNew,        "IrService: service new, obj="},
32    {kLogServiceFree,       "IrService: service free, obj="},
33    {kLogClassNew,          "IrService: class new, obj="},
34    {kLogClassFree,         "IrService: class free, obj="},
35    {kLogAttrNew,           "IrService: attr new, obj="},
36    {kLogAttrFree,          "IrService: attr free, obj="},
37    {kLogNamedListFree,     "IrService: named list free, obj="},
38    {kLogElementNew,        "IrService: element new, obj="},
39    {kLogElementFree,       "IrService: element free, obj="}
40};
41
42#define XTRACE(x, y, z) IrDALogAdd( x, y, ((uintptr_t)z & 0xffff), TraceEvents, true )
43#else
44#define XTRACE(x, y, z) ((void)0)
45#endif
46
47#pragma mark
48//============== TIASService ==============
49
50//--------------------------------------------------------------------------------
51//      TIASService
52//--------------------------------------------------------------------------------
53#define super TIASNamedList
54OSDefineMetaClassAndStructors(TIASService, TIASNamedList);
55
56/*static*/
57TIASService *
58TIASService::tIASService(void)
59{
60    TIASService *obj = new TIASService;
61
62    XTRACE(kLogServiceNew, 0, obj);
63
64    if (obj && !obj->Init()) {      // this named list has no name
65	obj->release();
66	obj = nil;
67    }
68    return obj;
69}
70
71
72//--------------------------------------------------------------------------------
73//      free
74//--------------------------------------------------------------------------------
75void TIASService::free()
76{
77    long index;
78
79    XTRACE(kLogServiceFree, 0, this);
80
81    // Iterate thru the list of classes and delete each one.  Note that I'm not
82    // removing them because I'm depending on the CList destructor to do that for me.
83    for (index = 0; index < this->GetArraySize(); index++) {
84	TIASClass* theClass = (TIASClass*)this->At(index);
85	theClass->release();
86    }
87
88    super::free();
89
90} // TIASService::free
91
92
93//--------------------------------------------------------------------------------
94//      AddIntegerEntry
95//--------------------------------------------------------------------------------
96IrDAErr TIASService::AddIntegerEntry(const UChar* className, const UChar* attributeName, ULong intValue)
97{
98    TIASElement* theEntry;
99
100    // Create, initialize the new entry
101    theEntry = TIASElement::tIASElement(intValue);      // create and initialize
102    require(theEntry, Fail_Element_New);
103
104    // Let AddAttributeEntry finish the job (it will free theEntry if there are any errors)
105    return AddAttributeEntry(className, attributeName, theEntry);
106
107Fail_Element_New:
108    return kIrDAErrNoMemory;
109
110} // TIASService::AddIntegerEntry
111
112
113//--------------------------------------------------------------------------------
114//      AddStringEntry
115//--------------------------------------------------------------------------------
116IrDAErr TIASService::AddStringEntry(const UChar* className, const UChar* attributeName,
117				    const UChar* stringValue, const UChar charSet, const ULong length)
118{
119    TIASElement *theEntry;
120
121    // Create, initialize the new entry
122    theEntry = TIASElement::tIASElement(stringValue, charSet, length);      // create and initialize
123    require(theEntry, Fail_Element_New);
124
125    // Let AddAttributeEntry finish the job (it will free theEntry if there are any errors)
126    return AddAttributeEntry(className, attributeName, theEntry);
127
128Fail_Element_New:
129    return kIrDAErrNoMemory;
130
131} // TIASService::AddStringEntry
132
133
134//--------------------------------------------------------------------------------
135//      AddNBytesEntry
136//--------------------------------------------------------------------------------
137IrDAErr TIASService::AddNBytesEntry(const UChar* className, const UChar* attributeName, const UChar*  aFewBytes, ULong length)
138{
139    TIASElement* theEntry;
140
141    // Create, initialize the new entry
142    theEntry = TIASElement::tIASElement(aFewBytes, length);     // create and initialize
143    require(theEntry, Fail_Element_New);
144
145    // Let AddAttributeEntry finish the job (it will free theEntry if there are any errors)
146    return AddAttributeEntry(className, attributeName, theEntry);
147
148Fail_Element_New:
149    return kIrDAErrNoMemory;
150
151} // TIASService::AddNBytesEntry
152
153
154//--------------------------------------------------------------------------------
155//      AddAttributeEntry
156//--------------------------------------------------------------------------------
157IrDAErr TIASService::AddAttributeEntry(const UChar* className, const UChar* attributeName, TIASElement* theEntry)
158{
159    IrDAErr result = kIrDAErrNoMemory;
160    ULong flags;
161    TIASAttribute *theAttr;
162
163    // Make sure the class and attribute exist
164    theAttr = AddAttribute(className, attributeName, flags);
165    XREQUIRE(theAttr, Fail_ClassAttr_New);
166
167    // Insert the new entry
168    result = theAttr->Insert(theEntry);
169    XREQUIRENOT(result, Fail_Entry_Insert);
170
171    return noErr;
172
173Fail_Entry_Insert:
174    RemoveAttribute(className, attributeName, flags);
175
176Fail_ClassAttr_New:
177    theEntry->release();
178
179    return result;
180
181} // TIASService::AddAttributeEntry
182
183
184//--------------------------------------------------------------------------------
185//      AddAttribute
186//--------------------------------------------------------------------------------
187TIASAttribute* TIASService::AddAttribute(const UChar* className, const UChar* attributeName, ULong& flags)
188{
189    IrDAErr result;
190    TIASClass* theClass;
191    TIASAttribute* theAttr;
192
193    theClass = AddClass(className, flags);
194    XREQUIRE(theClass, Fail_Class_New);
195
196    // Does the attribute already exist in this class
197    theAttr = theClass->FindAttribute(attributeName);
198
199    // If attribute exists, done
200    if (theAttr != nil) {
201	return theAttr;
202    }
203
204    // Create, initialize the new attribute
205    theAttr = TIASAttribute::tIASAttribute(attributeName);
206    require(theAttr, Fail_Attribute_New);
207
208    result = theClass->Insert(theAttr);
209    XREQUIRENOT(result, Fail_Attribute_Insert);
210
211    // I created the attribute, let caller know so then can delete it if necessary
212    flags |= kIASAddedAttribute;
213
214    return theAttr;
215
216Fail_Attribute_Insert:
217    theAttr->release();
218
219Fail_Attribute_New:
220    RemoveClass(className, flags);
221
222Fail_Class_New:
223    return nil;
224
225} // TIASService::AddAttribute
226
227
228//--------------------------------------------------------------------------------
229//      AddClass
230//--------------------------------------------------------------------------------
231TIASClass* TIASService::AddClass(const UChar* className, ULong& flags)
232{
233    IrDAErr result;
234    TIASClass *theClass;
235
236    // Init flags
237    flags = 0;
238
239    // Does the class already exist in the name service
240    theClass = FindClass(className);
241
242    // If class exists, done
243    if (theClass != nil) {
244	return theClass;
245    }
246
247    // Create, initialize the new class
248    theClass = TIASClass::tIASClass(className);
249    require(theClass, Fail_Class_New);
250
251    result = this->Insert(theClass);
252    XREQUIRENOT(result, Fail_Class_Insert);
253
254    // I created the class, let caller know so then can delete it if necessary
255    flags |= kIASAddedClass;
256
257    return theClass;
258
259Fail_Class_Insert:
260    theClass->release();
261
262Fail_Class_New:
263    return nil;
264
265} // TIASService::AddClass
266
267
268//--------------------------------------------------------------------------------
269//      RemoveClass
270//--------------------------------------------------------------------------------
271IrDAErr TIASService::RemoveClass(const UChar* className, ULong flags)
272{
273    TIASClass *theClass;
274
275    theClass = FindClass(className);
276    if (theClass && (flags & kIASDeleteClass)) {
277	this->Remove(theClass);
278	theClass->release();
279    }
280    return noErr;
281
282} // TIASService::RemoveClass
283
284
285//--------------------------------------------------------------------------------
286//      RemoveAttribute
287//--------------------------------------------------------------------------------
288IrDAErr TIASService::RemoveAttribute(const UChar* className, const UChar* attributeName, ULong flags)
289{
290    TIASClass* theClass;
291    TIASAttribute* theAttr;
292
293    theClass = FindClass(className);
294    if (theClass) {
295	theAttr = theClass->FindAttribute(attributeName);
296	if (theAttr && (flags & kIASDeleteAttribute)) {
297	    theClass->Remove(theAttr);
298	    theAttr->release();
299	}
300	if (flags & kIASDeleteClass) {
301	    this->Remove(theClass);
302	    theClass->release();
303	}
304    }
305    return noErr;
306
307} // TIASService::RemoveAttribute
308
309
310//--------------------------------------------------------------------------------
311//      FindClass
312//--------------------------------------------------------------------------------
313TIASClass* TIASService::FindClass(const UChar* className)
314{
315    return (TIASClass*)this->Search(className);
316
317} // TIASService::FindClass
318
319
320//--------------------------------------------------------------------------------
321//      FindAttribute
322//--------------------------------------------------------------------------------
323TIASAttribute* TIASService::FindAttribute(const UChar* className, const UChar* attributeName)
324{
325    TIASClass* theClass;
326    TIASAttribute* theAttr = nil;
327
328    theClass = FindClass(className);
329    if (theClass) {
330	theAttr = theClass->FindAttribute(attributeName);
331    }
332    return theAttr;
333
334} // TIASService::FindAttribute
335
336
337#pragma mark
338//============== TIASClass ================
339
340#undef super
341#define super TIASNamedList
342OSDefineMetaClassAndStructors(TIASClass, TIASNamedList);
343
344
345//--------------------------------------------------------------------------------
346//      TIASClass
347//--------------------------------------------------------------------------------
348/*static*/
349TIASClass *
350TIASClass::tIASClass(const UChar *name)
351{
352    TIASClass *obj = new TIASClass;
353
354    XTRACE(kLogClassNew, 0, obj);
355
356    if (obj && !obj->Init(name)) {
357	obj->release();
358	obj = nil;
359    }
360    return obj;
361}
362
363
364//--------------------------------------------------------------------------------
365//      free
366//--------------------------------------------------------------------------------
367void TIASClass::free()
368{
369    long index;
370
371    XTRACE(kLogClassFree, 0, this);
372
373    // Iterate thru the list of attributes and delete each one.  Note that I'm not
374    // removing them because I'm depending on the list destructor to do that for me.
375    for (index = 0; index < this->GetArraySize(); index++) {
376	TIASAttribute* theAttr = (TIASAttribute*)this->At(index);
377	theAttr->release();
378    }
379
380    super::free();
381
382} // TIASClass::free
383
384
385//--------------------------------------------------------------------------------
386//      Insert
387//--------------------------------------------------------------------------------
388IrDAErr TIASClass::Insert(TIASAttribute* attribute)
389{
390    return CList::Insert((void*)attribute);
391
392} // TIASClass::Insert
393
394
395//--------------------------------------------------------------------------------
396//      FindAttribute
397//--------------------------------------------------------------------------------
398TIASAttribute* TIASClass::FindAttribute(const UChar* attributeName)
399{
400    return (TIASAttribute*)this->Search(attributeName);
401
402} // TIASClass::FindAttribute
403
404
405#pragma mark
406//============== TIASAttribute ============
407
408#undef super
409#define super TIASNamedList
410OSDefineMetaClassAndStructors(TIASAttribute, TIASNamedList);
411
412
413//--------------------------------------------------------------------------------
414//      TIASAttribute
415//--------------------------------------------------------------------------------
416/*static*/
417TIASAttribute *
418TIASAttribute::tIASAttribute(const UChar *name)
419{
420    TIASAttribute *obj = new TIASAttribute;
421
422    XTRACE(kLogAttrNew, 0, obj);
423
424    if (obj && !obj->Init(name)) {
425	obj->release();
426	obj = nil;
427    }
428    return obj;
429}
430
431/*static*/
432TIASAttribute *
433TIASAttribute::tIASAttribute(CBuffer *buffer)
434{
435    TIASAttribute *obj = new TIASAttribute;
436
437    XTRACE(kLogAttrNew, 0, obj);
438
439    if (obj && !obj->InitFromBuffer(buffer)) {
440	obj->release();
441	obj = nil;
442    }
443    return obj;
444}
445
446
447//--------------------------------------------------------------------------------
448//      free
449//--------------------------------------------------------------------------------
450void TIASAttribute::free()
451{
452    long index;
453
454    XTRACE(kLogAttrFree, 0, this);
455
456    // Iterate thru the list of elements and delete each one.  Note that I'm not
457    // removing them because I'm depending on the list destructor to do that for me.
458    for (index = 0; index < this->GetArraySize(); index++) {
459	TIASElement* theElement = (TIASElement*)this->At(index);
460	theElement->release();
461    }
462    super::free();
463
464} // TIASAttribute::free
465
466
467//--------------------------------------------------------------------------------
468//      Insert
469//--------------------------------------------------------------------------------
470IrDAErr TIASAttribute::Insert(TIASElement* element)
471{
472    return CList::Insert((void*)element);
473
474} // TIASAttribute::Insert
475
476
477//--------------------------------------------------------------------------------
478//      AddInfoToBuffer
479//--------------------------------------------------------------------------------
480void TIASAttribute::AddInfoToBuffer(CBuffer* buffer)
481{
482    long index;
483    ULong arraySize = this->GetArraySize();
484
485    // Write out the number of elements (as a 16 byte quantity)
486    buffer->Put((int)((arraySize >> 8) & 0xFF));    // Hi byte of short
487    buffer->Put((int)((arraySize >> 0) & 0xFF));    // Lo byte of short
488
489    // No iterate thru the elements and let each of them add themselves to the buffer
490    for (index = 0; index < this->GetArraySize(); index++) {
491	TIASElement* theElement = (TIASElement*)this->At(index);
492	theElement->AddInfoToBuffer(buffer);
493    }
494
495} // TIASAttribute::AddInfoToBuffer
496
497
498//--------------------------------------------------------------------------------
499//      InitFromBuffer
500//--------------------------------------------------------------------------------
501Boolean TIASAttribute::InitFromBuffer(CBuffer* buffer)
502{
503    ULong entryIndex;
504    ULong listLength;
505    UByte listLenBuf[2];    // Defined as a Big Endian UShort by protocol
506    TIASElement* element;
507
508    if (!super::Init()) return false;
509
510    // All (successful) replies have a list length field
511    if (buffer->Getn(listLenBuf, sizeof(listLenBuf)) != sizeof(listLenBuf)) {
512	return false;
513    }
514    listLength = (ULong)(listLenBuf[0] * 256) + (ULong)listLenBuf[1];
515
516    // Get each attribute entry and add it to the attribute
517    for (entryIndex = 0; entryIndex < listLength; entryIndex++) {
518	IrDAErr result;
519
520	// Create an attribute entry from the buffer info
521	element = TIASElement::tIASElement(buffer);
522	require(element, Fail);
523
524	// Add the attr entry to the attribute (list)
525	result = this->Insert(element);
526	if (result != noErr) {
527	    element->release();
528	    return false;
529	}
530    }
531
532    return true;
533
534Fail:
535    return false;
536
537} // TIASAttribute::ExtractInfoFromBuffer
538
539
540#pragma mark
541//============== TIASNamedList ============
542
543#undef super
544#define super CList
545OSDefineMetaClassAndStructors(TIASNamedList, CList);
546
547
548// never created directly, no factories here!
549
550//--------------------------------------------------------------------------------
551//      free
552//--------------------------------------------------------------------------------
553void TIASNamedList::free()
554{
555    XTRACE(kLogNamedListFree, 0, this);
556
557    if (fName != nil) {
558	IOFree(fName, fNameLen);
559	fName = nil;
560    }
561
562    super::free();
563
564} // TIASNamedList::free
565
566
567//--------------------------------------------------------------------------------
568//      Init
569//--------------------------------------------------------------------------------
570Boolean TIASNamedList::Init(const UChar *theName)
571{
572    fName = nil;
573
574    if (!super::init()) return false;
575
576    fNameLen = strlen((const char*)theName) + 1;
577    if (fNameLen) {
578	fName = (UChar*)IOMalloc(strlen((const char*)theName) + 1);
579	require(fName, Fail);
580    }
581    strlcpy((char*)fName, (const char*)theName, fNameLen);
582    return true;
583
584Fail:
585    return false;
586} // TIASNamedList::Init
587
588//
589// init w/out a name, seems kinda silly, but here we are
590//
591Boolean TIASNamedList::Init(void)
592{
593    fName = nil;
594    return super::init();
595}
596
597//--------------------------------------------------------------------------------
598//      Search
599//--------------------------------------------------------------------------------
600void* TIASNamedList::Search(const UChar* matchName)
601{
602    CListIterator *iter = CListIterator::cListIterator(this);
603    TIASNamedList* item;
604    void* result = nil;
605    //int review_consider_putting_in_dynamic_cast;    // to make sure list items are named lists
606
607    for (item = (TIASNamedList*)iter->FirstItem(); iter->More(); item = (TIASNamedList*)iter->NextItem()) {
608	if (strcmp((const char*)(item->fName), (const char*)matchName) == 0) {
609	    result = (void*)item;
610	    break;
611	}
612    }
613    iter->release();
614
615    return result;
616
617} // TIASNamedList::Search
618
619
620#pragma mark
621//============== TIASElement ==============
622
623#undef super
624#define super OSObject
625OSDefineMetaClassAndStructors(TIASElement, OSObject);
626
627//--------------------------------------------------------------------------------
628//      TIASElement
629//--------------------------------------------------------------------------------
630/*static*/
631TIASElement * TIASElement::tIASElement(ULong theValue)
632{
633    TIASElement *obj = new TIASElement;
634
635    XTRACE(kLogElementNew, 0, obj);
636
637    if (obj && !obj->init_with_long(theValue)) {
638	obj->release();
639	obj = nil;
640    }
641    return obj;
642}
643
644/*static*/
645TIASElement * TIASElement::tIASElement(const UChar* theBytes, ULong length)
646{
647    TIASElement *obj = new TIASElement;
648
649    XTRACE(kLogElementNew, 0, obj);
650
651    if (obj && !obj->init_with_nbytes(theBytes, length)) {
652	obj->release();
653	obj = nil;
654    }
655    return obj;
656}
657
658/*static*/
659TIASElement * TIASElement::tIASElement(const UChar* theString, UChar charSet, ULong length)
660{
661    TIASElement *obj = new TIASElement;
662
663    XTRACE(kLogElementNew, 0, obj);
664
665    if (obj && !obj->init_with_string(theString, charSet, length)) {
666	obj->release();
667	obj = nil;
668    }
669    return obj;
670}
671
672/*static*/
673TIASElement * TIASElement::tIASElement(CBuffer* buffer)
674{
675    TIASElement *obj = new TIASElement;
676
677    XTRACE(kLogElementNew, 0, obj);
678
679    if (obj && !obj->init_with_buffer(buffer)) {
680	obj->release();
681	obj = nil;
682    }
683    return obj;
684}
685
686
687
688//--------------------------------------------------------------------------------
689//      free
690//--------------------------------------------------------------------------------
691void TIASElement::free()
692{
693    int len;
694
695
696    XTRACE(kLogElementFree, 0, this);
697
698    if (nameOrBytes && (nameOrBytes != (UByte*)&valueOrBytes)) {        // if we allocated memory
699	len = length;
700	if (type == kIASValueString)        // if a unicode string, then allocated memory is length+2
701	    len += 2;
702	IOFree(nameOrBytes, len);
703	nameOrBytes = nil;
704    }
705
706    super::free();
707}
708
709
710//// Inits
711Boolean TIASElement::init_with_long(ULong theValue)
712{
713    type = kIASValueMissing;
714    length = 0;
715    valueOrBytes = 0;
716    nameOrBytes = nil;
717    characterSet = kIASCharSetAscii;
718
719    if (!super::init()) return false;
720
721    return SetInteger(theValue);
722}
723
724Boolean TIASElement::init_with_nbytes(const UChar* theBytes, ULong length)
725{
726    type = kIASValueMissing;
727    length = 0;
728    valueOrBytes = 0;
729    nameOrBytes = nil;
730    characterSet = kIASCharSetAscii;
731
732    if (!super::init()) return false;
733
734    return SetNBytes(theBytes, length);
735}
736
737Boolean TIASElement::init_with_string(const UChar* theString, UChar charSet, ULong length)
738{
739    type = kIASValueMissing;
740    length = 0;
741    valueOrBytes = 0;
742    nameOrBytes = nil;
743    characterSet = kIASCharSetAscii;
744
745    if (!super::init()) return false;
746
747    return SetString(theString, charSet, length);
748}
749
750Boolean TIASElement::init_with_buffer(CBuffer* buffer)
751{
752    type = kIASValueMissing;
753    length = 0;
754    valueOrBytes = 0;
755    nameOrBytes = nil;
756    characterSet = kIASCharSetAscii;
757
758    if (!super::init()) return false;
759
760    return ExtractInfoFromBuffer(buffer);
761}
762
763
764
765//--------------------------------------------------------------------------------
766//      SetInteger
767//--------------------------------------------------------------------------------
768Boolean TIASElement::SetInteger(ULong theValue)
769{
770    type = kIASValueInteger;
771    length = 4;
772    valueOrBytes = htonl(theValue);
773    nameOrBytes = (UByte*)&valueOrBytes;
774    return true;
775} // TIASElement::SetInteger
776
777
778//--------------------------------------------------------------------------------
779//      SetNBytes
780//--------------------------------------------------------------------------------
781Boolean TIASElement::SetNBytes(const UChar * theBytes, ULong theBytesLength)
782{
783    type = kIASValueNBytes;
784    length = theBytesLength;
785    nameOrBytes = (UByte*)IOMalloc(length);
786    require(nameOrBytes, Fail);
787    BlockMove(theBytes, nameOrBytes, length);
788    return true;
789
790Fail:
791    return false;
792} // TIASElement::SetNBytes
793
794
795//--------------------------------------------------------------------------------
796//      SetString
797//--------------------------------------------------------------------------------
798Boolean TIASElement::SetString(const UChar* theString, const UChar charSet, const ULong len)
799{
800    type = kIASValueString;
801    if (charSet != kIASCharSetUniCode)          // if not unicode, use strlen to compute length
802	length = (ULong)strlen((const char*)theString);
803    else
804	length = len;       // if unicode, use supplied length
805
806    valueOrBytes = 0;
807    characterSet = charSet;
808
809    // allocate room for string and two nulls (unicode or C) at end
810    nameOrBytes = (UByte*)IOMalloc((unsigned int)(length+2));
811    require(nameOrBytes, Fail);
812
813    //strcpy((char*)nameOrBytes, (const char*)theString);
814    BlockMove(theString, nameOrBytes, length);      // copy the string
815    // would normally just have one null at the end of a C string, but
816    // unicode "end of string" appears to want two nulls, since it's
817    // a 16-bit encoding.  So always append two nulls.
818    nameOrBytes[length] = 0;
819    nameOrBytes[length+1] = 0;
820    return true;
821
822Fail:
823    return false;
824
825} // TIASElement::SetString
826
827
828//--------------------------------------------------------------------------------
829//      GetInteger
830//--------------------------------------------------------------------------------
831IrDAErr TIASElement::GetInteger(ULong  *theValue)
832{
833    if (type != kIASValueInteger) {
834	return kIrDAErrGeneric; // ***FIXME: Better error return
835    }
836    *theValue = ntohl(valueOrBytes);
837    return noErr;
838
839} // TIASElement::GetInteger
840
841
842//--------------------------------------------------------------------------------
843//      GetNBytes
844//--------------------------------------------------------------------------------
845IrDAErr TIASElement::GetNBytes(UByte **theBytes, ULong *theLength)
846{
847    if (type != kIASValueNBytes) {
848	return kIrDAErrGeneric; // ***FIXME: Better error return
849    }
850    *theBytes = nameOrBytes;        // return pointer directly to our buffer
851    *theLength = length;
852    return noErr;
853
854} // TIASElement::GetNBytes
855
856//--------------------------------------------------------------------------------
857//      GetString
858//--------------------------------------------------------------------------------
859IrDAErr TIASElement::GetString(UByte **theString, UByte *charSet, ULong *len)
860{
861    if (type != kIASValueString) {
862	return kIrDAErrGeneric;         // ***FIXME: Better error return
863    }
864    *theString = nameOrBytes;       // return pointer to our copy!
865
866    if (charSet != nil)             // if caller is asking for character set
867	*charSet = characterSet;    // return it too
868
869    if (len != nil)                 // if caller supplied a length buffer
870	*len = length;              // return the length too (needed for unicode)
871
872    return noErr;                   // hope the client doesn't clobber me :-)
873
874} // TIASElement::GetString
875
876
877//--------------------------------------------------------------------------------
878//      AddInfoToBuffer
879//--------------------------------------------------------------------------------
880void TIASElement::AddInfoToBuffer(CBuffer* buffer)
881{
882    UByte header[5];
883    UByte* pHdr = &header[0];
884
885    // Fill in the object id - not really exists, faking it if I can get away with it
886    *pHdr++ = 0;
887    *pHdr++ = 0;
888
889    // Fill in the type
890    *pHdr++ = type;
891
892    XASSERT(length < 256);
893
894    // Fill in ascii char set/lengths
895    if (type == kIASValueNBytes) {
896	*pHdr++ = 0;                // Hi byte of length
897	*pHdr++ = (UByte)length;    // Lo byte of length
898    }
899    else if (type == kIASValueString) {
900	*pHdr++ = characterSet;     // Character set (defaults to ascii)
901	*pHdr++ = (UByte)length;    // Length of string
902    }
903
904    // Put out the header
905    buffer->Putn(header, pHdr - header);
906
907    // Put out the integer/string/octet sequence
908    buffer->Putn(nameOrBytes, length);
909
910} // TIASElement::AddInfoToBuffer
911
912
913//--------------------------------------------------------------------------------
914//      ExtractInfoFromBuffer
915//--------------------------------------------------------------------------------
916Boolean TIASElement::ExtractInfoFromBuffer(CBuffer* buffer)
917{
918    UByte entryHeader[3];   // UShort object id followed by attr value type id
919    UByte lengthInfo[2];    // high length byte, then low length byte
920    UByte charSet;          // character set
921    ULong length;
922    ULong intValue;
923    Boolean rc;
924    unsigned char buf[1024];    // max nBytes is 1024 (no null at end)
925
926
927    // Each entry must have at least a 2-byte object id and an attr value type id byte
928    if (buffer->Getn(entryHeader, sizeof(entryHeader)) != sizeof(entryHeader)) {
929	return false;
930    }
931
932    // Determine how many bytes to input and "set" the appropriate type/value
933    switch(entryHeader[2] /*type*/ ) {
934	case kIASValueMissing:
935	    // This is the default value of an attr element - all done
936	    rc = true;
937	    break;
938
939	case kIASValueInteger:
940	    if (buffer->Getn((UByte*)&intValue, sizeof(intValue)) != sizeof(intValue)) {
941		return kIrDAErrGeneric; // FIXME: Return better error code
942	    }
943	    intValue = ntohl(intValue);	// convert to host before saving
944	    rc = SetInteger(intValue);
945	    break;
946
947	case kIASValueNBytes:
948	    // first get the 16-bit length
949	    if (buffer->Getn(lengthInfo, sizeof(lengthInfo)) != sizeof(lengthInfo)) {
950		return false;
951	    }
952	    length = lengthInfo[0] << 8 | lengthInfo[1];    // could read directly into a short
953	    check(length <= 1024);          // according to spec
954	    check(length <= sizeof(buf));   // sanity
955	    if ((UInt32)buffer->Getn(buf, length) != length)
956		return false;
957	    rc = SetNBytes(buf, length);
958	    break;
959
960	case kIASValueString:
961	    // first get the character set code, length bytes
962	    if (buffer->Getn(lengthInfo, sizeof(lengthInfo)) != sizeof(lengthInfo)) {
963		return kIrDAErrGeneric; // FIXME: Return better error code
964	    }
965	    charSet = lengthInfo[0];    // 1st byte is the character set
966	    length = lengthInfo[1];     // 2nd byte is the length
967	    if ((UInt32)buffer->Getn(buf, length) != length)
968		    return false;
969	    buf[length] = 0;                    // turn into C string before calling SetString
970						// since length parm is ignored unless unicode charset
971	    rc = SetString(buf, charSet, length);   // copy it into the attribute
972	    break;
973
974	default:
975	    // Unknown type
976	    //DebugPrintf("extract info from buffer type %d", entryHeader[2]);  // jdg
977	    rc = false;
978	    break;
979    }
980
981    return rc;
982
983} // TIASElement::ExtractInfoFromBuffer
984
985