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