2ae30efbc6a7bab66ec8f86ab0dae3b92b03cbb3
[shibboleth/sp.git] / shib-target / ddf.cpp
1 /*
2  *  Copyright 2001-2005 Internet2
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * ddf.cpp - C++ DDF abstraction for interpretive RPC
19  *
20  * Created by:  Scott Cantor and Tom Sanfilippo, OSU
21  *
22  * $Id$
23  */
24
25 #ifdef WIN32
26 # define _CRT_NONSTDC_NO_DEPRECATE 1
27 # define _CRT_SECURE_NO_DEPRECATE 1
28 # define SHIBTARGET_EXPORTS __declspec(dllexport)
29 # define snprintf _snprintf
30 #endif
31
32 #include <saml/saml.h>
33 #include <shib-target/ddf.h>
34
35 #include <stdexcept>
36
37 using namespace saml;
38 using namespace shibtarget;
39 using namespace std;
40
41 // defensive string functions
42
43 size_t ddf_strlen(const char* s)
44 {
45     return s ? strlen(s) : 0;
46 }
47
48 char* ddf_strdup(const char* s)
49 {
50     return (s && *s) ? strdup(s) : NULL;
51 }
52
53 #define MAX_NAME_LEN 255
54
55 /* Parses '.' notation paths, where each component is at most MAX_NAME_LEN long.
56    path contains the address of a constant string which is the current path.
57    name points to a buffer in which to place the first path component.
58    After execution, the path pointer will be moved past the first dot.
59    The actual path string is never modified. Only name is written to.
60    The name buffer is returned from the function. */
61 char* ddf_token(const char** path, char* name)
62 {
63     const char* temp=NULL;
64     
65     *name='\0';
66     if (*path==NULL || **path=='\0')
67         return name;
68
69     temp=strchr(*path,'.');
70     if (temp==NULL)
71     {
72         strcpy(name,*path);
73         *path=NULL;
74     }
75     else if (temp>*path)
76     {
77         strncpy(name,*path,temp-*path);
78         name[temp-*path]='\0';
79         *path=temp+1;
80     }
81     else
82         *path=temp+1;
83     return name;
84 }
85
86 // body implementation
87
88 struct shibtarget::ddf_body_t {
89     ddf_body_t() : name(NULL), parent(NULL), next(NULL), prev(NULL), type(DDF_EMPTY) {}
90
91     char* name;                     // name of node
92     ddf_body_t* parent;             // parent node, if any
93     ddf_body_t* next;               // next node, if any
94     ddf_body_t* prev;               // previous node, if any
95
96     enum {
97             DDF_EMPTY,
98             DDF_STRING,
99             DDF_INT,
100         DDF_FLOAT,
101             DDF_STRUCT,
102         DDF_LIST,
103             DDF_POINTER
104     } type;                         // data type of node
105
106     union {
107         char* string;
108         long integer;
109         double floating;
110         void* pointer;
111         struct {
112                 ddf_body_t* first;
113                 ddf_body_t* last;
114                 ddf_body_t* current;
115                 unsigned long count;
116         } children;
117     } value;                        // value of node
118 };
119
120 // library implementation
121
122 DDF::DDF(const char* n)
123 {
124     m_handle=new(nothrow) ddf_body_t;
125     name(n);
126 }
127
128 DDF::DDF(const char* n, const char* val)
129 {
130     m_handle=new(nothrow) ddf_body_t;
131     name(n);
132     string(val);
133 }
134
135 DDF::DDF(const char* n, long val)
136 {
137     m_handle=new(nothrow) ddf_body_t;
138     name(n);
139     integer(val);
140 }
141
142 DDF::DDF(const char* n, double val)
143 {
144     m_handle=new(nothrow) ddf_body_t;
145     name(n);
146     floating(val);
147 }
148
149 DDF::DDF(const char* n, void* val)
150 {
151     m_handle=new(nothrow) ddf_body_t;
152     name(n);
153     pointer(val);
154 }
155
156 DDF& DDF::destroy()
157 {
158     remove().empty().name(NULL);
159     delete m_handle;
160     m_handle=NULL;
161     return *this;
162 }
163
164 DDF DDF::copy() const
165 {
166     if (m_handle==NULL)
167         return DDF();
168
169     switch (m_handle->type) {
170         case ddf_body_t::DDF_EMPTY:
171             return DDF(m_handle->name);
172         case ddf_body_t::DDF_STRING:
173             return DDF(m_handle->name,m_handle->value.string);
174         case ddf_body_t::DDF_INT:
175             return DDF(m_handle->name,m_handle->value.integer);
176         case ddf_body_t::DDF_FLOAT:
177             return DDF(m_handle->name,m_handle->value.floating);
178         case ddf_body_t::DDF_POINTER:
179             return DDF(m_handle->name,m_handle->value.pointer);
180         case ddf_body_t::DDF_STRUCT:
181         case ddf_body_t::DDF_LIST:
182         {
183             DDF copy(m_handle->name), temp;
184             if (m_handle->type==ddf_body_t::DDF_STRUCT)
185                 copy.structure();
186             else
187                 copy.list();
188             ddf_body_t* child=m_handle->value.children.first;
189             while (child) {
190                 temp.m_handle=child;
191                 DDF temp2=temp.copy();
192                 copy.add(temp2);
193                 if (copy.m_handle==NULL)
194                     return copy;
195                 if (m_handle->value.children.current==child)
196                     copy.m_handle->value.children.current=copy.m_handle->value.children.last;
197                 child=child->next;
198             }
199             return copy;
200         }
201     }
202     return DDF();
203 }
204
205 const char* DDF::name() const
206 {
207     return (m_handle) ? m_handle->name : NULL;
208 }
209
210 DDF& DDF::name(const char* name)
211 {
212     char trunc_name[MAX_NAME_LEN+1]="";
213
214     if (m_handle) {
215         if (m_handle->name)
216             free(m_handle->name);
217         if (name && *name) {
218             strncpy(trunc_name,name,MAX_NAME_LEN);
219             trunc_name[MAX_NAME_LEN]='\0';
220             m_handle->name=ddf_strdup(trunc_name);
221             if (!m_handle->name)
222                 destroy();
223         }
224         else
225             m_handle->name=NULL;
226     }
227     return *this;
228 }
229
230 bool DDF::isnull() const
231 {
232     return m_handle ? false : true;
233 }
234
235 bool DDF::isempty() const
236 {
237     return m_handle ? (m_handle->type==ddf_body_t::DDF_EMPTY) : false;
238 }
239
240 bool DDF::isstring() const
241 {
242     return m_handle ? (m_handle->type==ddf_body_t::DDF_STRING) : false;
243 }
244
245 bool DDF::isint() const
246 {
247     return m_handle ? (m_handle->type==ddf_body_t::DDF_INT) : false;
248 }
249
250 bool DDF::isfloat() const
251 {
252     return m_handle ? (m_handle->type==ddf_body_t::DDF_FLOAT) : false;
253 }
254
255 bool DDF::isstruct() const
256 {
257     return m_handle ? (m_handle->type==ddf_body_t::DDF_STRUCT) : false;
258 }
259
260 bool DDF::islist() const
261 {
262     return m_handle ? (m_handle->type==ddf_body_t::DDF_LIST) : false;
263 }
264
265 bool DDF::ispointer() const
266 {
267     return m_handle ? (m_handle->type==ddf_body_t::DDF_POINTER) : false;
268 }
269
270 const char* DDF::string() const
271 {
272     return isstring() ? m_handle->value.string : NULL;
273 }
274
275 long DDF::integer() const
276 {
277     if (m_handle) {
278         switch(m_handle->type) {
279             case ddf_body_t::DDF_INT:
280                 return m_handle->value.integer;
281             case ddf_body_t::DDF_FLOAT:
282                 return static_cast<long>(m_handle->value.floating);
283             case ddf_body_t::DDF_STRING:
284                 return m_handle->value.string ? atol(m_handle->value.string) : 0;
285             case ddf_body_t::DDF_STRUCT:
286             case ddf_body_t::DDF_LIST:
287                 return m_handle->value.children.count;
288             case ddf_body_t::DDF_POINTER:
289                 return reinterpret_cast<long>(m_handle->value.pointer);
290         }
291     }
292     return 0;
293 }
294
295 double DDF::floating() const
296 {
297     if (m_handle) {
298         switch(m_handle->type) {
299             case ddf_body_t::DDF_INT:
300                 return m_handle->value.integer;
301             case ddf_body_t::DDF_FLOAT:
302                 return m_handle->value.floating;
303             case ddf_body_t::DDF_STRING:
304                 return m_handle->value.string ? atof(m_handle->value.string) : 0;
305             case ddf_body_t::DDF_STRUCT:
306             case ddf_body_t::DDF_LIST:
307                 return m_handle->value.children.count;
308         }
309     }
310     return 0;
311 }
312
313 void* DDF::pointer() const
314 {
315     return ispointer() ? m_handle->value.pointer : NULL;
316 }
317
318 size_t DDF::strlen() const
319 {
320     return ddf_strlen(string());
321 }
322
323 bool DDF::operator==(const char* s) const
324 {
325     if (string()==NULL || s==NULL)
326         return (string()==NULL && s==NULL);
327     else
328         return (::strcmp(string(),s)==0);
329 }
330
331 DDF& DDF::empty()
332 {
333     if (m_handle) {
334         switch (m_handle->type) {
335             case ddf_body_t::DDF_STRING:
336                 if (m_handle->value.string)
337                     free(m_handle->value.string);
338                 break;
339             case ddf_body_t::DDF_LIST:
340             case ddf_body_t::DDF_STRUCT:
341             {
342                 DDF temp;
343                 while (m_handle->value.children.first)
344                 {
345                     temp.m_handle=m_handle->value.children.first;
346                     temp.destroy();
347                 }
348             }
349         }
350         m_handle->type=ddf_body_t::DDF_EMPTY;
351     }
352     return *this;
353 }
354
355 DDF& DDF::string(const char* val)
356 {
357     if (empty().m_handle) {
358         m_handle->value.string=ddf_strdup(val);
359         if (!m_handle->value.string && val && *val)
360             return destroy();
361         m_handle->type=ddf_body_t::DDF_STRING;
362     }
363     return *this;
364 }
365
366 DDF& DDF::string(long val)
367 {
368     char buf[20];
369
370     sprintf(buf,"%ld",val);
371     return string(buf);
372 }
373
374 DDF& DDF::string(double val)
375 {
376     char buf[40];
377
378     snprintf(buf,39,"%f",val);
379     return string(buf);
380 }
381
382 DDF& DDF::integer(long val)
383 {
384     if (empty().m_handle) {
385         m_handle->value.integer=val;
386         m_handle->type=ddf_body_t::DDF_INT;
387     }
388     return *this;
389 }
390
391 DDF& DDF::integer(const char* val)
392 {
393     if (empty().m_handle) {
394         m_handle->value.integer=(val ? atol(val) : 0);
395         m_handle->type=ddf_body_t::DDF_INT;
396     }
397     return *this;
398 }
399
400 DDF& DDF::floating(double val)
401 {
402     if (empty().m_handle) {
403         m_handle->value.floating=val;
404         m_handle->type=ddf_body_t::DDF_FLOAT;
405     }
406     return *this;
407 }
408
409 DDF& DDF::floating(const char* val)
410 {
411     if (empty().m_handle) {
412         m_handle->value.floating=(val ? atof(val) : 0);
413         m_handle->type=ddf_body_t::DDF_FLOAT;
414     }
415     return *this;
416 }
417
418 DDF& DDF::structure()
419 {
420     if (empty().m_handle) {
421         m_handle->type=ddf_body_t::DDF_STRUCT;
422         m_handle->value.children.first=NULL;
423         m_handle->value.children.last=NULL;
424         m_handle->value.children.current=NULL;
425         m_handle->value.children.count=0;
426     }
427     return *this;
428 }
429
430 DDF& DDF::list()
431 {
432     if (empty().m_handle) {
433         m_handle->type=ddf_body_t::DDF_LIST;
434         m_handle->value.children.first=NULL;
435         m_handle->value.children.last=NULL;
436         m_handle->value.children.current=NULL;
437         m_handle->value.children.count=0;
438     }
439     return *this;
440 }
441
442 DDF& DDF::pointer(void* val)
443 {
444     if (empty().m_handle) {
445         m_handle->value.pointer=val;
446         m_handle->type=ddf_body_t::DDF_POINTER;
447     }
448     return *this;
449 }
450
451 DDF& DDF::add(DDF& child)
452 {
453     if ((!isstruct() && !islist()) || !child.m_handle)
454         return child;
455
456     if (m_handle==child.m_handle->parent)
457         return child;
458
459     if (isstruct()) {
460         if (!child.name())
461             return child;
462         getmember(child.name()).destroy();
463     }
464
465     child.remove();
466     if (!m_handle->value.children.first)
467         m_handle->value.children.first=child.m_handle;
468     else {
469         m_handle->value.children.last->next=child.m_handle;
470         child.m_handle->prev=m_handle->value.children.last;
471     }
472     m_handle->value.children.last=child.m_handle;
473     child.m_handle->parent=m_handle;
474     m_handle->value.children.count++;
475     return child;
476 }
477
478 DDF& DDF::addbefore(DDF& child, DDF& before)
479 {
480     if (!islist() || !child.m_handle || !before.m_handle || before.m_handle->parent!=m_handle)
481         return child;
482
483     child.remove();
484     if (m_handle->value.children.first==before.m_handle)
485         m_handle->value.children.first=child.m_handle;
486     child.m_handle->prev=before.m_handle->prev;
487     if (child.m_handle->prev)
488         child.m_handle->prev->next=child.m_handle;
489     before.m_handle->prev=child.m_handle;
490     child.m_handle->next=before.m_handle;
491     child.m_handle->parent=m_handle;
492     m_handle->value.children.count++;
493     return child;
494 }
495
496 DDF& DDF::addafter(DDF& child, DDF& after)
497 {
498     if (!islist() || !child.m_handle || !after.m_handle || after.m_handle->parent!=m_handle)
499         return child;
500
501     child.remove();
502     if (m_handle->value.children.last==after.m_handle)
503         m_handle->value.children.last=child.m_handle;
504     child.m_handle->next=after.m_handle->next;
505     if (child.m_handle->next)
506         child.m_handle->next->prev=child.m_handle;
507     after.m_handle->next=child.m_handle;
508     child.m_handle->prev=after.m_handle;
509     child.m_handle->parent=m_handle;
510     m_handle->value.children.count++;
511     return child;
512 }
513
514 void DDF::swap(DDF& arg)
515 {
516     ddf_body_t* temp=arg.m_handle;
517     arg.m_handle=m_handle;
518     m_handle=temp;
519 }
520
521 DDF& DDF::remove()
522 {
523     if (!m_handle || !m_handle->parent)
524         return *this;
525
526     if (m_handle->next)
527         m_handle->next->prev=m_handle->prev;
528
529     if (m_handle->prev)
530         m_handle->prev->next=m_handle->next;
531
532     if (m_handle->parent->value.children.first==m_handle)
533         m_handle->parent->value.children.first=m_handle->next;
534
535     if (m_handle->parent->value.children.last==m_handle)
536         m_handle->parent->value.children.last=m_handle->prev;
537
538     if (m_handle->parent->value.children.current==m_handle)
539         m_handle->parent->value.children.current=m_handle->prev;
540
541     m_handle->parent->value.children.count--;
542     m_handle->parent=NULL;
543     m_handle->next=NULL;
544     m_handle->prev=NULL;
545     return *this;
546 }
547
548 DDF DDF::parent() const
549 {
550     DDF p;
551
552     p.m_handle=(m_handle ? m_handle->parent : NULL);
553     return p;
554 }
555
556 DDF DDF::first()
557 {
558     DDF f;
559
560     if (islist() || isstruct())
561         f.m_handle=m_handle->value.children.current=m_handle->value.children.first;
562     return f;
563 }
564
565 DDF DDF::next()
566 {
567     DDF n;
568
569     if ((islist() || isstruct()) && m_handle->value.children.current!=m_handle->value.children.last) {
570         if (!m_handle->value.children.current)
571             n.m_handle=m_handle->value.children.current=m_handle->value.children.first;
572         else
573             n.m_handle=m_handle->value.children.current=m_handle->value.children.current->next;
574     }
575     return n;
576 }
577
578 DDF DDF::last()
579 {
580     DDF l;
581
582     if ((islist() || isstruct()) && m_handle->value.children.last) {
583         m_handle->value.children.current=m_handle->value.children.last->prev;
584         l.m_handle=m_handle->value.children.last;
585     }
586     return l;
587 }
588
589 DDF DDF::previous()
590 {
591     DDF p;
592
593     if (islist() || isstruct()) {
594         p.m_handle=m_handle->value.children.current;
595         if (p.m_handle)
596             m_handle->value.children.current=m_handle->value.children.current->prev;
597     }
598     return p;
599 }
600
601 DDF DDF::operator[](unsigned long index) const
602 {
603     DDF d;
604
605     if (islist() && index<m_handle->value.children.count) {
606         for (d.m_handle=m_handle->value.children.first; index; index--)
607             d.m_handle=d.m_handle->next;
608     }
609     else
610         throw range_error("DDF object not a list with >=index+1 elements");
611     return d;
612 }
613
614 DDF DDF::addmember(const char* path)
615 {
616     char name[MAX_NAME_LEN+1];
617     const char* path_ptr=path;
618     
619     if (m_handle && ddf_strlen(ddf_token(&path_ptr,name))>0) {
620         if (!isstruct())
621             structure();
622
623         DDF new_member=getmember(name);
624         if (!new_member.m_handle) {
625             DDF temp(name);
626             new_member=add(temp);
627         }
628
629         if (new_member.m_handle) {
630             if (ddf_strlen(path_ptr)>0) {
631                 DDF last_member=new_member.addmember(path_ptr);
632                 if (!last_member.m_handle)
633                     return new_member.destroy();
634                 else
635                     return last_member;
636             }
637             return new_member;
638         }
639         return new_member;
640     }
641     return DDF();
642 }
643
644 DDF DDF::getmember(const char* path) const
645 {
646     char name[MAX_NAME_LEN+1];
647     const char* path_ptr=path;
648     DDF current;
649
650     if (isstruct() && ddf_strlen(ddf_token(&path_ptr,name))>0) {
651         current.m_handle=m_handle->value.children.first;
652         while (current.m_handle && strcmp(current.m_handle->name,name)!=0)
653             current.m_handle=current.m_handle->next;
654
655         if (current.m_handle && ddf_strlen(path_ptr)>0)
656             current=current.getmember(path_ptr);
657     }
658     return current;
659 }
660
661
662 void ddf_print_indent(FILE* f, int indent)
663 {
664     for (; indent>0; indent--)
665         putc(' ',f);
666 }
667
668 void DDF::dump(FILE* f, int indent) const
669 {
670     if (!f)
671         f=stderr;
672
673     ddf_print_indent(f,indent);
674     if (m_handle) {
675         switch (m_handle->type) {
676             
677             case ddf_body_t::DDF_EMPTY:
678                 fprintf(f,"empty");
679                 if (m_handle->name)
680                     fprintf(f," %s",m_handle->name);
681                 break;
682
683             case ddf_body_t::DDF_STRING:
684                 if (m_handle->name)
685                     fprintf(f,"char* %s = ",m_handle->name);
686                 else
687                     fprintf(f,"char* = ");
688                 if (const char* chptr=m_handle->value.string) {
689                     putc('"',f);
690                     while (*chptr)
691                         fputc(*chptr++,f);
692                     putc('"',f);
693                 }
694                 else
695                     fprintf(f,"NULL");
696                 break;
697
698             case ddf_body_t::DDF_INT:
699                 if (m_handle->name)
700                     fprintf(f,"long %s = ",m_handle->name);
701                 else
702                     fprintf(f,"long = ");
703                 fprintf(f,"%ld",m_handle->value.integer);
704                 break;
705
706             case ddf_body_t::DDF_FLOAT:
707                 if (m_handle->name)
708                     fprintf(f,"double %s = ",m_handle->name);
709                 else
710                     fprintf(f,"double = ");
711                 fprintf(f,"%.15f",m_handle->value.floating);
712                 break;
713
714             case ddf_body_t::DDF_STRUCT:
715                 fprintf(f,"struct ");
716                 if (m_handle->name)
717                     fprintf(f,"%s ",m_handle->name);
718                 putc('{',f);
719                 if (m_handle->value.children.count) {
720                     putc('\n',f);
721                     DDF child;
722                     child.m_handle=m_handle->value.children.first;
723                     while (child.m_handle) {
724                         child.dump(f,indent+2);
725                         child.m_handle=child.m_handle->next;
726                     }
727                 }
728                 ddf_print_indent(f,indent);
729                 putc('}',f);
730                 break;
731
732             case ddf_body_t::DDF_LIST:
733                 fprintf(f,"list");
734                 if (m_handle->name)
735                     fprintf(f," %s",m_handle->name);
736                 fprintf(f,"[%lu] {",m_handle->value.children.count);
737                 if (m_handle->value.children.count) {
738                     putc('\n',f);
739                     DDF child;
740                     child.m_handle=m_handle->value.children.first;
741                     while (child.m_handle) {
742                         child.dump(f,indent+2);
743                         child.m_handle=child.m_handle->next;
744                     }
745                 }
746                 ddf_print_indent(f,indent);
747                 putc('}',f);
748                 break;
749
750             case ddf_body_t::DDF_POINTER:
751                 if (m_handle->name)
752                     fprintf(f,"void* %s = ",m_handle->name);
753                 else
754                     fprintf(f,"void* = ");
755                 if (m_handle->value.pointer)
756                     fprintf(f,"%p",m_handle->value.pointer);
757                 else
758                     fprintf(f,"NULL");
759                 break;
760
761             default:
762                 fprintf(f,"UNKNOWN -- WARNING: ILLEGAL VALUE");
763         }
764     }
765     else
766         fprintf(f,"NULL");
767     fprintf(f,";\n");
768 }
769
770 // Serialization is fairly easy. We have to walk the DDF and hand-generate a
771 // wddxPacket XML fragment, with some simple extensions. We escape the four major
772 // special characters, which requires that we output strings one char at a time.
773
774 void xml_encode(ostream& os, const char* start)
775 {
776     while (start && *start) {
777         switch (*start) {
778             case '\'':  os << "&apos;";     break;
779             case '<':   os << "&lt;";       break;
780             case '>':   os << "&gt;";       break;
781             case '&':   os << "&amp;";      break;
782             default:    os << *start;
783         }
784         start++;
785     }
786 }
787
788 void serialize(ddf_body_t* p, ostream& os, bool name_attr=true)
789 {
790     if (p) {
791         switch (p->type) {
792             
793             case ddf_body_t::DDF_STRING:
794                 os << "<string";
795                 if (name_attr && p->name) {
796                     os << " name='";
797                     xml_encode(os,p->name);
798                     os << '\'';
799                 }
800                 if (p->value.string) {
801                     os << '>';
802                     xml_encode(os,p->value.string);
803                     os << "</string>\n";
804                 }
805                 else
806                     os << "/>\n";
807                 break;
808
809             case ddf_body_t::DDF_INT:
810                 os << "<number";
811                 if (name_attr && p->name) {
812                     os << " name='";
813                     xml_encode(os,p->name);
814                     os << '\'';
815                 }
816                 os << '>' << p->value.integer << "</number>\n";
817                 break;
818
819             case ddf_body_t::DDF_FLOAT:
820                 os << "<number";
821                 if (name_attr && p->name) {
822                     os << " name='";
823                     xml_encode(os,p->name);
824                     os << '\'';
825                 }
826                 os << '>' << fixed << p->value.floating << dec << "</number>\n";
827                 break;
828
829             case ddf_body_t::DDF_STRUCT:
830             {
831                 os << "<struct";
832                 if (name_attr && p->name) {
833                     os << " name='";
834                     xml_encode(os,p->name);
835                     os << '\'';
836                 }
837                 os << ">\n";
838                 ddf_body_t* child=p->value.children.first;
839                 while (child) {
840                     os << "<var name='";
841                     xml_encode(os,child->name);
842                     os << "'>\n";
843                     serialize(child,os,false);
844                     os << "</var>\n";
845                     child=child->next;
846                 }
847                 os << "</struct>\n";
848                 break;
849             }
850
851             case ddf_body_t::DDF_LIST:
852             {
853                 os << "<array length='" << p->value.children.count << '\'';
854                 if (name_attr && p->name) {
855                     os << " name='";
856                     xml_encode(os,p->name);
857                     os << '\'';
858                 }
859                 os << ">\n";
860                 ddf_body_t* child=p->value.children.first;
861                 while (child) {
862                     serialize(child,os);
863                     child=child->next;
864                 }
865                 os << "</array>\n";
866                 break;
867             }
868
869             case ddf_body_t::DDF_EMPTY:
870             case ddf_body_t::DDF_POINTER:
871             default:
872                 os << "<null";
873                 if (name_attr && p->name) {
874                     os << " name='";
875                     xml_encode(os,p->name);
876                     os << '\'';
877                 }
878                 os << "/>\n";
879                 break;
880         }
881     }
882     else
883         os << "<null/>\n";
884 }
885
886 // The stream insertion will work for any ostream-based object.
887
888 SHIBTARGET_EXPORTS ostream& shibtarget::operator<<(ostream& os, const DDF& obj)
889 {
890     os.precision(15);
891     os << "<wddxPacket version=\"1.0\" lowercase=\"no\">\n<header/>\n<data>\n";
892     serialize(obj.m_handle,os);
893     os << "</data>\n</wddxPacket>\n";
894     return os;
895 }
896
897 // This is a DTD internal subset based on a compatible permutation of the WDDX spec, with the
898 // extension of a name attribute on all the typed elements, which DDF has, but WDDX does not.
899
900 static const char* g_DocType=
901 "\
902 <!DOCTYPE wddxPacket [\n\
903 <!ELEMENT wddxPacket (header, data)>\n\
904 <!ATTLIST wddxPacket version CDATA #FIXED \"1.0\" lowercase (yes|no) \"yes\">\n\
905 <!ELEMENT header (comment?)>\n\
906 <!ELEMENT comment (#PCDATA)>\n\
907 <!ELEMENT data (null | number | string | array | struct)>\n\
908 <!ELEMENT null EMPTY>\n\
909 <!ATTLIST null name CDATA #IMPLIED type CDATA #IMPLIED>\n\
910 <!ELEMENT string (#PCDATA | char)*>\n\
911 <!ATTLIST string name CDATA #IMPLIED type CDATA #IMPLIED>\n\
912 <!ELEMENT char EMPTY>\n\
913 <!ATTLIST char code CDATA #REQUIRED>\n\
914 <!ELEMENT number (#PCDATA)>\n\
915 <!ATTLIST number name CDATA #IMPLIED type CDATA #IMPLIED>\n\
916 <!ELEMENT array (null | number | string | array | struct)*>\n\
917 <!ATTLIST array length CDATA #REQUIRED name CDATA #IMPLIED type CDATA #IMPLIED>\n\
918 <!ELEMENT struct (var*)>\n\
919 <!ATTLIST struct name CDATA #IMPLIED type CDATA #IMPLIED>\n\
920 <!ELEMENT var (null | number | string | array | struct)>\n\
921 <!ATTLIST var name CDATA #REQUIRED>\n\
922 ]>\n";
923
924 // This function constructs a DDF object equivalent to the wddx data element rooted
925 // by the input.
926
927 static const XMLCh _no[] = { chLatin_n, chLatin_o, chNull };
928 static const XMLCh _name[] = { chLatin_n, chLatin_a, chLatin_m, chLatin_e, chNull };
929 static const XMLCh _var[] = { chLatin_v, chLatin_a, chLatin_r, chNull };
930 static const XMLCh _string[] = { chLatin_s, chLatin_t, chLatin_r, chLatin_i, chLatin_n, chLatin_g, chNull };
931 static const XMLCh _number[] = { chLatin_n, chLatin_u, chLatin_m, chLatin_b, chLatin_e, chLatin_r, chNull };
932 static const XMLCh _array[] = { chLatin_a, chLatin_r, chLatin_r, chLatin_a, chLatin_y, chNull };
933 static const XMLCh _struct[] = { chLatin_s, chLatin_t, chLatin_r, chLatin_u, chLatin_c, chLatin_t, chNull };
934 static const XMLCh _lowercase[] =
935 { chLatin_l, chLatin_o, chLatin_w, chLatin_e, chLatin_r, chLatin_c, chLatin_a, chLatin_s, chLatin_e, chNull };
936
937 DDF deserialize(DOMElement* root, bool lowercase)
938 {
939     DDF obj(NULL);
940     auto_ptr_char name_val(root->getAttribute(_name));
941     if (name_val.get() && *name_val.get()) {
942         if (lowercase)
943             for (char* pch=const_cast<char*>(name_val.get()); *pch=tolower(*pch); pch++);
944         obj.name(name_val.get());
945     }
946
947     const XMLCh* tag=root->getTagName();
948     if (!XMLString::compareString(tag,_var)) {
949         root=saml::XML::getFirstChildElement(root);
950         tag=(root ? root->getTagName() : &chNull);
951     }
952
953     if (!XMLString::compareString(tag,_string)) {
954         DOMNode* child=root->getFirstChild();
955         if (child && child->getNodeType()==DOMNode::TEXT_NODE) {
956             auto_ptr_char val(child->getNodeValue());
957             obj.string(val.get());
958         }
959     }
960     else if (!XMLString::compareString(tag,_number)) {
961         DOMNode* child=root->getFirstChild();
962         if (child && child->getNodeType()==DOMNode::TEXT_NODE) {
963             auto_ptr_char val(child->getNodeValue());
964             if (val.get() && strchr(val.get(),'.'))
965                 obj.floating(val.get());
966             else
967                 obj.integer(val.get());
968         }
969     }
970     else if (!XMLString::compareString(tag,_array)) {
971         obj.list();
972         DOMNodeList* children=root->getChildNodes();
973         for (unsigned int i=0; children && i<children->getLength(); i++)
974             if (children->item(i)->getNodeType()==DOMNode::ELEMENT_NODE) {
975                 DDF temp=deserialize(static_cast<DOMElement*>(children->item(i)),lowercase);
976                 obj.add(temp);
977             }
978     }
979     else if (!XMLString::compareString(tag,_struct)) {
980         obj.structure();
981         DOMNodeList* children=root->getChildNodes();
982         for (unsigned int i=0; children && i<children->getLength(); i++)
983             if (children->item(i)->getNodeType()==DOMNode::ELEMENT_NODE) {
984                 DDF temp=deserialize(static_cast<DOMElement*>(children->item(i)),lowercase);
985                 obj.add(temp);
986             }
987     }
988
989     return obj;
990 }
991
992 SHIBTARGET_EXPORTS istream& shibtarget::operator>>(istream& is, DDF& obj)
993 {
994     // Parse the input stream into a DOM tree and construct the equivalent DDF.
995     DOMDocument* doc=NULL;
996     try {
997         XML::StreamInputSource src(is);
998         Wrapper4InputSource dsrc(&src,false);
999         saml::XML::Parser parser(false);    // non-validating
1000         doc=parser.parse(dsrc);
1001         const XMLCh* lowercase=doc->getDocumentElement()->getAttribute(_lowercase);
1002         DOMElement* first=saml::XML::getFirstChildElement(saml::XML::getLastChildElement(doc->getDocumentElement()));
1003         obj.destroy();
1004         obj=deserialize(first,XMLString::compareString(lowercase,_no)!=0);
1005         doc->release();
1006     }
1007     catch(...) {
1008         if (doc)
1009             doc->release();
1010         throw;
1011     }
1012     return is;
1013 }