1// ======================================================================
2//	File:		KCParamUtility.h
3//
4//	Wrapper classes for function parameters
5//	(using Parry's PodWrapper)
6//
7//
8//	Copyright:	Copyright (c) 2000,2003,2006 Apple Computer, Inc. All Rights Reserved.
9//
10//	Change History (most recent first):
11//
12//		 <1>	2/22/00	em		Created.
13// ======================================================================
14#ifndef __KC_PARAM_UTILITY_
15#define __KC_PARAM_UTILITY_
16
17#if TARGET_RT_MAC_MACHO
18	#include <OSServices/KeychainCore.h>
19	#include <OSServices/KeychainCorePriv.h>
20	#include <SecurityHI/KeychainHI.h>
21        //#include <SecurityCore/SecKeychainAPI.h>
22#else
23	#include <Keychain.h>
24#endif
25#include <security_utilities/utilities.h>
26
27#include <list>
28#include <stdio.h>
29#include <string>
30#include <Carbon/Carbon.h>
31
32#undef check
33//typedef const char* SecStringPtr;
34
35// ���������������������������������������������������������������������������
36// 	� CParam - base class for TParam template
37// ���������������������������������������������������������������������������
38class CParam
39{
40public:
41	virtual void		Write(FILE *inFile)=0;
42	virtual void		Read(FILE *inFile)=0;
43	virtual bool 		Compare(FILE *inFile)=0;
44};
45typedef std::list<CParam*>	tParamList;
46// ���������������������������������������������������������������������������
47// 	� TParam
48// ���������������������������������������������������������������������������
49template <class Wrapper, class StructT, class T>
50class TParam : public CParam
51{
52public:
53                        TParam(const char *inName)
54							:mName(inName), mResult(true)
55						{
56						}
57
58                        TParam(const char *inName, T&inData)
59							:mPod(inData), mName(inName), mResult(true)
60						{
61						}
62
63	virtual				~TParam(){}
64
65	bool				operator == (const T inData) const { return (mPod == inData); }
66	Wrapper&			operator = (const T inData){ return mPod = inData; }
67	Wrapper&			operator = (const T* inData){ return mPod = inData; }
68						operator T*(){ return (T*)mPod; }
69						operator T(){ return (T)mPod; }
70
71	virtual void		Write(FILE *inFile)
72						{
73							WriteTitle(inFile);
74							mPod.WriteData(inFile);
75						}
76
77	virtual void		Read(FILE *inFile)
78						{
79							ReadTitle(inFile);
80							mPod.ReadData(inFile);
81						}
82
83	virtual bool		Compare(FILE *inFile)
84						{
85							ReadTitle(inFile);
86                            Wrapper	aWrapper;
87                            aWrapper.ReadData(inFile);
88                            return (mResult = (mPod == aWrapper));
89                        }
90
91protected:
92	Wrapper				mPod;
93	const char			*mName;
94	bool				mResult;
95
96	virtual void		WriteTitle(FILE *inFile)
97						{
98							if(mResult)
99								fprintf(inFile, "     %s : ", mName);
100							else
101								fprintf(inFile, "***  %s : ", mName);
102						}
103
104	virtual void		ReadTitle(FILE *inFile)
105						{
106                            char	aTitle[256];
107                            fscanf(inFile, "%s : ", aTitle);
108							if(::strcmp(mName, aTitle) != 0){
109								throw(mName);
110							}
111						}
112
113};
114
115// ���������������������������������������������������������������������������
116// 	� Non-struct POD wrapping macros
117// ���������������������������������������������������������������������������
118#define	POD_STRUCT(type)				type##Struct
119#define POD_CLASS(type)					CParam##type
120#define TYPEDEF_POD_STRUCT(type)		typedef struct type##Struct { type data; } type##Struct;
121#define	TYPEDEF_POD_CLASS(type)			typedef TParam<C##type, type##Struct, type> CParam##type;
122#define	TYPEDEF_STRUCTPOD_CLASS(type)	typedef TParam<C##type, type, type> CParam##type;
123// ���������������������������������������������������������������������������
124// 	� UInt32 wrapper
125// ���������������������������������������������������������������������������
126TYPEDEF_POD_STRUCT(UInt32)
127class CUInt32 :  public PodWrapper<CUInt32, POD_STRUCT(UInt32)>{
128public:
129                        CUInt32(){ data = 0; };
130                        CUInt32(const UInt32 &inData){ data = inData; }
131
132    CUInt32 &			operator = (const UInt32 &inData){ data = inData; return *this; }
133	bool 				operator == (const UInt32 inData) const { return data == inData; }
134						operator UInt32*(){ return &data; }
135						operator UInt32(){ return data; }
136
137	virtual void		WriteData(FILE *inFile)
138                        {
139                            fprintf(inFile, "%ld\n", data);
140                        }
141
142	virtual void		ReadData(FILE *inFile)
143                        {
144                            fscanf(inFile, "%ld\n", &data);
145                        }
146};
147TYPEDEF_POD_CLASS(UInt32)
148
149// ���������������������������������������������������������������������������
150// 	� UInt16 wrapper
151// ���������������������������������������������������������������������������
152TYPEDEF_POD_STRUCT(UInt16)
153class CUInt16 :  public PodWrapper<CUInt16, POD_STRUCT(UInt16)>{
154public:
155                        CUInt16(){ data = 0; };
156                        CUInt16(const UInt16 &inData){ data = inData; }
157
158    CUInt16 &			operator = (const UInt16 &inData){ data = inData; return *this; }
159	bool 				operator == (const UInt16 inData) const { return data == inData; }
160                        operator UInt16*(){ return &data; }
161                        operator UInt16(){ return data; }
162
163	virtual void		WriteData(FILE *inFile)
164                        {
165                            fprintf(inFile, "%ld\n", (UInt32)data);
166                        }
167
168	virtual void		ReadData(FILE *inFile)
169                        {
170                            UInt32	aData;
171                            fscanf(inFile, "%ld\n", &aData);
172                            data = aData;
173                        }
174};
175TYPEDEF_POD_CLASS(UInt16)
176
177// ���������������������������������������������������������������������������
178// 	� Boolean wrapper
179// ���������������������������������������������������������������������������
180TYPEDEF_POD_STRUCT(Boolean)
181class CBoolean :  public PodWrapper<CBoolean, POD_STRUCT(Boolean)>{
182public:
183                        CBoolean(){ data = false; }
184                        CBoolean(const Boolean &inData){ data = inData; }
185                        operator Boolean*(){ return &data; }
186                        operator Boolean(){ return data; }
187
188    CBoolean &			operator = (const Boolean &inData){ data = inData; return *this; }
189	bool 				operator == (const Boolean inData) const { return data == inData; }
190
191	virtual void		WriteData(FILE *inFile)
192                        {
193                            fprintf(inFile, "%d\n", data);
194                        }
195
196	virtual void		ReadData(FILE *inFile)
197                        {
198                            int		aValue;
199                            fscanf(inFile, "%d\n", &aValue);
200                            data = ((aValue == 0) ? false : true);
201                        }
202
203};
204TYPEDEF_POD_CLASS(Boolean)
205
206// ���������������������������������������������������������������������������
207// 	� FourCharCode wrapper
208// ���������������������������������������������������������������������������
209TYPEDEF_POD_STRUCT(FourCharCode)
210class CFourCharCode :  public PodWrapper<CFourCharCode, POD_STRUCT(FourCharCode)>{
211public:
212                        CFourCharCode(){ data = '????'; }
213                        CFourCharCode(const FourCharCode &inData){ data = inData; }
214
215    CFourCharCode &		operator = (const FourCharCode &inData){ data = inData; return *this; }
216	bool 				operator == (const FourCharCode inData) const { return data == inData; }
217                        operator FourCharCode*(){ return &data; }
218                        operator FourCharCode(){ return data; }
219
220	virtual void		WriteData(FILE *inFile)
221                        {
222							for(UInt16 i=0; i<sizeof(FourCharCode); i++){
223								fprintf(inFile, "%c", (char)(data >> ((sizeof(FourCharCode)-i-1) * 8)));
224							}
225							fprintf(inFile, "\n");
226                        }
227
228	virtual void		ReadData(FILE *inFile)
229                        {
230                            FourCharCode	aValue = 0;
231							for(UInt16 i=0; i<sizeof(FourCharCode); i++){
232								char	aChar;
233								fscanf(inFile, "%c", &aChar);
234								aValue += (UInt32)aChar << ((sizeof(FourCharCode)-i-1)*8);
235							}
236							fscanf(inFile, "\n");
237							data = aValue;
238                        }
239
240};
241TYPEDEF_POD_CLASS(FourCharCode)
242
243typedef CParamFourCharCode	CParamOSType;
244typedef CParamFourCharCode	CParamKCItemClass;
245typedef CParamFourCharCode	CParamKCAttrType;
246
247// ���������������������������������������������������������������������������
248// 	� AliasHandle wrapper
249// ���������������������������������������������������������������������������
250TYPEDEF_POD_STRUCT(AliasHandle)
251class CAliasHandle : public PodWrapper<CAliasHandle, POD_STRUCT(AliasHandle)>{
252public:
253                        CAliasHandle(){ data = NULL; }
254                        CAliasHandle(const AliasHandle &inData){ data = inData; }
255
256    CAliasHandle &		operator = (const AliasHandle &inData){ data = inData; return *this; }
257	bool 				operator == (const AliasHandle inData) const { return data == inData; }
258                        operator AliasHandle*(){ return &data; }
259                        operator AliasHandle(){ return data; }
260
261	virtual void		WriteData(FILE *inFile)
262                        {
263							fprintf(inFile, "%s\n", mFullPathName);
264                        }
265
266	virtual void		ReadData(FILE *inFile)
267                        {
268							memset(mFullPathName, 0, sizeof(mFullPathName));
269							if(UNIX_fgets(mFullPathName, sizeof(mFullPathName), inFile)){
270										// fgets grabs the newline code too
271								mFullPathName[strlen(mFullPathName)-1] = 0;
272							}
273							else throw("Syntax error in CAliasHandle");
274
275							if(strchr(mFullPathName, ':')){
276										// Create a alias from the full-path name
277						//%%%cpm - this WONT work, Keychain mgr does not fill in the FSSpec
278								::NewAliasMinimalFromFullPath(
279											strlen(mFullPathName),
280											mFullPathName,
281											NULL,
282											NULL,
283											&data);
284							}
285							else{
286										// Ask KeychainLib to fill in the FSSpec for us
287								FSSpec	tmpSpec = {0,0};
288								tmpSpec.name[0] = ::strlen(mFullPathName);
289								memcpy(tmpSpec.name+1, mFullPathName, tmpSpec.name[0]);
290
291								KCRef	aKeychain;
292								::KCMakeKCRefFromFSSpec(&tmpSpec, &aKeychain);
293								::KCReleaseKeychain(&aKeychain);
294						//%%%cpm - this WONT work, Keychain mgr does not fill in the FSSpec
295                        		::NewAliasMinimal(
296											&tmpSpec,
297											&data);
298							}
299                        }
300protected:
301    char				mFullPathName[1024];
302};
303TYPEDEF_POD_CLASS(AliasHandle)
304// ���������������������������������������������������������������������������
305// 	� StringPtr wrapper
306// ���������������������������������������������������������������������������
307TYPEDEF_POD_STRUCT(StringPtr)
308class CStringPtr : public PodWrapper<CStringPtr, POD_STRUCT(StringPtr)>{
309public:
310                        CStringPtr(){ data = new unsigned char[256]; memset(data, 0, 256); }
311                        CStringPtr(const StringPtr &inData){ memset(data, 0, 256); memcpy(data, inData, inData[0]); }
312    virtual		~CStringPtr(){ delete data; }
313
314    CStringPtr &	operator = (const StringPtr inData){ memset(data, 0, 256); memcpy(data, inData, inData[0]); return *this; }
315    bool 		operator == (const StringPtr inData) const { return ((data[0] == inData[0]) && (memcmp(data, inData, data[0]+1) == 0)); }
316                        operator StringPtr*(){ return &data; }
317                        operator StringPtr(){ return data; }
318
319    virtual void	WriteData(FILE *inFile)
320                        {
321                            fprintf(inFile, "%s\n", data+1);
322                        }
323
324    virtual void	ReadData(FILE *inFile)
325                        {
326                            memset(data, 0, 256);
327
328                            char	cString[256];
329							if(UNIX_fgets(cString, 256, inFile)){
330								data[0] = strlen(cString)-1;
331								memcpy(data+1, cString, data[0]);
332							}
333							else
334								throw("Syntax error in CStringPtr");
335                        }
336};
337TYPEDEF_POD_CLASS(StringPtr)
338
339
340TYPEDEF_POD_STRUCT(AFPServerSignature)
341class CAFPServerSignature : public PodWrapper<CAFPServerSignature, POD_STRUCT(AFPServerSignature)>{
342public:
343                        CAFPServerSignature(){ memset(data, 0, sizeof(data)); }
344                        CAFPServerSignature(const AFPServerSignature &inData){  memcpy(data, inData, sizeof(data)); }
345
346    CAFPServerSignature &operator = (const AFPServerSignature inData){ memcpy(data, inData, sizeof(data)); return *this; }
347	bool 				operator == (const AFPServerSignature inData) const { return (memcmp(data, inData, sizeof(data)) == 0); }
348                        operator AFPServerSignature*(){ return &data; }
349
350	virtual void		WriteData(FILE *inFile)
351                        {
352                            for(UInt16 i=0; i<sizeof(data); i++) fprintf(inFile, "%c", data[i]);
353                            fprintf(inFile, "\n");
354                        }
355
356	virtual void		ReadData(FILE *inFile)
357                        {
358                            for(UInt16 i=0; i<sizeof(data); i++) fscanf(inFile, "%c", (UInt8*)(data+i));
359                            fscanf(inFile, "\n");
360                        }
361};
362//TYPEDEF_POD_CLASS(AFPServerSignature)
363typedef TParam<CAFPServerSignature, AFPServerSignatureStruct, AFPServerSignatureStruct> CParamAFPServerSignature;
364
365// ���������������������������������������������������������������������������
366// 	�  Blob wrapper
367// ���������������������������������������������������������������������������
368typedef  struct kcBlob{UInt32 length; void* data; } kcBlob;
369class CkcBlob : public PodWrapper<CkcBlob, kcBlob>{
370public:
371                        CkcBlob(){ length = 0; data = NULL; }
372                        CkcBlob(const kcBlob &inData){ length = 0; data = NULL; DeepCopy(inData.length, inData.data); }
373    CkcBlob &			operator = (const kcBlob &inData){ DeepCopy(inData.length, inData.data); return *this; }
374	bool 				operator == (const kcBlob inData) const { return ((inData.length == length) && (memcmp(data, inData.data, length) == 0)); }
375                        operator kcBlob*(){ return this; }
376
377#if defined(__MWERKS__)
378                        operator kcBlob(){ return *this; }
379#endif
380
381	virtual void		WriteData(FILE *inFile)
382                        {
383                            fprintf(inFile, "/%ld/", length);
384							if(length > 0){
385								for(UInt32 i=0; i<length; i++) fprintf(inFile, "%c", ((UInt8*)data)[i]);
386							}
387							fprintf(inFile, "\n");
388                        }
389
390	virtual void		ReadData(FILE *inFile)
391                        {
392							UInt32	aLength;
393                            fscanf(inFile, "/%ld/", &aLength);
394
395										// recyle 'data' if the size remains the same
396							if(aLength != length){
397								if(data) delete (UInt8*)data;
398								data = NULL;
399								if(aLength > 0) data = (UInt8*)new char[aLength+2];
400								length = aLength;
401							}
402							if(length > 0){
403								UNIX_fgets((char*)data, aLength+3, inFile);
404								((UInt8*)data)[length] = 0;
405							}
406							else
407								fscanf(inFile, "\n");
408                        }
409protected:
410    virtual void		DeepCopy(UInt32 inLength, const void *inData)
411                        {
412                            if(data != NULL) delete (UInt8*)data;
413                            data = NULL;
414
415                            length = inLength;
416                            if(length == 0) return;
417                            data = (UInt8*)new char[length];
418                            memcpy(data, inData, length);
419                        }
420};
421TYPEDEF_STRUCTPOD_CLASS(kcBlob)
422
423// ���������������������������������������������������������������������������
424// 	� FSSpec wrapper
425// ���������������������������������������������������������������������������
426class CFSSpec : public PodWrapper<CFSSpec, FSSpec>{
427public:
428                        CFSSpec(){ vRefNum = 0; parID = 0; memset(name, 0, sizeof(name)); mFullPathName[0] = 0;}
429                        CFSSpec(const FSSpec &inData){ memcpy(this, &inData, sizeof(*this)); }
430    CFSSpec &			operator = (const FSSpec &inData){ memcpy(this, &inData, sizeof(*this)); return *this; }
431	bool 				operator == (const FSSpec inData) const { return (this == &inData) || !memcmp(this, &inData, sizeof(FSSpec)); }
432                        operator FSSpec*(){ return this ; }
433
434	virtual void		WriteData(FILE *inFile)
435                        {
436							fprintf(inFile, "%s\n", mFullPathName);
437                        }
438
439	virtual void		ReadData(FILE *inFile)
440                        {
441							memset(mFullPathName, 0, sizeof(mFullPathName));
442							if(UNIX_fgets(mFullPathName, sizeof(mFullPathName), inFile)){
443										// fgets grabs the newline code too
444								name[0] = strlen(mFullPathName)-1;
445								mFullPathName[name[0]] = 0;
446								memcpy(name+1, mFullPathName, name[0]);
447							}
448							else throw("Syntax error in CFSSpec");
449                        }
450protected:
451    char				mFullPathName[1024];
452};
453TYPEDEF_STRUCTPOD_CLASS(FSSpec)
454
455// ���������������������������������������������������������������������������
456// 	� FSRef wrapper
457// ���������������������������������������������������������������������������
458class CFSRef : public PodWrapper<CFSRef, FSRef>{
459public:
460                        CFSRef(){ memset(hidden, 0, sizeof(hidden)); }
461                        CFSRef(const FSRef &inData){ memcpy(this, &inData, sizeof(*this)); }
462
463    CFSRef &			operator = (const FSRef &inData){ memcpy(this, &inData, sizeof(*this)); return *this; }
464	bool 				operator == (const FSRef inData) const  { return (this == &inData) || !memcmp(this, &inData, sizeof(FSRef)); }
465                        operator FSRef*(){ return this; }
466
467	virtual void		WriteData(FILE *inFile)
468                        {
469                                            // ��� need work
470                            fprintf(inFile, "\n");
471                        }
472
473	virtual void		ReadData(FILE *inFile)
474                        {
475                                            // ��� need work
476                            fscanf(inFile, "\n");
477                        }
478};
479TYPEDEF_STRUCTPOD_CLASS(FSRef)
480
481
482// ���������������������������������������������������������������������������
483// 	� KCAttribute wrapper
484// ���������������������������������������������������������������������������
485class CKCAttribute : public PodWrapper<CKCAttribute, KCAttribute>{
486public:
487                        CKCAttribute(){ tag = '0000'; length = 0; data = NULL; }
488                        CKCAttribute(const KCAttribute &inData){ memcpy(this, &inData, sizeof(*this)); }
489
490    CKCAttribute &		operator = (const KCAttribute &inData){ memcpy(this, &inData, sizeof(*this)); return *this; }
491	bool 				operator == (const KCAttribute inData) const
492						{
493							if(inData.tag != tag) return false;
494							return(memcmp(inData.data, data, ((inData.length < length) ? inData.length : length)) == 0);
495						}
496
497                        operator KCAttribute*(){ return this; }
498#if defined(__MWERKS__)
499						operator KCAttribute(){ return *this; }
500#endif
501	virtual void		WriteData(FILE *inFile)
502                        {
503							fprintf(inFile, "\n");
504
505							CParamKCAttrType	aTag(".tag", tag);
506							aTag.Write(inFile);
507
508							kcBlob				theBlob = {length, data};
509							CParamkcBlob		aData(".data", theBlob);
510							aData.Write(inFile);
511                        }
512
513	virtual void		ReadData(FILE *inFile)
514                        {
515                            fscanf(inFile, "\n");
516
517							CParamKCAttrType	aTag(".tag");
518							aTag.Read(inFile);
519							tag = aTag;
520
521							CParamkcBlob		aData(".data");
522							aData.Read(inFile);
523
524							kcBlob				aBlob;
525							aBlob = aData;
526							length = aBlob.length;
527							data = aBlob.data;
528                        }
529};
530TYPEDEF_STRUCTPOD_CLASS(KCAttribute)
531
532
533// ���������������������������������������������������������������������������
534// 	� KCAttributeList wrapper
535// ���������������������������������������������������������������������������
536class CKCAttributeList : public PodWrapper<CKCAttributeList, KCAttributeList>{
537public:
538                        CKCAttributeList(){ count = 0; attr = NULL; }
539                        CKCAttributeList(const CKCAttributeList &inData){ memcpy(this, &inData, sizeof(*this)); }
540
541    CKCAttributeList &	operator = (const CKCAttributeList &inData){ memcpy(this, &inData, sizeof(*this)); return *this; }
542	bool 				operator == (const CKCAttributeList inData) const  { return (this == &inData) || !memcmp(this, &inData, sizeof(CKCAttributeList)); }
543                        operator CKCAttributeList*(){ return this; }
544
545	virtual void		WriteData(FILE *inFile)
546                        {
547							fprintf(inFile, "\n");
548
549							CParamUInt32	aCount(".count", count);
550							aCount.Write(inFile);
551
552							for(UInt32 i=0; i<count; i++){
553								char aAttributeTitle[32];
554								sprintf(aAttributeTitle, ".%ld", i);
555								CParamKCAttribute	aAttr(aAttributeTitle, *(attr+i));
556								aAttr.Write(inFile);
557							}
558                        }
559
560	virtual void		ReadData(FILE *inFile)
561                        {
562                            fscanf(inFile, "\n");
563
564							CParamUInt32	aCount(".count");
565							aCount.Read(inFile);
566
567										// recycle if the size does not change
568							if(count != (UInt32)aCount){
569								if(attr) delete attr;
570								count = (UInt32)aCount;
571								attr = new KCAttribute[count];
572							}
573
574							for(UInt32 i=0; i<count; i++){
575								char aAttributeTitle[32];
576								sprintf(aAttributeTitle, ".%ld", i);
577								CParamKCAttribute	aAttr(aAttributeTitle);
578								aAttr.Read(inFile);
579								*(attr+i) = (KCAttribute)aAttr;
580							}
581                        }
582};
583TYPEDEF_STRUCTPOD_CLASS(KCAttributeList)
584
585// ���������������������������������������������������������������������������
586// 	� CKCRef wrapper
587// ���������������������������������������������������������������������������
588TYPEDEF_POD_STRUCT(KCRef)
589class CKCRef : public PodWrapper<CKCRef, POD_STRUCT(KCRef)>{
590public:
591						CKCRef(){ data = NULL; }
592                        CKCRef(const KCRef &inData){ data = inData; }
593	bool				operator == (const KCRef inKC)
594						{
595							if(inKC == data) return true;
596
597							char	thisName[256] = "";
598							char	aInName[256] = "";
599							::kcgetkeychainname(data, thisName);
600							::kcgetkeychainname(inKC, aInName);
601							return(::strcmp(thisName, aInName));
602						}
603};
604
605
606// ���������������������������������������������������������������������������
607// 	� KCItemRef wrapper
608// ���������������������������������������������������������������������������
609TYPEDEF_POD_STRUCT(KCItemRef)
610class CKCItemRef : public PodWrapper<CKCItemRef, POD_STRUCT(KCItemRef)>{
611public:
612						CKCItemRef(){ data = NULL; }
613                        CKCItemRef(const KCItemRef &inData){ data = inData; }
614	bool				operator == (const KCItemRef inKCItem)
615						{
616							if(inKCItem == data) return true;
617
618							KCRef	thisKeychain = 0;
619							KCRef	aInKeychain = 0;
620							::KCGetKeychain(data, &thisKeychain);
621							::KCGetKeychain(inKCItem, &aInKeychain);
622							if((CKCRef(thisKeychain) == aInKeychain) == false) return false;
623
624// Bug #2458217 - (KCGetData() causes bus error)
625#if TARGET_RT_MAC_MACHO
626	return true;
627#else
628							UInt32	thisLength;
629							UInt32	aInLength;
630							::KCGetData(data, 0, NULL, &thisLength);
631							::KCGetData(inKCItem, 0, NULL, &aInLength);
632							if(thisLength != aInLength) return false;
633
634							char	*thisData = new char[thisLength];
635							char	*aInData = new char[aInLength];
636							::KCGetData(data, thisLength, thisData, &thisLength);
637							::KCGetData(inKCItem, aInLength, aInData, &aInLength);
638
639							int aResult = ::memcmp(thisData, aInData, thisLength);
640
641							delete thisData;
642							delete aInData;
643							return(aResult == 0);
644#endif
645						}
646};
647
648
649#endif	// __KC_PARAM_UTILITY_
650