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