1 /***************************************************************************
2 (C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
3 Business Machines Corporation and Siemens Rolm Communications Inc.
4
5 For purposes of this license notice, the term Licensors shall mean,
6 collectively, Apple Computer, Inc., AT&T Corp., International
7 Business Machines Corporation and Siemens Rolm Communications Inc.
8 The term Licensor shall mean any of the Licensors.
9
10 Subject to acceptance of the following conditions, permission is hereby
11 granted by Licensors without the need for written agreement and without
12 license or royalty fees, to use, copy, modify and distribute this
13 software for any purpose.
14
15 The above copyright notice and the following four paragraphs must be
16 reproduced in all copies of this software and any software including
17 this software.
18
19 THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
20 ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
21 MODIFICATIONS.
22
23 IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
24 INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
25 OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 DAMAGE.
27
28 EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
29 INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
30 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 PURPOSE.
32
33 The software is provided with RESTRICTED RIGHTS. Use, duplication, or
34 disclosure by the government are subject to restrictions set forth in
35 DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
36
37 ***************************************************************************/
38
39 /*
40 * src: vobject.c
41 * doc: vobject and APIs to construct vobject, APIs pretty print
42 * vobject, and convert a vobject into its textual representation.
43 */
44
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48
49 #include "vobject.h"
50
51 #define NAME_OF(o) o->id
52 #define VALUE_TYPE(o) o->valType
53 #define STRINGZ_VALUE_OF(o) o->val.strs
54 #define USTRINGZ_VALUE_OF(o) o->val.ustrs
55 #define INTEGER_VALUE_OF(o) o->val.i
56 #define LONG_VALUE_OF(o) o->val.l
57 #define ANY_VALUE_OF(o) o->val.any
58 #define VOBJECT_VALUE_OF(o) o->val.vobj
59
60 typedef union ValueItem {
61 const char *strs;
62 const wchar_t *ustrs;
63 unsigned int i;
64 unsigned long l;
65 void *any;
66 VObject *vobj;
67 } ValueItem;
68
69 struct VObject {
70 VObject *next;
71 const char *id;
72 VObject *prop;
73 unsigned short valType;
74 ValueItem val;
75 };
76
77 typedef struct StrItem StrItem;
78
79 struct StrItem {
80 StrItem *next;
81 const char *s;
82 unsigned int refCnt;
83 };
84
85 const char** fieldedProp;
86
87
88
89 /*----------------------------------------------------------------------
90 The following functions involve with memory allocation:
91 newVObject
92 deleteVObject
93 dupStr
94 deleteStr
95 newStrItem
96 deleteStrItem
97 ----------------------------------------------------------------------*/
98
newVObject_(const char * id)99 static VObject* newVObject_(const char *id)
100 {
101 VObject *p = (VObject*)malloc(sizeof(VObject));
102 p->next = 0;
103 p->id = id;
104 p->prop = 0;
105 VALUE_TYPE(p) = 0;
106 ANY_VALUE_OF(p) = 0;
107 return p;
108 }
109
newVObject(const char * id)110 VObject* newVObject(const char *id)
111 {
112 return newVObject_(lookupStr(id));
113 }
114
deleteVObject(VObject * p)115 void deleteVObject(VObject *p)
116 {
117 if (!p)
118 return;
119 if (p->id)
120 unUseStr(p->id);
121 free(p);
122 }
123
dupStr(const char * s,size_t size)124 char* dupStr(const char *s, size_t size)
125 {
126 char *t;
127 if (size == 0) {
128 size = strlen(s);
129 }
130 t = (char*)malloc(size+1);
131 if (t) {
132 memcpy(t,s,size);
133 t[size] = 0;
134 return t;
135 }
136 else {
137 return (char*)0;
138 }
139 }
140
deleteStr(const char * p)141 void deleteStr(const char *p)
142 {
143 if (p)
144 free((void*)p);
145 }
146
147
newStrItem(const char * s,StrItem * next)148 static StrItem* newStrItem(const char *s, StrItem *next)
149 {
150 StrItem *p = (StrItem*)malloc(sizeof(StrItem));
151 p->next = next;
152 p->s = s;
153 p->refCnt = 1;
154 return p;
155 }
156
deleteStrItem(StrItem * p)157 static void deleteStrItem(StrItem *p)
158 {
159 if (p)
160 free((void*)p);
161 }
162
163
164 /*----------------------------------------------------------------------
165 The following function provide accesses to VObject's value.
166 ----------------------------------------------------------------------*/
167
vObjectName(VObject * o)168 const char* vObjectName(VObject *o)
169 {
170 return NAME_OF(o);
171 }
172
setVObjectName(VObject * o,const char * id)173 void setVObjectName(VObject *o, const char* id)
174 {
175 NAME_OF(o) = id;
176 }
177
vObjectStringZValue(VObject * o)178 const char* vObjectStringZValue(VObject *o)
179 {
180 return STRINGZ_VALUE_OF(o);
181 }
182
setVObjectStringZValue(VObject * o,const char * s)183 void setVObjectStringZValue(VObject *o, const char *s)
184 {
185 STRINGZ_VALUE_OF(o) = dupStr(s,0);
186 VALUE_TYPE(o) = VCVT_STRINGZ;
187 }
188
setVObjectStringZValue_(VObject * o,const char * s)189 void setVObjectStringZValue_(VObject *o, const char *s)
190 {
191 STRINGZ_VALUE_OF(o) = s;
192 VALUE_TYPE(o) = VCVT_STRINGZ;
193 }
194
vObjectUStringZValue(VObject * o)195 const wchar_t* vObjectUStringZValue(VObject *o)
196 {
197 return USTRINGZ_VALUE_OF(o);
198 }
199
setVObjectUStringZValue(VObject * o,const wchar_t * s)200 void setVObjectUStringZValue(VObject *o, const wchar_t *s)
201 {
202 size_t size = (size_t)((uStrLen(s)+1)*sizeof(wchar_t));
203 USTRINGZ_VALUE_OF(o) = (wchar_t*) dupStr((char*)s,size);
204 VALUE_TYPE(o) = VCVT_USTRINGZ;
205 }
206
setVObjectUStringZValue_(VObject * o,const wchar_t * s)207 void setVObjectUStringZValue_(VObject *o, const wchar_t *s)
208 {
209 USTRINGZ_VALUE_OF(o) = s;
210 VALUE_TYPE(o) = VCVT_USTRINGZ;
211 }
212
vObjectIntegerValue(VObject * o)213 unsigned int vObjectIntegerValue(VObject *o)
214 {
215 return INTEGER_VALUE_OF(o);
216 }
217
setVObjectIntegerValue(VObject * o,unsigned int i)218 void setVObjectIntegerValue(VObject *o, unsigned int i)
219 {
220 INTEGER_VALUE_OF(o) = i;
221 VALUE_TYPE(o) = VCVT_UINT;
222 }
223
vObjectLongValue(VObject * o)224 unsigned long vObjectLongValue(VObject *o)
225 {
226 return LONG_VALUE_OF(o);
227 }
228
setVObjectLongValue(VObject * o,unsigned long l)229 void setVObjectLongValue(VObject *o, unsigned long l)
230 {
231 LONG_VALUE_OF(o) = l;
232 VALUE_TYPE(o) = VCVT_ULONG;
233 }
234
vObjectAnyValue(VObject * o)235 void* vObjectAnyValue(VObject *o)
236 {
237 return ANY_VALUE_OF(o);
238 }
239
setVObjectAnyValue(VObject * o,void * t)240 void setVObjectAnyValue(VObject *o, void *t)
241 {
242 ANY_VALUE_OF(o) = t;
243 VALUE_TYPE(o) = VCVT_RAW;
244 }
245
vObjectVObjectValue(VObject * o)246 VObject* vObjectVObjectValue(VObject *o)
247 {
248 return VOBJECT_VALUE_OF(o);
249 }
250
setVObjectVObjectValue(VObject * o,VObject * p)251 void setVObjectVObjectValue(VObject *o, VObject *p)
252 {
253 VOBJECT_VALUE_OF(o) = p;
254 VALUE_TYPE(o) = VCVT_VOBJECT;
255 }
256
vObjectValueType(VObject * o)257 int vObjectValueType(VObject *o)
258 {
259 return (int)VALUE_TYPE(o);
260 }
261
262
263 /*----------------------------------------------------------------------
264 The following functions can be used to build VObject.
265 ----------------------------------------------------------------------*/
266
addVObjectProp(VObject * o,VObject * p)267 VObject* addVObjectProp(VObject *o, VObject *p)
268 {
269 /* circular link list pointed to tail */
270 /*
271 o {next,id,prop,val}
272 V
273 pn {next,id,prop,val}
274 V
275 ...
276 p1 {next,id,prop,val}
277 V
278 pn
279 -->
280 o {next,id,prop,val}
281 V
282 pn {next,id,prop,val}
283 V
284 p {next,id,prop,val}
285 ...
286 p1 {next,id,prop,val}
287 V
288 pn
289 */
290
291 VObject *tail = o->prop;
292 if (tail) {
293 p->next = tail->next;
294 o->prop = tail->next = p;
295 }
296 else {
297 o->prop = p->next = p;
298 }
299 return p;
300 }
301
addProp(VObject * o,const char * id)302 VObject* addProp(VObject *o, const char *id)
303 {
304 return addVObjectProp(o,newVObject(id));
305 }
306
addProp_(VObject * o,const char * id)307 static VObject* addProp_(VObject *o, const char *id)
308 {
309 return addVObjectProp(o,newVObject_(id));
310 }
311
addList(VObject ** o,VObject * p)312 void addList(VObject **o, VObject *p)
313 {
314 p->next = 0;
315 if (*o == 0) {
316 *o = p;
317 }
318 else {
319 VObject *t = *o;
320 while (t->next) {
321 t = t->next;
322 }
323 t->next = p;
324 }
325 }
326
nextVObjectInList(VObject * o)327 VObject* nextVObjectInList(VObject *o)
328 {
329 return o->next;
330 }
331
setValueWithSize_(VObject * prop,void * val,unsigned int size)332 VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size)
333 {
334 VObject *sizeProp;
335 setVObjectAnyValue(prop, val);
336 sizeProp = addProp(prop,VCDataSizeProp);
337 setVObjectLongValue(sizeProp, size);
338 return prop;
339 }
340
setValueWithSize(VObject * prop,void * val,unsigned int size)341 VObject* setValueWithSize(VObject *prop, void *val, unsigned int size)
342 {
343 void *p = dupStr((const char *)val,size);
344 return setValueWithSize_(prop,p,p?size:0);
345 }
346
initPropIterator(VObjectIterator * i,VObject * o)347 void initPropIterator(VObjectIterator *i, VObject *o)
348 {
349 i->start = o->prop;
350 i->next = 0;
351 }
352
initVObjectIterator(VObjectIterator * i,VObject * o)353 void initVObjectIterator(VObjectIterator *i, VObject *o)
354 {
355 i->start = o->next;
356 i->next = 0;
357 }
358
moreIteration(VObjectIterator * i)359 int moreIteration(VObjectIterator *i)
360 {
361 return (i->start && (i->next==0 || i->next!=i->start));
362 }
363
nextVObject(VObjectIterator * i)364 VObject* nextVObject(VObjectIterator *i)
365 {
366 if (i->start && i->next != i->start) {
367 if (i->next == 0) {
368 i->next = i->start->next;
369 return i->next;
370 }
371 else {
372 i->next = i->next->next;
373 return i->next;
374 }
375 }
376 else return (VObject*)0;
377 }
378
isAPropertyOf(VObject * o,const char * id)379 VObject* isAPropertyOf(VObject *o, const char *id)
380 {
381 VObjectIterator i;
382 initPropIterator(&i,o);
383 while (moreIteration(&i)) {
384 VObject *each = nextVObject(&i);
385 if (!strcasecmp(id,each->id))
386 return each;
387 }
388 return (VObject*)0;
389 }
390
addGroup(VObject * o,const char * g)391 VObject* addGroup(VObject *o, const char *g)
392 {
393 /*
394 a.b.c
395 -->
396 prop(c)
397 prop(VCGrouping=b)
398 prop(VCGrouping=a)
399 */
400 char *dot = strrchr(g,'.');
401 if (dot) {
402 VObject *p, *t;
403 char *gs, *n = dot+1;
404 gs = dupStr(g,0); /* so we can write to it. */
405 /* used to be
406 * t = p = addProp_(o,lookupProp_(n));
407 */
408 t = p = addProp_(o,lookupProp(n));
409 dot = strrchr(gs,'.');
410 if (dot) {
411 *dot = 0;
412 do {
413 dot = strrchr(gs,'.');
414 if (dot) {
415 n = dot+1;
416 *dot=0;
417 }
418 else
419 n = gs;
420 /* property(VCGroupingProp=n);
421 * and the value may have VCGrouping property
422 */
423 t = addProp(t,VCGroupingProp);
424 setVObjectStringZValue(t,lookupProp_(n));
425 } while (n != gs);
426 } else {
427 t = addProp(t,VCGroupingProp);
428 setVObjectStringZValue(t,lookupProp_(n));
429 }
430 deleteStr(gs);
431 return p;
432 }
433 else
434 return addProp_(o,lookupProp(g));
435 }
436
addPropValue(VObject * o,const char * p,const char * v)437 VObject* addPropValue(VObject *o, const char *p, const char *v)
438 {
439 VObject *prop;
440 prop = addProp(o,p);
441 setVObjectUStringZValue_(prop, fakeUnicode(v,0));
442 return prop;
443 }
444
addPropSizedValue_(VObject * o,const char * p,const char * v,unsigned int size)445 VObject* addPropSizedValue_(VObject *o, const char *p, const char *v,
446 unsigned int size)
447 {
448 VObject *prop;
449 prop = addProp(o,p);
450 (void)setValueWithSize_(prop, (void*)v, size);
451 return prop;
452 }
453
addPropSizedValue(VObject * o,const char * p,const char * v,unsigned int size)454 VObject* addPropSizedValue(VObject *o, const char *p, const char *v,
455 unsigned int size)
456 {
457 return addPropSizedValue_(o,p,dupStr(v,size),size);
458 }
459
460
461
462 /*----------------------------------------------------------------------
463 The following pretty print a VObject
464 ----------------------------------------------------------------------*/
465
466 static void printVObject_(FILE *fp, VObject *o, int level);
467
indent(FILE * fp,int level)468 static void indent(FILE *fp, int level)
469 {
470 int i;
471 for (i=0;i<level*4;i++) {
472 fputc(' ', fp);
473 }
474 }
475
printValue(FILE * fp,VObject * o,int level)476 static void printValue(FILE *fp, VObject *o, int level)
477 {
478 switch (VALUE_TYPE(o)) {
479 case VCVT_USTRINGZ: {
480 char c;
481 char *t,*s;
482 s = t = fakeCString(USTRINGZ_VALUE_OF(o));
483 fputc('"',fp);
484 while (c=*t,c) {
485 fputc(c,fp);
486 if (c == '\n') indent(fp,level+2);
487 t++;
488 }
489 fputc('"',fp);
490 deleteStr(s);
491 break;
492 }
493 case VCVT_STRINGZ: {
494 char c;
495 const char *s = STRINGZ_VALUE_OF(o);
496 fputc('"',fp);
497 while (c=*s,c) {
498 fputc(c,fp);
499 if (c == '\n') indent(fp,level+2);
500 s++;
501 }
502 fputc('"',fp);
503 break;
504 }
505 case VCVT_UINT:
506 fprintf(fp,"%u", INTEGER_VALUE_OF(o)); break;
507 case VCVT_ULONG:
508 fprintf(fp,"%lu", LONG_VALUE_OF(o)); break;
509 case VCVT_RAW:
510 fprintf(fp,"[raw data]"); break;
511 case VCVT_VOBJECT:
512 fprintf(fp,"[vobject]\n");
513 printVObject_(fp,VOBJECT_VALUE_OF(o),level+1);
514 break;
515 case 0:
516 fprintf(fp,"[none]"); break;
517 default:
518 fprintf(fp,"[unknown]"); break;
519 }
520 }
521
printNameValue(FILE * fp,VObject * o,int level)522 static void printNameValue(FILE *fp,VObject *o, int level)
523 {
524 indent(fp,level);
525 if (NAME_OF(o)) {
526 fprintf(fp,"%s", NAME_OF(o));
527 }
528 if (VALUE_TYPE(o)) {
529 fputc('=',fp);
530 printValue(fp,o, level);
531 }
532 fprintf(fp,"\n");
533 }
534
printVObject_(FILE * fp,VObject * o,int level)535 static void printVObject_(FILE *fp, VObject *o, int level)
536 {
537 VObjectIterator t;
538 if (o == 0) {
539 fprintf(fp,"[NULL]\n");
540 return;
541 }
542 printNameValue(fp,o,level);
543 initPropIterator(&t,o);
544 while (moreIteration(&t)) {
545 VObject *eachProp = nextVObject(&t);
546 printVObject_(fp,eachProp,level+1);
547 }
548 }
549
printVObject(FILE * fp,VObject * o)550 void printVObject(FILE *fp,VObject *o)
551 {
552 printVObject_(fp,o,0);
553 }
554
printVObjectToFile(char * fname,VObject * o)555 void printVObjectToFile(char *fname,VObject *o)
556 {
557 FILE *fp = fopen(fname,"w");
558 if (fp) {
559 printVObject(fp,o);
560 fclose(fp);
561 }
562 }
563
printVObjectsToFile(char * fname,VObject * list)564 void printVObjectsToFile(char *fname,VObject *list)
565 {
566 FILE *fp = fopen(fname,"w");
567 if (fp) {
568 while (list) {
569 printVObject(fp,list);
570 list = nextVObjectInList(list);
571 }
572 fclose(fp);
573 }
574 }
575
cleanVObject(VObject * o)576 void cleanVObject(VObject *o)
577 {
578 if (o == 0) return;
579 if (o->prop) {
580 /* destroy time: cannot use the iterator here.
581 Have to break the cycle in the circular link
582 list and turns it into regular NULL-terminated
583 list -- since at some point of destruction,
584 the reference entry for the iterator to work
585 will not longer be valid.
586 */
587 VObject *p;
588 p = o->prop->next;
589 o->prop->next = 0;
590 do {
591 VObject *t = p->next;
592 cleanVObject(p);
593 p = t;
594 } while (p);
595 }
596 switch (VALUE_TYPE(o)) {
597 case VCVT_USTRINGZ:
598 case VCVT_STRINGZ:
599 case VCVT_RAW:
600 /* assume they are all allocated by malloc. */
601 free((char*)STRINGZ_VALUE_OF(o));
602 break;
603 case VCVT_VOBJECT:
604 cleanVObject(VOBJECT_VALUE_OF(o));
605 break;
606 }
607 deleteVObject(o);
608 }
609
cleanVObjects(VObject * list)610 void cleanVObjects(VObject *list)
611 {
612 while (list) {
613 VObject *t = list;
614 list = nextVObjectInList(list);
615 cleanVObject(t);
616 }
617 }
618
619 /*----------------------------------------------------------------------
620 The following is a String Table Facilities.
621 ----------------------------------------------------------------------*/
622
623 #define STRTBLSIZE 255
624
625 static StrItem *strTbl[STRTBLSIZE];
626
hashStr(const char * s)627 static unsigned int hashStr(const char *s)
628 {
629 unsigned int h = 0;
630 int i;
631 for (i=0;s[i];i++) {
632 h += s[i]*i;
633 }
634 return h % STRTBLSIZE;
635 }
636
lookupStr(const char * s)637 const char* lookupStr(const char *s)
638 {
639 char *newS;
640 StrItem *t;
641 unsigned int h = hashStr(s);
642 if ((t = strTbl[h]) != 0) {
643 do {
644 if (strcasecmp(t->s,s) == 0) {
645 t->refCnt++;
646 return t->s;
647 }
648 t = t->next;
649 } while (t);
650 }
651 newS = dupStr(s,0);
652 strTbl[h] = newStrItem(newS,strTbl[h]);
653 return newS;
654 }
655
unUseStr(const char * s)656 void unUseStr(const char *s)
657 {
658 StrItem *cur, *prev;
659
660 unsigned int h = hashStr(s);
661 cur = strTbl[h];
662 prev = cur;
663 while (cur != 0) {
664 if (strcasecmp(cur->s,s) == 0) {
665 cur->refCnt--;
666 /* if that was the last reference to this string, kill it. */
667 if (cur->refCnt == 0) {
668 if (cur == strTbl[h]) {
669 strTbl[h] = cur->next;
670 deleteStr(prev->s);
671 deleteStrItem(prev);
672 } else {
673 prev->next = cur->next;
674 deleteStr(cur->s);
675 deleteStrItem(cur);
676 }
677 return;
678 }
679 }
680 prev = cur;
681 cur = cur->next;
682 }
683 }
684
cleanStrTbl()685 void cleanStrTbl()
686 {
687 int i;
688 for (i=0; i<STRTBLSIZE;i++) {
689 StrItem *t = strTbl[i];
690 while (t) {
691 StrItem *p;
692 deleteStr(t->s);
693 p = t;
694 t = t->next;
695 deleteStrItem(p);
696 }
697 strTbl[i] = 0;
698 }
699 }
700
701
702 struct PreDefProp {
703 const char *name;
704 const char *alias;
705 const char** fields;
706 unsigned int flags;
707 };
708
709 /* flags in PreDefProp */
710 #define PD_BEGIN 0x1
711 #define PD_INTERNAL 0x2
712
713 static const char *adrFields[] = {
714 VCPostalBoxProp,
715 VCExtAddressProp,
716 VCStreetAddressProp,
717 VCCityProp,
718 VCRegionProp,
719 VCPostalCodeProp,
720 VCCountryNameProp,
721 0
722 };
723
724 static const char *nameFields[] = {
725 VCFamilyNameProp,
726 VCGivenNameProp,
727 VCAdditionalNamesProp,
728 VCNamePrefixesProp,
729 VCNameSuffixesProp,
730 NULL
731 };
732
733 static const char *orgFields[] = {
734 VCOrgNameProp,
735 VCOrgUnitProp,
736 VCOrgUnit2Prop,
737 VCOrgUnit3Prop,
738 VCOrgUnit4Prop,
739 NULL
740 };
741
742 static const char *AAlarmFields[] = {
743 VCRunTimeProp,
744 VCSnoozeTimeProp,
745 VCRepeatCountProp,
746 VCAudioContentProp,
747 0
748 };
749
750 /* ExDate -- has unnamed fields */
751 /* RDate -- has unnamed fields */
752
753 static const char *DAlarmFields[] = {
754 VCRunTimeProp,
755 VCSnoozeTimeProp,
756 VCRepeatCountProp,
757 VCDisplayStringProp,
758 0
759 };
760
761 static const char *MAlarmFields[] = {
762 VCRunTimeProp,
763 VCSnoozeTimeProp,
764 VCRepeatCountProp,
765 VCEmailAddressProp,
766 VCNoteProp,
767 0
768 };
769
770 static const char *PAlarmFields[] = {
771 VCRunTimeProp,
772 VCSnoozeTimeProp,
773 VCRepeatCountProp,
774 VCProcedureNameProp,
775 0
776 };
777
778 static const struct PreDefProp propNames[] = {
779 { VC7bitProp, 0, 0, 0 },
780 { VC8bitProp, 0, 0, 0 },
781 { VCAAlarmProp, 0, AAlarmFields, 0 },
782 { VCAdditionalNamesProp, 0, 0, 0 },
783 { VCAdrProp, 0, adrFields, 0 },
784 { VCAgentProp, 0, 0, 0 },
785 { VCAIFFProp, 0, 0, 0 },
786 { VCAOLProp, 0, 0, 0 },
787 { VCAppleLinkProp, 0, 0, 0 },
788 { VCAttachProp, 0, 0, 0 },
789 { VCAttendeeProp, 0, 0, 0 },
790 { VCATTMailProp, 0, 0, 0 },
791 { VCAudioContentProp, 0, 0, 0 },
792 { VCAVIProp, 0, 0, 0 },
793 { VCBase64Prop, 0, 0, 0 },
794 { VCBBSProp, 0, 0, 0 },
795 { VCBirthDateProp, 0, 0, 0 },
796 { VCBMPProp, 0, 0, 0 },
797 { VCBodyProp, 0, 0, 0 },
798 { VCBusinessRoleProp, 0, 0, 0 },
799 { VCCalProp, 0, 0, PD_BEGIN },
800 { VCCaptionProp, 0, 0, 0 },
801 { VCCardProp, 0, 0, PD_BEGIN },
802 { VCCarProp, 0, 0, 0 },
803 { VCCategoriesProp, 0, 0, 0 },
804 { VCCellularProp, 0, 0, 0 },
805 { VCCGMProp, 0, 0, 0 },
806 { VCCharSetProp, 0, 0, 0 },
807 { VCCIDProp, VCContentIDProp, 0, 0 },
808 { VCCISProp, 0, 0, 0 },
809 { VCCityProp, 0, 0, 0 },
810 { VCClassProp, 0, 0, 0 },
811 { VCCommentProp, 0, 0, 0 },
812 { VCCompletedProp, 0, 0, 0 },
813 { VCContentIDProp, 0, 0, 0 },
814 { VCCountryNameProp, 0, 0, 0 },
815 { VCDAlarmProp, 0, DAlarmFields, 0 },
816 { VCDataSizeProp, 0, 0, PD_INTERNAL },
817 { VCDayLightProp, 0, 0, 0 },
818 { VCDCreatedProp, 0, 0, 0 },
819 { VCDeliveryLabelProp, 0, 0, 0 },
820 { VCDescriptionProp, 0, 0, 0 },
821 { VCDIBProp, 0, 0, 0 },
822 { VCDisplayStringProp, 0, 0, 0 },
823 { VCDomesticProp, 0, 0, 0 },
824 { VCDTendProp, 0, 0, 0 },
825 { VCDTstartProp, 0, 0, 0 },
826 { VCDueProp, 0, 0, 0 },
827 { VCEmailAddressProp, 0, 0, 0 },
828 { VCEncodingProp, 0, 0, 0 },
829 { VCEndProp, 0, 0, 0 },
830 { VCEventProp, 0, 0, PD_BEGIN },
831 { VCEWorldProp, 0, 0, 0 },
832 { VCExNumProp, 0, 0, 0 },
833 { VCExpDateProp, 0, 0, 0 },
834 { VCExpectProp, 0, 0, 0 },
835 { VCExtAddressProp, 0, 0, 0 },
836 { VCFamilyNameProp, 0, 0, 0 },
837 { VCFaxProp, 0, 0, 0 },
838 { VCFullNameProp, 0, 0, 0 },
839 { VCGeoLocationProp, 0, 0, 0 },
840 { VCGeoProp, 0, 0, 0 },
841 { VCGIFProp, 0, 0, 0 },
842 { VCGivenNameProp, 0, 0, 0 },
843 { VCGroupingProp, 0, 0, 0 },
844 { VCHomeProp, 0, 0, 0 },
845 { VCIBMMailProp, 0, 0, 0 },
846 { VCInlineProp, 0, 0, 0 },
847 { VCInternationalProp, 0, 0, 0 },
848 { VCInternetProp, 0, 0, 0 },
849 { VCISDNProp, 0, 0, 0 },
850 { VCJPEGProp, 0, 0, 0 },
851 { VCLanguageProp, 0, 0, 0 },
852 { VCLastModifiedProp, 0, 0, 0 },
853 { VCLastRevisedProp, 0, 0, 0 },
854 { VCLocationProp, 0, 0, 0 },
855 { VCLogoProp, 0, 0, 0 },
856 { VCMailerProp, 0, 0, 0 },
857 { VCMAlarmProp, 0, MAlarmFields, 0 },
858 { VCMCIMailProp, 0, 0, 0 },
859 { VCMessageProp, 0, 0, 0 },
860 { VCMETProp, 0, 0, 0 },
861 { VCModemProp, 0, 0, 0 },
862 { VCMPEG2Prop, 0, 0, 0 },
863 { VCMPEGProp, 0, 0, 0 },
864 { VCMSNProp, 0, 0, 0 },
865 { VCNamePrefixesProp, 0, 0, 0 },
866 { VCNameProp, 0, nameFields, 0 },
867 { VCNameSuffixesProp, 0, 0, 0 },
868 { VCNoteProp, 0, 0, 0 },
869 { VCOrgNameProp, 0, 0, 0 },
870 { VCOrgProp, 0, orgFields, 0 },
871 { VCOrgUnit2Prop, 0, 0, 0 },
872 { VCOrgUnit3Prop, 0, 0, 0 },
873 { VCOrgUnit4Prop, 0, 0, 0 },
874 { VCOrgUnitProp, 0, 0, 0 },
875 { VCPagerProp, 0, 0, 0 },
876 { VCPAlarmProp, 0, PAlarmFields, 0 },
877 { VCParcelProp, 0, 0, 0 },
878 { VCPartProp, 0, 0, 0 },
879 { VCPCMProp, 0, 0, 0 },
880 { VCPDFProp, 0, 0, 0 },
881 { VCPGPProp, 0, 0, 0 },
882 { VCPhotoProp, 0, 0, 0 },
883 { VCPICTProp, 0, 0, 0 },
884 { VCPMBProp, 0, 0, 0 },
885 { VCPostalBoxProp, 0, 0, 0 },
886 { VCPostalCodeProp, 0, 0, 0 },
887 { VCPostalProp, 0, 0, 0 },
888 { VCPowerShareProp, 0, 0, 0 },
889 { VCPreferredProp, 0, 0, 0 },
890 { VCPriorityProp, 0, 0, 0 },
891 { VCProcedureNameProp, 0, 0, 0 },
892 { VCProdIdProp, 0, 0, 0 },
893 { VCProdigyProp, 0, 0, 0 },
894 { VCPronunciationProp, 0, 0, 0 },
895 { VCPSProp, 0, 0, 0 },
896 { VCPublicKeyProp, 0, 0, 0 },
897 { VCQPProp, VCQuotedPrintableProp, 0, 0 },
898 { VCQuickTimeProp, 0, 0, 0 },
899 { VCQuotedPrintableProp, 0, 0, 0 },
900 { VCRDateProp, 0, 0, 0 },
901 { VCRegionProp, 0, 0, 0 },
902 { VCRelatedToProp, 0, 0, 0 },
903 { VCRepeatCountProp, 0, 0, 0 },
904 { VCResourcesProp, 0, 0, 0 },
905 { VCRNumProp, 0, 0, 0 },
906 { VCRoleProp, 0, 0, 0 },
907 { VCRRuleProp, 0, 0, 0 },
908 { VCRSVPProp, 0, 0, 0 },
909 { VCRunTimeProp, 0, 0, 0 },
910 { VCSequenceProp, 0, 0, 0 },
911 { VCSnoozeTimeProp, 0, 0, 0 },
912 { VCStartProp, 0, 0, 0 },
913 { VCStatusProp, 0, 0, 0 },
914 { VCStreetAddressProp, 0, 0, 0 },
915 { VCSubTypeProp, 0, 0, 0 },
916 { VCSummaryProp, 0, 0, 0 },
917 { VCTelephoneProp, 0, 0, 0 },
918 { VCTIFFProp, 0, 0, 0 },
919 { VCTimeZoneProp, 0, 0, 0 },
920 { VCTitleProp, 0, 0, 0 },
921 { VCTLXProp, 0, 0, 0 },
922 { VCTodoProp, 0, 0, PD_BEGIN },
923 { VCTranspProp, 0, 0, 0 },
924 { VCUniqueStringProp, 0, 0, 0 },
925 { VCURLProp, 0, 0, 0 },
926 { VCURLValueProp, 0, 0, 0 },
927 { VCValueProp, 0, 0, 0 },
928 { VCVersionProp, 0, 0, 0 },
929 { VCVideoProp, 0, 0, 0 },
930 { VCVoiceProp, 0, 0, 0 },
931 { VCWAVEProp, 0, 0, 0 },
932 { VCWMFProp, 0, 0, 0 },
933 { VCWorkProp, 0, 0, 0 },
934 { VCX400Prop, 0, 0, 0 },
935 { VCX509Prop, 0, 0, 0 },
936 { VCXRuleProp, 0, 0, 0 },
937 { 0,0,0,0 }
938 };
939
940
lookupPropInfo(const char * str)941 static const struct PreDefProp* lookupPropInfo(const char* str)
942 {
943 /* brute force for now, could use a hash table here. */
944 int i;
945
946 for (i = 0; propNames[i].name; i++)
947 if (strcasecmp(str, propNames[i].name) == 0) {
948 return &propNames[i];
949 }
950
951 return 0;
952 }
953
954
lookupProp_(const char * str)955 const char* lookupProp_(const char* str)
956 {
957 int i;
958
959 for (i = 0; propNames[i].name; i++)
960 if (strcasecmp(str, propNames[i].name) == 0) {
961 const char* s;
962 s = propNames[i].alias?propNames[i].alias:propNames[i].name;
963 return lookupStr(s);
964 }
965 return lookupStr(str);
966 }
967
968
lookupProp(const char * str)969 const char* lookupProp(const char* str)
970 {
971 int i;
972
973 for (i = 0; propNames[i].name; i++)
974 if (strcasecmp(str, propNames[i].name) == 0) {
975 const char *s;
976 fieldedProp = propNames[i].fields;
977 s = propNames[i].alias?propNames[i].alias:propNames[i].name;
978 return lookupStr(s);
979 }
980 fieldedProp = 0;
981 return lookupStr(str);
982 }
983
984
985 /*----------------------------------------------------------------------
986 APIs to Output text form.
987 ----------------------------------------------------------------------*/
988 #define OFILE_REALLOC_SIZE 256
989 typedef struct OFile {
990 FILE *fp;
991 char *s;
992 int len;
993 int limit;
994 int alloc:1;
995 unsigned int fail:1;
996 } OFile;
997
998 #if 0
999 static void appendsOFile(OFile *fp, const char *s)
1000 {
1001 int slen;
1002 if (fp->fail) return;
1003 slen = strlen(s);
1004 if (fp->fp) {
1005 fwrite(s,1,slen,fp->fp);
1006 }
1007 else {
1008 stuff:
1009 if (fp->len + slen < fp->limit) {
1010 memcpy(fp->s+fp->len,s,slen);
1011 fp->len += slen;
1012 return;
1013 }
1014 else if (fp->alloc) {
1015 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
1016 if (OFILE_REALLOC_SIZE <= slen) fp->limit += slen;
1017 fp->s = (char *) realloc(fp->s,(size_t)fp->limit);
1018 if (fp->s) goto stuff;
1019 }
1020 if (fp->alloc)
1021 free(fp->s);
1022 fp->s = 0;
1023 fp->fail = 1;
1024 }
1025 }
1026
1027 static void appendcOFile(OFile *fp, char c)
1028 {
1029 if (fp->fail) return;
1030 if (fp->fp) {
1031 fputc(c,fp->fp);
1032 }
1033 else {
1034 stuff:
1035 if (fp->len+1 < fp->limit) {
1036 fp->s[fp->len] = c;
1037 fp->len++;
1038 return;
1039 }
1040 else if (fp->alloc) {
1041 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
1042 fp->s = (char *) realloc(fp->s,fp->limit);
1043 if (fp->s) goto stuff;
1044 }
1045 if (fp->alloc)
1046 free(fp->s);
1047 fp->s = 0;
1048 fp->fail = 1;
1049 }
1050 }
1051 #else
appendcOFile_(OFile * fp,char c)1052 static void appendcOFile_(OFile *fp, char c)
1053 {
1054 if (fp->fail) return;
1055 if (fp->fp) {
1056 fputc(c,fp->fp);
1057 }
1058 else {
1059 stuff:
1060 if (fp->len+1 < fp->limit) {
1061 fp->s[fp->len] = c;
1062 fp->len++;
1063 return;
1064 }
1065 else if (fp->alloc) {
1066 fp->limit = fp->limit + OFILE_REALLOC_SIZE;
1067 fp->s = realloc(fp->s,(size_t)fp->limit);
1068 if (fp->s) goto stuff;
1069 }
1070 if (fp->alloc)
1071 free(fp->s);
1072 fp->s = 0;
1073 fp->fail = 1;
1074 }
1075 }
1076
appendcOFile(OFile * fp,char c)1077 static void appendcOFile(OFile *fp, char c)
1078 {
1079 if (c == '\n') {
1080 /* write out as <CR><LF> */
1081 appendcOFile_(fp,0xd);
1082 appendcOFile_(fp,0xa);
1083 }
1084 else
1085 appendcOFile_(fp,c);
1086 }
1087
appendsOFile(OFile * fp,const char * s)1088 static void appendsOFile(OFile *fp, const char *s)
1089 {
1090 size_t i, slen;
1091 slen = strlen(s);
1092 for (i=0; i<slen; i++) {
1093 appendcOFile(fp,s[i]);
1094 }
1095 }
1096
1097 #endif
1098
initOFile(OFile * fp,FILE * ofp)1099 static void initOFile(OFile *fp, FILE *ofp)
1100 {
1101 fp->fp = ofp;
1102 fp->s = 0;
1103 fp->len = 0;
1104 fp->limit = 0;
1105 fp->alloc = 0;
1106 fp->fail = 0;
1107 }
1108
initMemOFile(OFile * fp,char * s,int len)1109 static void initMemOFile(OFile *fp, char *s, int len)
1110 {
1111 fp->fp = 0;
1112 fp->s = s;
1113 fp->len = 0;
1114 fp->limit = s?len:0;
1115 fp->alloc = s?0:1;
1116 fp->fail = 0;
1117 }
1118
1119
writeBase64(OFile * fp,unsigned char * s,long len)1120 static int writeBase64(OFile *fp, unsigned char *s, long len)
1121 {
1122 long cur = 0;
1123 int i, numQuads = 0;
1124 unsigned long trip;
1125 unsigned char b;
1126 char quad[5];
1127 #define MAXQUADS 16
1128
1129 quad[4] = 0;
1130
1131 while (cur < len) {
1132 /* collect the triplet of bytes into 'trip' */
1133 trip = 0;
1134 for (i = 0; i < 3; i++) {
1135 b = (cur < len) ? *(s + cur) : 0;
1136 cur++;
1137 trip = trip << 8 | b;
1138 }
1139 /* fill in 'quad' with the appropriate four characters */
1140 for (i = 3; i >= 0; i--) {
1141 b = (unsigned char)(trip & 0x3F);
1142 trip = trip >> 6;
1143 if ((3 - i) < (cur - len))
1144 quad[i] = '='; /* pad char */
1145 else if (b < 26) quad[i] = (char)b + 'A';
1146 else if (b < 52) quad[i] = (char)(b - 26) + 'a';
1147 else if (b < 62) quad[i] = (char)(b - 52) + '0';
1148 else if (b == 62) quad[i] = '+';
1149 else quad[i] = '/';
1150 }
1151 /* now output 'quad' with appropriate whitespace and line ending */
1152 appendsOFile(fp, (numQuads == 0 ? " " : ""));
1153 appendsOFile(fp, quad);
1154 appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : "")));
1155 numQuads = (numQuads + 1) % MAXQUADS;
1156 }
1157 appendcOFile(fp,'\n');
1158
1159 return 1;
1160 }
1161
writeString(OFile * fp,const char * s)1162 static void writeString(OFile *fp, const char *s)
1163 {
1164 appendsOFile(fp,s);
1165 }
1166
writeQPString(OFile * fp,const char * s)1167 static void writeQPString(OFile *fp, const char *s)
1168 {
1169 char buf[4];
1170 int count=0;
1171 const char *p = s;
1172
1173 while (*p) {
1174 /* break up lines biggger than 75 chars */
1175 if(count >=74){
1176 count=0;
1177 appendsOFile(fp,"=\n");
1178 }
1179
1180 /* escape any non ASCII characters and '=' as per rfc1521 */
1181 if (*p<= 0x1f || *p >=0x7f || *p == '=' ) {
1182 snprintf(buf,sizeof(buf),"=%02X",(unsigned char)*p);
1183 appendsOFile(fp,buf);
1184 count+=3;
1185 } else {
1186 appendcOFile(fp,*p);
1187 count++;
1188 }
1189 p++;
1190 }
1191 }
1192
1193
1194
1195 static void writeVObject_(OFile *fp, VObject *o);
1196
writeValue(OFile * fp,VObject * o,unsigned long size,int quote)1197 static void writeValue(OFile *fp, VObject *o, unsigned long size,int quote)
1198 {
1199 if (o == 0) return;
1200 switch (VALUE_TYPE(o)) {
1201 case VCVT_USTRINGZ: {
1202 char *s = fakeCString(USTRINGZ_VALUE_OF(o));
1203 if(quote) writeQPString(fp, s);
1204 else writeString(fp,s);
1205 deleteStr(s);
1206 break;
1207 }
1208 case VCVT_STRINGZ: {
1209 if(quote) writeQPString(fp, STRINGZ_VALUE_OF(o));
1210 else writeString(fp,STRINGZ_VALUE_OF(o));
1211 break;
1212 }
1213 case VCVT_UINT: {
1214 char buf[16];
1215 snprintf(buf,sizeof(buf),"%u", INTEGER_VALUE_OF(o));
1216 appendsOFile(fp,buf);
1217 break;
1218 }
1219 case VCVT_ULONG: {
1220 char buf[16];
1221 snprintf(buf,sizeof(buf),"%lu", LONG_VALUE_OF(o));
1222 appendsOFile(fp,buf);
1223 break;
1224 }
1225 case VCVT_RAW: {
1226 appendcOFile(fp,'\n');
1227 writeBase64(fp,(unsigned char*)(ANY_VALUE_OF(o)),(long)size);
1228 break;
1229 }
1230 case VCVT_VOBJECT:
1231 appendcOFile(fp,'\n');
1232 writeVObject_(fp,VOBJECT_VALUE_OF(o));
1233 break;
1234 }
1235 }
1236
writeAttrValue(OFile * fp,VObject * o)1237 static void writeAttrValue(OFile *fp, VObject *o)
1238 {
1239 if (NAME_OF(o)) {
1240 const struct PreDefProp *pi;
1241 pi = lookupPropInfo(NAME_OF(o));
1242 if (pi && ((pi->flags & PD_INTERNAL) != 0)) return;
1243 appendcOFile(fp,';');
1244 appendsOFile(fp,NAME_OF(o));
1245 }
1246 else
1247 appendcOFile(fp,';');
1248 if (VALUE_TYPE(o)) {
1249 appendcOFile(fp,'=');
1250 writeValue(fp,o,0,0);
1251 }
1252 }
1253
writeGroup(OFile * fp,VObject * o)1254 static void writeGroup(OFile *fp, VObject *o)
1255 {
1256 char buf1[256];
1257 char buf2[256];
1258 strncpy(buf1,NAME_OF(o),sizeof(buf1)-1);
1259 buf1[sizeof(buf1)-1]='\0';
1260
1261 while ((o=isAPropertyOf(o,VCGroupingProp)) != 0) {
1262 strncpy(buf2,STRINGZ_VALUE_OF(o),sizeof(buf2)-1);
1263 buf2[sizeof(buf2)-1] = '\0';
1264 strncat(buf2,".",sizeof(buf2)-strlen(buf2)-1);
1265 strncat(buf2,buf1,sizeof(buf2)-strlen(buf2)-1);
1266 strcpy(buf1,buf2);
1267 }
1268 appendsOFile(fp,buf1);
1269 }
1270
inList(const char ** list,const char * s)1271 static int inList(const char **list, const char *s)
1272 {
1273 if (list == 0) return 0;
1274 while (*list) {
1275 if (strcasecmp(*list,s) == 0) return 1;
1276 list++;
1277 }
1278 return 0;
1279 }
1280
writeProp(OFile * fp,VObject * o)1281 static void writeProp(OFile *fp, VObject *o)
1282 {
1283 int isQuoted=0;
1284 if (NAME_OF(o)) {
1285 const struct PreDefProp *pi;
1286 VObjectIterator t;
1287 const char **fields_ = 0;
1288 pi = lookupPropInfo(NAME_OF(o));
1289 if (pi && ((pi->flags & PD_BEGIN) != 0)) {
1290 writeVObject_(fp,o);
1291 return;
1292 }
1293 if (isAPropertyOf(o,VCGroupingProp))
1294 writeGroup(fp,o);
1295 else
1296 appendsOFile(fp,NAME_OF(o));
1297 if (pi) fields_ = pi->fields;
1298 initPropIterator(&t,o);
1299 while (moreIteration(&t)) {
1300 const char *s;
1301 VObject *eachProp = nextVObject(&t);
1302 s = NAME_OF(eachProp);
1303 if (strcasecmp(VCGroupingProp,s) && !inList(fields_,s))
1304 writeAttrValue(fp,eachProp);
1305 if (strcasecmp(VCQPProp,s)==0 || strcasecmp(VCQuotedPrintableProp,s)==0)
1306 isQuoted=1;
1307 }
1308 if (fields_) {
1309 int i = 0, n = 0;
1310 const char** fields = fields_;
1311 /* output prop as fields */
1312 appendcOFile(fp,':');
1313 while (*fields) {
1314 VObject *tl = isAPropertyOf(o,*fields);
1315 i++;
1316 if (tl) n = i;
1317 fields++;
1318 }
1319 fields = fields_;
1320 for (i=0;i<n;i++) {
1321 writeValue(fp,isAPropertyOf(o,*fields),0,isQuoted);
1322 fields++;
1323 if (i<(n-1)) appendcOFile(fp,';');
1324 }
1325 }
1326 }
1327
1328 if (VALUE_TYPE(o)) {
1329 unsigned long size = 0;
1330 VObject *p = isAPropertyOf(o,VCDataSizeProp);
1331 if (p) size = LONG_VALUE_OF(p);
1332 appendcOFile(fp,':');
1333 writeValue(fp,o,size,isQuoted);
1334 }
1335
1336 appendcOFile(fp,'\n');
1337 }
1338
writeVObject_(OFile * fp,VObject * o)1339 static void writeVObject_(OFile *fp, VObject *o)
1340 {
1341 if (NAME_OF(o)) {
1342 const struct PreDefProp *pi;
1343 pi = lookupPropInfo(NAME_OF(o));
1344
1345 if (pi && ((pi->flags & PD_BEGIN) != 0)) {
1346 VObjectIterator t;
1347 const char *begin = NAME_OF(o);
1348 appendsOFile(fp,"BEGIN:");
1349 appendsOFile(fp,begin);
1350 appendcOFile(fp,'\n');
1351 initPropIterator(&t,o);
1352 while (moreIteration(&t)) {
1353 VObject *eachProp = nextVObject(&t);
1354 writeProp(fp, eachProp);
1355 }
1356 appendsOFile(fp,"END:");
1357 appendsOFile(fp,begin);
1358 appendsOFile(fp,"\n\n");
1359 }
1360 }
1361 }
1362
writeVObject(FILE * fp,VObject * o)1363 void writeVObject(FILE *fp, VObject *o)
1364 {
1365 OFile ofp;
1366 initOFile(&ofp,fp);
1367 writeVObject_(&ofp,o);
1368 }
1369
writeVObjectToFile(char * fname,VObject * o)1370 void writeVObjectToFile(char *fname, VObject *o)
1371 {
1372 FILE *fp = fopen(fname,"w");
1373 if (fp) {
1374 writeVObject(fp,o);
1375 fclose(fp);
1376 }
1377 }
1378
writeVObjectsToFile(char * fname,VObject * list)1379 void writeVObjectsToFile(char *fname, VObject *list)
1380 {
1381 FILE *fp = fopen(fname,"w");
1382 if (fp) {
1383 while (list) {
1384 writeVObject(fp,list);
1385 list = nextVObjectInList(list);
1386 }
1387 fclose(fp);
1388 }
1389 }
1390
writeMemVObject(char * s,int * len,VObject * o)1391 char* writeMemVObject(char *s, int *len, VObject *o)
1392 {
1393 OFile ofp;
1394 initMemOFile(&ofp,s,len?*len:0);
1395 writeVObject_(&ofp,o);
1396 if (len) *len = ofp.len;
1397 appendcOFile(&ofp,0);
1398 return ofp.s;
1399 }
1400
writeMemVObjects(char * s,int * len,VObject * list)1401 char* writeMemVObjects(char *s, int *len, VObject *list)
1402 {
1403 OFile ofp;
1404 initMemOFile(&ofp,s,len?*len:0);
1405 while (list) {
1406 writeVObject_(&ofp,list);
1407 list = nextVObjectInList(list);
1408 }
1409 if (len) *len = ofp.len;
1410 appendcOFile(&ofp,0);
1411 return ofp.s;
1412 }
1413
1414 /*----------------------------------------------------------------------
1415 APIs to do fake Unicode stuff.
1416 ----------------------------------------------------------------------*/
fakeUnicode(const char * ps,size_t * bytes)1417 wchar_t* fakeUnicode(const char *ps, size_t *bytes)
1418 {
1419 wchar_t *r, *pw;
1420 size_t len = strlen(ps)+1;
1421
1422 pw = r = (wchar_t*)malloc(sizeof(wchar_t)*len);
1423 if (bytes)
1424 *bytes = len * sizeof(wchar_t);
1425
1426 while (*ps) {
1427 if (*ps == '\n')
1428 *pw = (wchar_t)0x2028;
1429 else if (*ps == '\r')
1430 *pw = (wchar_t)0x2029;
1431 else
1432 *pw = (wchar_t)(unsigned char)*ps;
1433 ps++; pw++;
1434 }
1435 *pw = (wchar_t)0;
1436
1437 return r;
1438 }
1439
uStrLen(const wchar_t * u)1440 int uStrLen(const wchar_t *u)
1441 {
1442 int i;
1443
1444 if (u == NULL)
1445 return 0;
1446
1447 i = 0;
1448 while (*u != (wchar_t)0) { u++; i++; }
1449 return i;
1450 }
1451
fakeCString(const wchar_t * u)1452 char* fakeCString(const wchar_t *u)
1453 {
1454 char *s, *t;
1455 size_t len;
1456
1457 if (u == NULL)
1458 return NULL;
1459
1460 len = (size_t)(uStrLen(u) + 1);
1461 t = s = (char*)malloc(len);
1462 while (*u) {
1463 if (*u == (wchar_t)0x2028)
1464 *t = '\n';
1465 else if (*u == (wchar_t)0x2029)
1466 *t = '\r';
1467 else
1468 *t = (char)*u;
1469 u++; t++;
1470 }
1471 *t = 0;
1472 return s;
1473 }
1474
1475 /* end of source file vobject.c */
1476