source: trunk/src/core/RpLibrary.cc @ 1264

Last change on this file since 1264 was 1264, checked in by dkearney, 15 years ago

fixing rp library's get() function for retrieving encoded data. if the data is encoded there is no need to do xml entity translation. adding a function rappture's encode class for checking to see if a string has a proper header encode header. adding corresponding tcl functions and tests. also adjusting some of the int declarations to size_t.

  • Property svn:keywords set to Date Rev URL
File size: 64.4 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  Rappture Library Source
4 *
5 * ======================================================================
6 *  AUTHOR:  Derrick S. Kearney, Purdue University
7 *  Copyright (c) 2004-2007  Purdue Research Foundation
8 *
9 *  See the file "license.terms" for information on usage and
10 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * ======================================================================
12 */
13
14#include "scew/scew.h"
15#include "scew_extras.h"
16#include "RpLibrary.h"
17#include "RpEntityRef.h"
18#include "RpEncode.h"
19#include <algorithm>
20#include <iostream>
21#include <string>
22#include <sstream>
23#include <fstream>
24#include <stdlib.h>
25#include <errno.h>
26#include <time.h>
27#include <iterator>
28#include <cctype>
29
30// no arg constructor
31// used when we dont want to read an xml file to populate the xml tree
32// we are building a new xml structure
33RpLibrary::RpLibrary ()
34    :   parser      (NULL),
35        tree        (NULL),
36        root        (NULL),
37        freeTree    (1),
38        freeRoot    (1)
39{
40    tree = scew_tree_create();
41    root = scew_tree_add_root(tree, "run");
42}
43
44RpLibrary::RpLibrary (
45            const std::string filePath
46        )
47    :   parser      (NULL),
48        tree        (NULL),
49        root        (NULL),
50        freeTree    (0),
51        freeRoot    (1)
52{
53    std::stringstream msg;
54
55    if (filePath.length() != 0) {
56        // file path should not be null or empty string unless we are
57        // creating a new xml file
58
59        parser = scew_parser_create();
60
61        scew_parser_ignore_whitespaces(parser, 1);
62
63        /* Loads an XML file */
64        if (!scew_parser_load_file(parser, filePath.c_str()))
65        {
66            scew_error code = scew_error_code();
67            printf("Unable to load file (error #%d: %s)\n", code,
68                   scew_error_string(code));
69            msg << "Unable to load file (error #" << code
70                << ": " << scew_error_string(code) << ")\n";
71
72            if (code == scew_error_expat)
73            {
74                enum XML_Error expat_code =
75                    scew_error_expat_code(parser);
76                printf("Expat error #%d (line %d, column %d): %s\n",
77                       expat_code,
78                       scew_error_expat_line(parser),
79                       scew_error_expat_column(parser),
80                       scew_error_expat_string(expat_code));
81                msg << "Expat error #" << expat_code << " (line "
82                    << scew_error_expat_line(parser) << ", column "
83                    << scew_error_expat_column(parser) << "): "
84                    << "\n";
85            }
86
87            fflush(stdout);
88            scew_parser_free(parser);
89            parser = NULL;
90
91            // update the status of the call
92            status.error(msg.str().c_str());
93            status.addContext("RpLibrary::RpLibrary()");
94        }
95        else
96        {
97            tree = scew_parser_tree(parser);
98            freeTree = 0;
99            root = scew_tree_root(tree);
100        }
101    }
102    else {
103        // create a new xml (from an empty file)
104        freeTree = 1;
105        tree = scew_tree_create();
106        root = scew_tree_add_root(tree, "run");
107    }
108}
109
110
111// copy constructor
112// for some reason making this a const gives me problems
113// when calling xml()
114// need help looking into this
115// RpLibrary ( const RpLibrary& other )
116RpLibrary::RpLibrary ( const RpLibrary& other )
117    : parser    (NULL),
118      tree      (NULL),
119      root      (NULL),
120      freeTree  (0),
121      freeRoot  (1)
122{
123    std::stringstream msg;
124    std::string buffer;
125    int buffLen;
126
127    // fill in the current RpLibrary's data with other's data
128    parser = scew_parser_create();
129    scew_parser_ignore_whitespaces(parser, 1);
130
131    // Loads the XML from other
132    // the length cannot be 0 because xml() should not be returning
133    // empty strings
134    buffer = other.xml();
135    buffLen = buffer.length();
136
137    if (buffLen > 0) {
138        if (!scew_parser_load_buffer(parser,buffer.c_str(),buffLen))
139        {
140            // there was an error loading the buffer
141            // how do you tell the user, you couldn't make a copy?
142            scew_error code = scew_error_code();
143            printf("Unable to load buffer (error #%d: %s)\n", code,
144                   scew_error_string(code));
145            msg << "Unable to load file (error #" << code
146                << ": " << scew_error_string(code) << ")\n";
147
148            if (code == scew_error_expat)
149            {
150                enum XML_Error expat_code =
151                    scew_error_expat_code(parser);
152                printf("Expat error #%d (line %d, column %d): %s\n",
153                       expat_code,
154                       scew_error_expat_line(parser),
155                       scew_error_expat_column(parser),
156                       scew_error_expat_string(expat_code));
157                msg << "Expat error #" << expat_code << " (line "
158                    << scew_error_expat_line(parser) << ", column "
159                    << scew_error_expat_column(parser) << "): "
160                    << "\n";
161            }
162
163            // return an empty RpLibrary?
164            // return EXIT_FAILURE;
165
166            parser = NULL;
167
168            // update the status of the call
169            status.error(msg.str().c_str());
170            status.addContext("RpLibrary::RpLibrary()");
171        }
172        else {
173
174            // parsing the buffer was successful
175            // populate the new data members.
176
177            tree = scew_parser_tree(parser);
178            freeTree = 0;
179            freeRoot = 1;
180            root = scew_tree_root(tree);
181
182        }
183
184    } // end if (buffer.length() != 0) {
185}// end copy constructor
186
187// copy assignment operator
188// for some reason making this a const gives me problems
189// when calling xml()
190// need help looking into this
191// RpLibrary& operator= (const RpLibrary& other) {
192RpLibrary&
193RpLibrary::operator= (const RpLibrary& other) {
194
195    std::stringstream msg;
196    std::string buffer;
197    int buffLen;
198
199    scew_parser* tmp_parser;
200    scew_tree* tmp_tree;
201    scew_element* tmp_root;
202    int tmp_freeTree;
203    int tmp_freeRoot;
204
205    if (this != &other) {
206
207        tmp_parser   = parser;
208        tmp_tree     = tree;
209        tmp_root     = root;
210        tmp_freeTree = freeTree;
211        tmp_freeRoot = freeRoot;
212
213        // fill in the current RpLibrary's data with other's data
214        parser = scew_parser_create();
215        scew_parser_ignore_whitespaces(parser, 1);
216
217        // Loads the XML from other
218        // the length cannot be 0 because xml()
219        // should not be returning empty strings
220        buffer = other.xml();
221        buffLen = buffer.length();
222
223        if (buffLen > 0) {
224            if (!scew_parser_load_buffer(parser,buffer.c_str(),buffLen))
225            {
226                // there was an error loading the buffer
227                // how do you tell the user, you couldn't make a copy?
228                scew_error code = scew_error_code();
229                printf("Unable to load buffer (error #%d: %s)\n", code,
230                       scew_error_string(code));
231                msg << "Unable to load file (error #" << code
232                    << ": " << scew_error_string(code) << ")\n";
233
234                if (code == scew_error_expat)
235                {
236                    enum XML_Error expat_code =
237                        scew_error_expat_code(parser);
238                    printf("Expat error #%d (line %d, column %d): %s\n",
239                           expat_code,
240                           scew_error_expat_line(parser),
241                           scew_error_expat_column(parser),
242                           scew_error_expat_string(expat_code));
243                    msg << "Expat error #" << expat_code << " (line "
244                        << scew_error_expat_line(parser) << ", column "
245                        << scew_error_expat_column(parser) << "): "
246                        << "\n";
247                }
248
249                // return things back to the way they used to be
250                // or maybe return an empty RpLibrary?
251                // return EXIT_FAILURE;
252
253                // return this object to its previous state.
254                parser = tmp_parser;
255
256                // update the status of the call
257                status.error(msg.str().c_str());
258                status.addContext("RpLibrary::RpLibrary()");
259            }
260            else {
261
262                // parsing the buffer was successful
263                // populate the new data members.
264
265                tree = scew_parser_tree(parser);
266                freeTree = 0;
267                freeRoot = 1;
268                root = scew_tree_root(tree);
269
270                // free the current RpLibrary's data
271                // we do the free so far down so we can see if
272                // parsing the other object's xml fails.
273                // if the parsing fails, we can still return this
274                // object to its previous state.
275                if (tmp_tree && tmp_freeTree) {
276                    scew_tree_free(tmp_tree);
277                    tmp_tree = NULL;
278                }
279                if (tmp_parser) {
280                    scew_parser_free(tmp_parser);
281                    tmp_parser = NULL;
282                }
283                if (tmp_root && tmp_freeRoot) {
284                    tmp_root = NULL;
285                }
286            }
287
288        } // end if (buffer.length() != 0) {
289    } // end if (this != &other)
290
291    return *this;
292} // end operator=
293
294
295// default destructor
296RpLibrary::~RpLibrary ()
297{
298    // clean up dynamic memory
299
300    if (tree && freeTree) {
301        scew_tree_free(tree);
302        tree = NULL;
303    }
304    if (parser) {
305        scew_parser_free(parser);
306        parser = NULL;
307    }
308    if (!freeTree && root && freeRoot) {
309        scew_element_free(root);
310        root = NULL;
311    }
312}
313/**********************************************************************/
314// METHOD: _get_attribute()
315/// Return the attribute value matching the provided attribute name.
316/**
317 */
318
319std::string
320RpLibrary::_get_attribute (
321    scew_element* element,
322    std::string attributeName
323    ) const
324{
325    scew_attribute* attribute = NULL;
326    std::string attrVal;
327
328    if (element != NULL)
329    {
330        if (scew_attribute_count(element) > 0) {
331
332            while((attribute=scew_attribute_next(element, attribute)) != NULL)
333            {
334                if (    strcmp( scew_attribute_name(attribute),
335                                attributeName.c_str()) == 0     ){
336                    attrVal = scew_attribute_value(attribute);
337                }
338            }
339        }
340        else {
341            // there are no attributes, count == 0
342        }
343    }
344
345    return attrVal;
346}
347
348/**********************************************************************/
349// METHOD: _path2list()
350/// Convert a path into a list of element names.
351/**
352 */
353
354int
355RpLibrary::_path2list (
356    std::string& path,
357    std::string** list,
358    int listLen
359    ) const
360{
361    std::string::size_type pos = 0;
362    std::string::size_type start = 0;
363    std::string::size_type end = path.length();
364    int index = 0;
365    int retVal = 0;
366    unsigned int parenDepth = 0;
367
368    for (   pos = 0; (pos < end) && (index < listLen); pos++) {
369        if (path[pos] == '(') {
370            parenDepth++;
371            continue;
372        }
373
374        if (path[pos] == ')') {
375            parenDepth--;
376            continue;
377        }
378
379        if ( (path[pos] == '.') && (parenDepth == 0) ) {
380            list[index] = new std::string(path.substr(start,pos-start));
381            index++;
382            start = pos + 1;
383        }
384    }
385
386    // add the last path to the list
387    // error checking for path names like p1.p2.
388    if ( (start < end) && (pos == end) ) {
389        list[index] = new std::string(path.substr(start,pos-start));
390    }
391    retVal = index;
392    index++;
393
394    // null out the rest of the pointers so we know where to stop free'ing
395    while (index < listLen) {
396        list[index++] = NULL;
397    }
398
399    return retVal;
400}
401
402/**********************************************************************/
403// METHOD: _node2name()
404/// Retrieve the id of a node.
405/**
406 */
407
408std::string
409RpLibrary::_node2name (scew_element* node) const
410{
411    // XML_Char const* name = _get_attribute(node,"id");
412    std::string name = _get_attribute(node,"id");
413    std::stringstream retVal;
414    XML_Char const* type = NULL;
415    scew_element* parent = NULL;
416    scew_element** siblings = NULL;
417    unsigned int count = 0;
418    int tmpCount = 0;
419    int index = 0;
420    std::string indexStr;
421
422    type = scew_element_name(node);
423    parent = scew_element_parent(node);
424
425    if (parent) {
426
427        // if (name == NULL) {
428        if (name.empty()) {
429            siblings = scew_element_list(parent, type, &count);
430            if (count > 0) {
431                tmpCount = count;
432                while ((index < tmpCount) && (siblings[index] != node)) {
433                    index++;
434                }
435
436                if (index < tmpCount) {
437
438                    if (index > 0) {
439
440                        retVal << type << --index;
441                    }
442                    else {
443
444                        retVal << type;
445                    }
446
447                    /*
448                    if (retVal == NULL) {
449                        // error with allocating space
450                        return NULL;
451                    }
452                    */
453                }
454            }
455
456            scew_element_list_free(siblings);
457
458        }
459        else {
460
461            retVal << name;
462        }
463    }
464
465    return (retVal.str());
466}
467
468/**********************************************************************/
469// METHOD: _node2comp()
470/// Retrieve the component name of a node
471/**
472 */
473
474std::string
475RpLibrary::_node2comp (scew_element* node) const
476{
477    // XML_Char const* name = _get_attribute(node,"id");
478    std::string id = _get_attribute(node,"id");
479    std::stringstream retVal;
480    XML_Char const* type = NULL;
481    scew_element* parent = NULL;
482    scew_element** siblings = NULL;
483    unsigned int count = 0;
484    int tmpCount = 0;
485    int index = 0;
486    std::string indexStr;
487
488    type = scew_element_name(node);
489    parent = scew_element_parent(node);
490
491    if (parent) {
492        if (id.empty()) {
493            siblings = scew_element_list(parent, type, &count);
494            if (count > 0) {
495                tmpCount = count;
496                // figure out what the index value should be
497                while ((index < tmpCount) && (siblings[index] != node)) {
498                    index++;
499                }
500
501                if (index < tmpCount) {
502                    if (index > 0) {
503                        // retVal << type << --index;
504                        retVal << type << index;
505                    }
506                    else {
507                        retVal << type;
508                    }
509                }
510
511            }
512            else {
513                // count == 0 ??? this state should never be reached
514            }
515            scew_element_list_free(siblings);
516
517        }
518        else {
519            // node has attribute id
520            retVal << type << "(" << id << ")";
521
522        }
523    }
524
525    return (retVal.str());
526}
527
528/**********************************************************************/
529// METHOD: _node2path()
530/// Retrieve the full path name of a node
531/**
532 */
533
534std::string
535RpLibrary::_node2path (scew_element* node) const
536{
537
538    std::stringstream path;
539    scew_element* snode = node;
540    scew_element* parent = NULL;
541
542    if (snode) {
543        parent = scew_element_parent(snode);
544        path.clear();
545
546        while (snode && parent) {
547
548            if (!path.str().empty()) {
549                path.str(_node2comp(snode) + "." + path.str());
550                // path.str("." + _node2comp(snode) + path.str());
551            }
552            else {
553                path.str(_node2comp(snode));
554                // path.str("." + _node2comp(snode));
555            }
556
557            snode = scew_element_parent(snode);
558            parent = scew_element_parent(snode);
559        }
560    }
561
562    return (path.str());
563}
564
565/**********************************************************************/
566// METHOD: _splitPath()
567/// Split a path (component) name into its tag name, index, and id
568/**
569 */
570
571int
572RpLibrary::_splitPath ( std::string& path,
573                        std::string& tagName,
574                        int* idx,
575                        std::string& id ) const
576{
577    int stop = 0;
578    int start = 0;
579    int index = path.length();
580
581    if (index) {
582        index--;
583    }
584
585    if (!path.empty()) {
586        if (path[index] == ')') {
587            stop = index;
588            while (path[index] != '(') {
589                index--;
590            }
591            start = index+1;
592            // strncpy(id,path+start,stop-start);
593            // id = new std::string(path.substr(start,stop-start));
594            id = path.substr(start,stop-start);
595            index--;
596        }
597        if (isdigit(path[index])) {
598            stop = index;
599            while (isdigit(path[index])) {
600                index--;
601            }
602            // sscanf(path[index+1],"%d",idx);
603            sscanf(path.c_str()+index+1,"%d",idx);
604        }
605        if (isalpha(path[index])) {
606            start = 0;
607            stop = index+1;
608            // tagName = new std::string(path.substr(start,stop-start));
609            tagName = path.substr(start,stop-start);
610            // strncpy(tagName,path+start,stop-start);
611        }
612    }
613    else {
614        tagName = "";
615        *idx = 0;
616        id = "";
617    }
618
619    return 1;
620}
621
622/**********************************************************************/
623// METHOD: _find()
624/// Find or create a node and return it.
625/**
626 */
627
628scew_element*
629RpLibrary::_find(std::string path, int create) const
630{
631    std::string tagName = "";
632    std::string id = "";
633    int index = 0;
634    int listLen = (path.length()/2)+1;
635    std::string** list;
636    int path_size = 0;
637    int listIdx = 0;
638    unsigned int count = 0;
639    int tmpCount = 0;
640    int lcv = 0;
641    std::string tmpId;
642
643    scew_element* tmpElement = this->root;
644    scew_element* node = NULL;
645    scew_element** eleList = NULL;
646
647
648    if (path.empty()) {
649        // user gave an empty path
650        return tmpElement;
651    }
652
653    list = (std::string **) calloc(listLen, sizeof( std::string * ) );
654
655    if (!list) {
656        // error calloc'ing space for list
657        return NULL;
658    }
659
660    path_size = _path2list (path,list,listLen);
661
662    while ( (listIdx <= path_size) && (tmpElement != NULL ) ){
663
664        _splitPath(*(list[listIdx]),tagName,&index,id);
665
666        if (id.empty()) {
667            /*
668            # If the name is like "type2", then look for elements with
669            # the type name and return the one with the given index.
670            # If the name is like "type", then assume the index is 0.
671            */
672
673            eleList = scew_element_list(tmpElement, tagName.c_str(), &count);
674            tmpCount = count;
675            if (index < tmpCount) {
676                node = eleList[index];
677            }
678            else {
679                /* there is no element with the specified index */
680                node = NULL;
681            }
682
683            scew_element_list_free(eleList);
684            eleList = NULL;
685        }
686        else {
687
688            /* what if its like type2(id) ? */
689            /* still unresolved */
690
691            /*
692            # If the name is like "type(id)", then look for elements
693            # that match the type and see if one has the requested name.
694            # if the name is like "(id)", then look for any elements
695            # with the requested name.
696            */
697
698            if (!tagName.empty()) {
699                eleList = scew_element_list(tmpElement, tagName.c_str(), &count);
700            }
701            else {
702                eleList = scew_element_list_all(tmpElement, &count);
703            }
704
705            tmpCount = count;
706            for (lcv = 0; (lcv < tmpCount); lcv++) {
707                tmpId = _get_attribute(eleList[lcv], "id");
708                if (!tmpId.empty()) {
709                    if (id == tmpId) {
710                        node = eleList[lcv];
711                        break;
712                    }
713                }
714            }
715
716            if (lcv >= tmpCount) {
717                node = NULL;
718            }
719
720            scew_element_list_free(eleList);
721            eleList = NULL;
722
723        }
724
725        if (node == NULL) {
726            if (create == NO_CREATE_PATH) {
727                // break out instead of returning because we still need to
728                // free the list variable
729                tmpElement = node;
730                break;
731            }
732            else {
733                // create == CREATE_PATH
734                // we should create the rest of the path
735
736                // create the new element
737                // need to figure out how to properly number the new element
738                node = scew_element_add(tmpElement,tagName.c_str());
739                if (! node) {
740                    // a new element was not created
741                }
742
743                // add an attribute and attrValue to the new element
744                if (!id.empty()) {
745                    scew_element_add_attr_pair(node,"id",id.c_str());
746                }
747            }
748        }
749
750        tagName = "";
751        id = "";
752        index = 0;
753        tmpElement = node;
754        listIdx++;
755    }
756
757    // need to free the strings inside of list
758
759    if (list) {
760        for (listIdx = 0; listIdx < listLen; listIdx++) {
761            if (list[listIdx]) {
762                delete(list[listIdx]);
763                list[listIdx] = NULL;
764            }
765        }
766
767        free(list);
768        list = NULL;
769    }
770
771
772    return tmpElement;
773}
774
775/**********************************************************************/
776// METHOD: _checkPathConflict(scew_element *nodeA,scew_element *nodeB)
777/// check to see if nodeA is in nodeB's path
778/**
779 * This is used by put() function (the RpLibrary flavor). It is
780 * used to check if nodeA can be safely deleted and not effect nodeB
781 */
782
783int
784RpLibrary::_checkPathConflict(scew_element *nodeA, scew_element *nodeB) const
785{
786    scew_element *testNode = NULL;
787
788    if ( (nodeA == NULL) || (nodeB == NULL) ) {
789        return 0;
790    }
791
792    if (nodeA == nodeB) {
793        return 1;
794    }
795
796    testNode = nodeB;
797
798    while ((testNode = scew_element_parent(testNode)) != NULL) {
799        if (testNode == nodeA) {
800            return 1;
801        }
802    }
803
804    return 0;
805}
806
807/**********************************************************************/
808// METHOD: element()
809/// Search the path of a xml tree and return a RpLibrary node.
810/**
811 * It is the user's responsibility to delete the object when
812 * they are finished using it?, else i need to make this static
813 */
814
815RpLibrary*
816RpLibrary::element (std::string path) const
817{
818    RpLibrary* retLib = NULL;
819    scew_element* retNode = NULL;
820
821    if (!this->root) {
822        // library doesn't exist, do nothing;
823        return NULL;
824    }
825
826    /*
827    if (path.empty()) {
828        // an empty path returns the current RpLibrary
829        return this;
830    }
831    */
832
833    if (path.empty()) {
834        // this should be a smart pointer,
835        // if someone deletes the original this->root, this object is void
836        // and will be a memory leak.
837        // retNode = this->root;
838        retLib = new RpLibrary(*this);
839    }
840    else {
841        // get the node located at path
842        retNode = _find(path,NO_CREATE_PATH);
843
844        // if the node exists, create a rappture library object for it.
845        if (retNode) {
846            retLib = new RpLibrary( retNode,this->tree );
847        }
848    }
849
850    return retLib;
851}
852
853/**********************************************************************/
854// METHOD: entities()
855/// Search the path of a xml tree and return a list of its entities.
856/**
857 */
858
859std::list<std::string>
860RpLibrary::entities  (std::string path) const
861{
862    std::list<std::string> queue;
863    std::list<std::string>::iterator iter;
864    std::list<std::string> retList;
865    std::list<std::string> childList;
866    std::list<std::string>::iterator childIter;
867
868    RpLibrary* ele = NULL;
869    std::string pathBack = "";
870
871    RpLibrary* child = NULL;
872    std::string childType = "";
873    std::string childPath = "";
874    std::string paramsPath = "";
875
876    RpLibrary* cchild = NULL;
877    std::string cchildType = "";
878    std::string cchildPath = "";
879
880    queue.push_back(path);
881    iter = queue.begin();
882
883    while( iter != queue.end() ) {
884        ele = this->element(*iter);
885        child = NULL;
886
887        if ((*iter).empty()) {
888            pathBack = "";
889        }
890        else {
891            pathBack = *iter + ".";
892        }
893
894        while ( ele && (child = ele->children("",child)) != NULL ) {
895            childList.push_back(child->nodeComp());
896            delete child;
897        }
898
899        childIter = childList.begin();
900
901        while (childIter != childList.end()) {
902            child = ele->element(*childIter);
903
904            childType = child->nodeType();
905            childPath = child->nodeComp();
906            if ( (childType == "group") || (childType == "phase") ) {
907                // add this path to the queue for paths to search
908                queue.push_back(pathBack+childPath);
909            }
910            else if (childType == "structure") {
911                // add this path to the return list
912                retList.push_back(pathBack+child->nodeComp());
913
914                // check to see if there is a ".current.parameters" node
915                // if so, add them to the queue list for paths to search
916                paramsPath = "current.parameters";
917                if (child->element(paramsPath) != NULL) {
918                    queue.push_back((pathBack+child->nodeComp()+"."+paramsPath));
919                }
920            }
921            else {
922                // add this path to the return list
923                retList.push_back(pathBack+child->nodeComp());
924
925                // look for embedded groups and phases
926                // add them to the queue list for paths to search
927                cchild = NULL;
928                while ( (cchild = child->children("",cchild)) != NULL ) {
929                    cchildType = cchild->nodeType();
930                    cchildPath = cchild->nodePath();
931                    if ( (cchildType == "group") || (cchildType == "phase") ) {
932                        // add this path to the queue for paths to search
933                        queue.push_back(cchildPath);
934                    }
935                    delete cchild;
936                }
937            }
938
939            childList.erase(childIter);
940            childIter = childList.begin();
941            delete child;
942        }
943
944        queue.erase(iter);
945        iter = queue.begin();
946    }
947
948    return retList;
949}
950
951/**********************************************************************/
952// METHOD: diff()
953/// find the differences between two xml trees.
954/**
955 */
956
957std::list<std::string>
958RpLibrary::diff (RpLibrary* otherLib, std::string path) const
959{
960
961    std::list<std::string> thisVal; // two node list of specific entity's value
962    std::list<std::string> otherVal; // two node list of specific entity's value
963
964    std::list<std::string> thisv; // list of this library's entities
965    std::list<std::string>::iterator thisIter;
966
967    std::list<std::string> otherv; // list of other library's entities
968    std::list<std::string>::iterator otherIter;
969
970    std::list<std::string> retList;
971
972    std::string entry = "";
973    std::string thisSpath = "";  // temp string
974    std::string otherSpath = ""; // temp string
975
976    if ( (!this->root) || (!otherLib->root) ) {
977        // library doesn't exist, do nothing;
978        return retList;
979    }
980
981
982    thisv = this->entities(path);
983    otherv = otherLib->entities(path);
984
985    thisIter = thisv.begin();
986
987    while (thisIter != thisv.end() ) {
988        // reset otherIter for a new search.
989        otherIter = otherv.begin();
990        while ( (otherIter != otherv.end()) && (*otherIter != *thisIter) ) {
991            otherIter++;
992        }
993
994        //if (!path.empty()) {
995        //    thisSpath = path + "." + *thisIter;
996        //}
997        //else {
998        //    thisSpath = *thisIter;
999        //}
1000        thisSpath = *thisIter;
1001
1002        if (otherIter == otherv.end()) {
1003            // we've reached the end of the search
1004            // and did not find anything, mark this as a '-'
1005            thisVal = this->value(thisSpath);
1006            retList.push_back("-");
1007            retList.push_back(thisSpath);
1008            retList.push_back(thisVal.front());
1009            retList.push_back("");
1010        }
1011        else {
1012
1013            //if (!path.empty()) {
1014            //    otherSpath = path + "." + *otherIter;
1015            //}
1016            //else {
1017            //    otherSpath = *otherIter;
1018            //}
1019            otherSpath = *otherIter;
1020
1021            thisVal = this->value(thisSpath);
1022            otherVal = otherLib->value(otherSpath);
1023            if (thisVal.back() != otherVal.back()) {
1024                // add the difference to the return list
1025                retList.push_back("c");
1026                retList.push_back(otherSpath);
1027                retList.push_back(thisVal.front());
1028                retList.push_back(otherVal.front());
1029            }
1030
1031            // remove the last processed value from otherv
1032            otherv.erase(otherIter);
1033        }
1034
1035        // increment thisv's iterator.
1036        thisIter++;
1037    }
1038
1039    // add any left over values in otherv to the return list
1040    otherIter = otherv.begin();
1041    while ( otherIter != otherv.end() ) {
1042
1043        //if (!path.empty()) {
1044        //    otherSpath = path + "." + *otherIter;
1045        //}
1046        //else {
1047        //    otherSpath = *otherIter;
1048        //}
1049        otherSpath = *otherIter;
1050
1051        otherVal = otherLib->value(otherSpath);
1052
1053        retList.push_back("+");
1054        retList.push_back(otherSpath);
1055        retList.push_back("");
1056        retList.push_back(otherVal.front());
1057
1058        otherv.erase(otherIter);
1059        otherIter = otherv.begin();
1060    }
1061
1062    return retList;
1063}
1064
1065/**********************************************************************/
1066// METHOD: value(path)
1067/// Return a 2 element list containing the regular and normalized values.
1068/**
1069 */
1070
1071std::list<std::string>
1072RpLibrary::value (std::string path) const
1073{
1074    std::list<std::string> retArr;
1075
1076    std::string raw = "";
1077    std::string val = "";
1078
1079    RpLibrary* ele = NULL;
1080    RpLibrary* tele = NULL;
1081
1082    int childCount = 0;
1083    std::stringstream valStr;
1084
1085    ele = this->element(path);
1086
1087    if (ele != NULL ) {
1088
1089        if (ele->nodeType() == "structure") {
1090            raw = path;
1091            // try to find a label to represent the structure
1092            val = ele->get("about.label");
1093
1094            if (val == "") {
1095               val = ele->get("current.about.label");
1096            }
1097
1098            if (val == "") {
1099               tele = ele->element("current");
1100               if ( (tele != NULL) && (tele->nodeComp() != "") ) {
1101                   tele->children("components",NULL,"",&childCount);
1102                   valStr << "<structure> with " << childCount  << " components";
1103                   val = valStr.str();
1104               }
1105            }
1106
1107        }
1108        /*
1109        else if (ele->nodeType() == "number") {
1110            raw = "";
1111            retArr[1] = "";
1112            if ( (tele = ele->element("current")) != NULL) {
1113                raw = tele->get();
1114            }
1115            else if ( (tele = ele->element("default")) != NULL) {
1116                raw = tele->get();
1117            }
1118            val = raw
1119            if ( "" != raw) {
1120                // normalize the units
1121                units = ele->get("units");
1122                if ( "" != units) {
1123
1124                }
1125        }
1126        */
1127        else {
1128            raw = "";
1129            if ( (tele = ele->element("current")) != NULL) {
1130                raw = tele->get();
1131            }
1132            else if ( (tele = ele->element("default")) != NULL) {
1133                raw = tele->get();
1134            }
1135            val = raw;
1136        }
1137    }
1138
1139    retArr.push_back(raw);
1140    retArr.push_back(val);
1141
1142    return retArr;
1143}
1144
1145/**********************************************************************/
1146// METHOD: parent()
1147/// Search the path of a xml tree and return its parent.
1148/**
1149 * It is the user's responsibility to delete the object when
1150 * they are finished using it?, else i need to make this static
1151 */
1152
1153RpLibrary*
1154RpLibrary::parent (std::string path) const
1155{
1156    RpLibrary* retLib = NULL;
1157    std::string parentPath = "";
1158    scew_element* ele = NULL;
1159    scew_element* retNode = NULL;
1160
1161    if (!this->root) {
1162        // library doesn't exist, do nothing;
1163        return NULL;
1164    }
1165
1166    if (path.empty()) {
1167        // an empty path returns the parent of the current RpLibrary
1168        ele = this->root;
1169    }
1170    else {
1171        // else find the node representing the provided path
1172        ele = _find(path,NO_CREATE_PATH);
1173    }
1174
1175    if (ele != NULL) {
1176        retNode = scew_element_parent(ele);
1177        if (retNode) {
1178            // allocate a new rappture library object for the node
1179            retLib = new RpLibrary( retNode,this->tree );
1180        }
1181    }
1182    else {
1183        // path was not found by _find
1184    }
1185
1186
1187    return retLib;
1188}
1189
1190/**********************************************************************/
1191// METHOD: copy()
1192/// Copy the value from fromPath to toPath.
1193//  Copy the value from fromObj.fromPath to toPath
1194//  of the current rappture library object. This can copy rappture
1195//  library elements within or between xml trees.
1196/**
1197 */
1198
1199RpLibrary&
1200RpLibrary::copy (   std::string toPath,
1201                    RpLibrary* fromObj,
1202                    std::string fromPath )
1203{
1204    RpLibrary* value = NULL;
1205
1206    if (!this->root) {
1207        // library doesn't exist, do nothing;
1208        // need a good way to raise error, and this is not it.
1209        return *this;
1210    }
1211
1212    if (fromObj == NULL) {
1213        fromObj = this;
1214    }
1215
1216    if ( (fromObj == this) && (toPath == fromPath) ) {
1217        /* cannot copy over myself, causes path to disappear */
1218        return (*this);
1219    }
1220
1221    value = fromObj->element(fromPath);
1222
1223    if ( !value ) {
1224        status.error("fromPath could not be found within fromObj");
1225        status.addContext("RpLibrary::copy");
1226        return *this;
1227    }
1228
1229    this->put(toPath, value);
1230    status.addContext("RpLibrary::copy");
1231    delete value;
1232
1233    return (*this);
1234
1235}
1236
1237/**********************************************************************/
1238// METHOD: children()
1239/// Return the next child of the node located at 'path'
1240//
1241// The lookup is reset when you send a NULL rpChilNode.
1242// User is responsible for deleting returned values
1243//
1244/**
1245 */
1246
1247/*
1248RpLibrary*
1249RpLibrary::children (   std::string path,
1250                        RpLibrary* rpChildNode,
1251                        std::string type,
1252                        int* childCount)
1253{
1254    static std::string old_path = "";
1255    static RpLibrary* retLib = NULL;
1256    int myChildCount = 0;
1257    scew_element* parentNode = NULL;
1258    scew_element* childNode = NULL;
1259    std::string childName = "";
1260
1261    if (!this->root) {
1262        // library doesn't exist, do nothing;
1263        return NULL;
1264    }
1265
1266
1267    if (path.empty()) {
1268        // an empty path uses the current RpLibrary as parent
1269        parentNode = this->root;
1270    }
1271    else {
1272        // check to see if this path is the same as the one set
1273        // in the last call to this function.
1274        // if so, then we dont need to reset the parentNode
1275        //
1276        // this check is probably more dependent on rpChildNode
1277        // because we want to see if the person want to continue
1278        // an old search or start from the beginning of the child list
1279        //
1280        if ( (path.compare(old_path) == 0) && (rpChildNode != NULL) ) {
1281            parentNode = NULL;
1282        }
1283        // we need to search for a new parentNode
1284        else {
1285            parentNode = _find(path,NO_CREATE_PATH);
1286            if (parentNode == NULL) {
1287                // node not found
1288                // add error code here
1289                return NULL;
1290            }
1291        }
1292    }
1293
1294    old_path = path;
1295
1296
1297    if (rpChildNode) {
1298        childNode = rpChildNode->root;
1299    }
1300
1301    if (parentNode) {
1302        myChildCount = scew_element_count(parentNode);
1303    }
1304
1305    if (childCount) {
1306        *childCount = myChildCount;
1307    }
1308
1309    // clean up old memory
1310    delete retLib;
1311
1312    if ( (childNode = scew_element_next(parentNode,childNode)) ) {
1313
1314        if (!type.empty()) {
1315            childName = scew_element_name(childNode);
1316            // we are searching for a specific child name
1317            // keep looking till we find a name that matches the type.
1318            // if the current name does not match out search type,
1319            // grab the next child and check to see if its null
1320            // if its not null, get its name and test for type again
1321            while (  (type != childName)
1322                  && (childNode = scew_element_next(parentNode,childNode)) ) {
1323
1324                childName = scew_element_name(childNode);
1325            }
1326            if (type == childName) {
1327                // found a child with a name that matches type
1328                retLib = new RpLibrary( childNode,this->tree );
1329            }
1330            else {
1331                // no children with names that match 'type' were found
1332                retLib = NULL;
1333            }
1334        }
1335        else {
1336            retLib = new RpLibrary( childNode,this->tree );
1337        }
1338    }
1339    else {
1340        // somthing happened within scew, get error code and display
1341        // its probable there are no more child elements left to report
1342        retLib = NULL;
1343    }
1344
1345    return retLib;
1346}
1347*/
1348
1349RpLibrary*
1350RpLibrary::children (   std::string path,
1351                        RpLibrary* rpChildNode,
1352                        std::string type,
1353                        int* childCount)
1354{
1355    // this is static for efficency reasons
1356    static std::string old_path = "";
1357    // this was static so user never has to delete the retLib.
1358    // should be replaced by a smart pointer
1359    // static RpLibrary* retLib = NULL;
1360    RpLibrary* retLib = NULL;
1361    int myChildCount = 0;
1362    scew_element* parentNode = NULL;
1363    scew_element* childNode = NULL;
1364    std::string childName = "";
1365
1366    if (!this->root) {
1367        // library doesn't exist, do nothing;
1368        return NULL;
1369    }
1370
1371
1372    // check to see if the last call to this function
1373    // was searching for children of the same path.
1374    if ( (path.compare(old_path) == 0) && (rpChildNode != NULL) ) {
1375        parentNode = NULL;
1376    }
1377    else if (path.empty()) {
1378        // searching for children in a new path.
1379        // an empty path uses the current RpLibrary as parent
1380        parentNode = this->root;
1381    }
1382    else {
1383        // searching for children in a new, non-empty, path.
1384        parentNode = _find(path,NO_CREATE_PATH);
1385        if (parentNode == NULL) {
1386            // node not found
1387            // add error code here
1388            return NULL;
1389        }
1390    }
1391
1392    old_path = path;
1393
1394    if (rpChildNode) {
1395        childNode = rpChildNode->root;
1396    }
1397
1398    if (parentNode) {
1399        myChildCount = scew_element_count(parentNode);
1400        if (childCount) {
1401            *childCount = myChildCount;
1402        }
1403    }
1404
1405    // clean up old memory
1406    // delete retLib;
1407
1408    if ( (childNode = scew_element_next(parentNode,childNode)) ) {
1409
1410        if (!type.empty()) {
1411            childName = scew_element_name(childNode);
1412            // we are searching for a specific child name
1413            // keep looking till we find a name that matches the type.
1414            // if the current name does not match out search type,
1415            // grab the next child and check to see if its null
1416            // if its not null, get its name and test for type again
1417            while (  (type != childName)
1418                  && (childNode = scew_element_next(parentNode,childNode)) ) {
1419
1420                childName = scew_element_name(childNode);
1421            }
1422            if (type == childName) {
1423                // found a child with a name that matches type
1424                retLib = new RpLibrary( childNode,this->tree );
1425            }
1426            else {
1427                // no children with names that match 'type' were found
1428                retLib = NULL;
1429            }
1430        }
1431        else {
1432            retLib = new RpLibrary( childNode,this->tree );
1433        }
1434    }
1435    else {
1436        // somthing happened within scew, get error code and display
1437        // its probable there are no more child elements left to report
1438        retLib = NULL;
1439    }
1440
1441    return retLib;
1442}
1443
1444/**********************************************************************/
1445// METHOD: childCount()
1446/// Returns a std::list<RpLibrary*> of all children under 'path'
1447//
1448//
1449/**
1450 */
1451
1452RpLibrary&
1453RpLibrary::childCount(std::string path, int* childCount)
1454{
1455    if (this->root) {
1456        scew_element* parentNode;
1457        int myChildCount = 0;
1458
1459        parentNode = NULL;
1460        if (path.empty()) {
1461            // an empty path uses the current RpLibrary as parent
1462            parentNode = this->root;
1463        }
1464
1465        if (parentNode) {
1466            myChildCount = scew_element_count(parentNode);
1467        }
1468
1469        if (childCount) {
1470            *childCount = myChildCount;
1471        }
1472    }
1473    return *this;
1474}
1475
1476/**********************************************************************/
1477// METHOD: isNull()
1478/// returns whether this RpLibrary is a valid library node
1479//
1480//
1481/**
1482 */
1483
1484bool
1485RpLibrary::isNull () const
1486{
1487    if (this->root) {
1488        return false;
1489    }
1490
1491    return true;
1492}
1493
1494/**********************************************************************/
1495// METHOD: get()
1496/// Return the string value of the object held at location 'path'
1497/**
1498 */
1499
1500std::string
1501RpLibrary::get (std::string path, int translateFlag) const
1502{
1503    return (this->getString(path, translateFlag));
1504}
1505
1506/**********************************************************************/
1507// METHOD: getString()
1508/// Return the string value of the object held at location 'path'
1509/**
1510 */
1511
1512std::string
1513RpLibrary::getString (std::string path, int translateFlag) const
1514{
1515    Rappture::EntityRef ERTranslator;
1516    scew_element* retNode = NULL;
1517    XML_Char const* retCStr = NULL;
1518    const char* translatedContents = NULL;
1519    std::string retStr = "";
1520    Rappture::Buffer inData;
1521
1522    if (!this->root) {
1523        // library doesn't exist, do nothing;
1524        return retStr;
1525    }
1526
1527    retNode = _find(path,NO_CREATE_PATH);
1528
1529    if (retNode == NULL) {
1530        // need to raise error
1531        return retStr;
1532    }
1533
1534    retCStr = scew_element_contents(retNode);
1535
1536    if (!retCStr) {
1537        return retStr;
1538    }
1539
1540    inData = Rappture::Buffer(retCStr);
1541
1542    if (Rappture::encoding::isencoded(inData.bytes(),inData.size()) != 0) {
1543        // data is encoded,
1544        // coming from an rplib, this means it was at least base64 encoded
1545        // there is no reason to do entity translation
1546        // because base64 character set does not include xml entity chars
1547        status &= Rappture::encoding::decode(inData,0);
1548        status.addContext("RpLibrary::getSting");
1549        retStr = std::string(inData.bytes(),inData.size());
1550    } else {
1551        // check translateFlag to see if we need to translate entity refs
1552        if (translateFlag == RPLIB_TRANSLATE) {
1553            translatedContents = ERTranslator.decode(inData.bytes(),inData.size());
1554            if (translatedContents == NULL) {
1555                // translation failed
1556                if (!status) {
1557                    status.error("Error while translating entity references");
1558                    status.addContext("RpLibrary::getSting");
1559                }
1560            } else {
1561                // subtract 1 from size because ERTranslator adds extra NULL
1562                retStr = std::string(translatedContents,ERTranslator.size()-1);
1563                translatedContents = NULL;
1564            }
1565        }
1566    }
1567
1568    inData.clear();
1569
1570    return retStr;
1571}
1572
1573/**********************************************************************/
1574// METHOD: getDouble()
1575/// Return the double value of the object held at location 'path'
1576/**
1577 */
1578
1579double
1580RpLibrary::getDouble (std::string path) const
1581{
1582    std::string retValStr = "";
1583    double retValDbl = 0;
1584
1585    if (!this->root) {
1586        // library doesn't exist, do nothing;
1587        return retValDbl;
1588    }
1589
1590    retValStr = this->getString(path);
1591    status.addContext("RpLibrary::getDouble");
1592    // think about changing this to strtod()
1593    retValDbl = atof(retValStr.c_str());
1594
1595    return retValDbl;
1596}
1597
1598
1599/**********************************************************************/
1600// METHOD: getInt()
1601/// Return the integer value of the object held at location 'path'
1602/**
1603 */
1604
1605int
1606RpLibrary::getInt (std::string path) const
1607{
1608    std::string retValStr = "";
1609    int retValInt = 0;
1610
1611    if (!this->root) {
1612        // library doesn't exist, do nothing;
1613        return retValInt;
1614    }
1615
1616    retValStr = this->getString(path);
1617    status.addContext("RpLibrary::getInt");
1618    // think about changing this to strtod()
1619    retValInt = atoi(retValStr.c_str());
1620
1621    return retValInt;
1622}
1623
1624
1625/**********************************************************************/
1626// METHOD: getBool()
1627/// Return the boolean value of the object held at location 'path'
1628/**
1629 */
1630
1631bool
1632RpLibrary::getBool (std::string path) const
1633{
1634    std::string retValStr = "";
1635    bool retValBool = false;
1636    int retValLen = 0;
1637
1638    if (!this->root) {
1639        // library doesn't exist, do nothing;
1640        return retValBool;
1641    }
1642
1643    retValStr = this->getString(path);
1644    status.addContext("RpLibrary::getBool");
1645    std::transform (retValStr.begin(),retValStr.end(),retValStr.begin(),tolower);
1646    retValLen = retValStr.length();
1647
1648    if ((retValStr.compare(0,retValLen,"1",0,retValLen) == 0  )   ||
1649        (retValStr.compare(0,retValLen,"yes",0,retValLen) == 0 )  ||
1650        (retValStr.compare(0,retValLen,"true",0,retValLen) == 0 ) ||
1651        (retValStr.compare(0,retValLen,"on",0,retValLen) == 0))
1652    {
1653        retValBool = true;
1654    }
1655    else if((retValStr.compare(0,retValLen,"0",0,retValLen) == 0  )    ||
1656            (retValStr.compare(0,retValLen,"no",0,retValLen) == 0 )    ||
1657            (retValStr.compare(0,retValLen,"false",0,retValLen) == 0 ) ||
1658            (retValStr.compare(0,retValLen,"off",0,retValLen) == 0))
1659    {
1660        retValBool = false;
1661    }
1662    else {
1663        // default to false?
1664        retValBool = false;
1665    }
1666
1667    return retValBool;
1668}
1669
1670
1671/**********************************************************************/
1672// METHOD: getData()
1673/// Return a pointer and memory size of the object held at location 'path'
1674/**
1675 */
1676
1677Rappture::Buffer
1678RpLibrary::getData (std::string path) const
1679{
1680    Rappture::EntityRef ERTranslator;
1681    scew_element* retNode = NULL;
1682    const char* retCStr = NULL;
1683    Rappture::Buffer buf;
1684    int translateFlag = RPLIB_TRANSLATE;
1685    const char* translatedContents = NULL;
1686    int len = 0;
1687
1688    if (!this->root) {
1689        // library doesn't exist, do nothing;
1690        return buf;
1691    }
1692
1693    retNode = _find(path,NO_CREATE_PATH);
1694
1695    if (retNode == NULL) {
1696        // need to raise error
1697        status.error("could not find element located at path");
1698        status.addContext("RpLibrary::getData()");
1699        return buf;
1700    }
1701
1702    retCStr = scew_element_contents(retNode);
1703
1704    if (retCStr == NULL) {
1705        // element located at path is empty
1706        return buf;
1707    }
1708
1709    if (translateFlag == RPLIB_TRANSLATE) {
1710        translatedContents = ERTranslator.decode(retCStr,0);
1711        if (translatedContents == NULL) {
1712            // translation failed
1713            if (!status) {
1714                status.error("Error while translating entity references");
1715                status.addContext("RpLibrary::getData()");
1716            }
1717        }
1718        else {
1719            len = strlen(translatedContents);
1720            buf.append(translatedContents,len);
1721            translatedContents = NULL;
1722        }
1723    }
1724    else {
1725        len = strlen(retCStr);
1726        buf.append(retCStr,len);
1727    }
1728
1729    return buf;
1730}
1731
1732
1733/**********************************************************************/
1734// METHOD: put()
1735/// Put a string value into the xml.
1736/**
1737 */
1738
1739RpLibrary&
1740RpLibrary::put (    std::string path,
1741                    std::string value,
1742                    std::string id,
1743                    unsigned int append,
1744                    unsigned int translateFlag)
1745{
1746    Rappture::EntityRef ERTranslator;
1747    scew_element* retNode = NULL;
1748    std::string tmpVal = "";
1749    const char* contents = NULL;
1750    const char* translatedContents = NULL;
1751
1752    if (!this->root) {
1753        // library doesn't exist, do nothing;
1754        status.error("invalid library object");
1755        status.addContext("RpLibrary::put() - putString");
1756        return *this;
1757    }
1758
1759    // check for binary data
1760    if (Rappture::encoding::isbinary(value.c_str(),value.length()) != 0) {
1761        putData(path,value.c_str(),value.length(),append);
1762        status.addContext("RpLibrary::put() - putString");
1763        return *this;
1764    }
1765
1766    retNode = _find(path,CREATE_PATH);
1767
1768    if (retNode == NULL) {
1769        // node not found, set error
1770        status.error("Error while searching for node: node not found");
1771        status.addContext("RpLibrary::put() - putString");
1772        return *this;
1773    }
1774
1775    if (translateFlag == RPLIB_TRANSLATE) {
1776        translatedContents = ERTranslator.encode(value.c_str(),0);
1777        if (translatedContents == NULL) {
1778            // entity referene translation failed
1779            if (!status) {
1780                status.error("Error while translating entity references");
1781            }
1782        }
1783        else {
1784            value = std::string(translatedContents);
1785            translatedContents = NULL;
1786        }
1787    }
1788
1789    if (append == RPLIB_APPEND) {
1790        contents = scew_element_contents(retNode);
1791        if (contents != NULL) {
1792            tmpVal = std::string(contents);
1793            value = tmpVal + value;
1794        }
1795    }
1796
1797    scew_element_set_contents(retNode,value.c_str());
1798
1799    status.addContext("RpLibrary::put() - putString");
1800    return *this;
1801}
1802
1803/**********************************************************************/
1804// METHOD: put()
1805/// Put a double value into the xml.
1806/**
1807 */
1808
1809RpLibrary&
1810RpLibrary::put (    std::string path,
1811                    double value,
1812                    std::string id,
1813                    unsigned int append )
1814{
1815    std::stringstream valStr;
1816
1817    if (this->root == NULL) {
1818        // library doesn't exist, do nothing;
1819        status.error("invalid library object");
1820        status.addContext("RpLibrary::put()");
1821        return *this;
1822    }
1823
1824    valStr << value;
1825
1826    put(path,valStr.str(),id,append);
1827    status.addContext("RpLibrary::put() - putDouble");
1828    return *this;
1829}
1830
1831/**********************************************************************/
1832// METHOD: put()
1833/// Put a RpLibrary* value into the xml. This is used by copy()
1834/**
1835 *  Append flag adds additional nodes, it does not merge same
1836 *  named nodes together
1837 */
1838
1839RpLibrary&
1840RpLibrary::put (    std::string path,
1841                    RpLibrary* value,
1842                    std::string id,
1843                    unsigned int append )
1844{
1845    scew_element *retNode   = NULL;
1846    scew_element *new_elem  = NULL;
1847    scew_element *childNode = NULL;
1848    scew_element *tmpNode   = NULL;
1849    const char *contents    = NULL;
1850    int retVal              = 1;
1851    int deleteTmpNode       = 0;
1852
1853    if (this->root == NULL) {
1854        // library doesn't exist, do nothing;
1855        status.error("invalid library object");
1856        status.addContext("RpLibrary::put()");
1857        return *this;
1858    }
1859
1860    if (value == NULL) {
1861        // you cannot put a null RpLibrary into the tree
1862        // user specified a null value
1863        status.error("user specified NULL value");
1864        status.addContext("RpLibrary::put()");
1865        return *this;
1866    }
1867
1868    if (value->root == NULL) {
1869        // you cannot put a null RpLibrary into the tree
1870        // user specified a null value
1871        status.error("user specified uninitialized RpLibrary object");
1872        status.addContext("RpLibrary::put()");
1873        return *this;
1874    }
1875
1876    tmpNode = value->root;
1877
1878    if (append == RPLIB_OVERWRITE) {
1879        retNode = _find(path,NO_CREATE_PATH);
1880        if (retNode) {
1881            // compare roots to see if they are part of the
1882            // same xml tree, if so, make a tmp copy of the
1883            // tree to be copied before freeing it.
1884            if (_checkPathConflict(retNode,tmpNode)) {
1885                tmpNode = scew_element_copy(tmpNode);
1886                deleteTmpNode = 1;
1887            }
1888            contents = scew_element_contents(tmpNode);
1889            if (contents) {
1890                scew_element_set_contents(retNode, "");
1891            }
1892
1893            while ( (childNode = scew_element_next(retNode,childNode)) ) {
1894                scew_element_free(childNode);
1895            }
1896        }
1897        else {
1898            // path did not exist and was not created
1899            // do nothing
1900        }
1901    }
1902
1903    retNode = _find(path,CREATE_PATH);
1904
1905    if (retNode) {
1906        contents = scew_element_contents(tmpNode);
1907        if (contents) {
1908            scew_element_set_contents(retNode, contents);
1909        }
1910
1911        while ( (childNode = scew_element_next(tmpNode,childNode)) ) {
1912            if ((new_elem = scew_element_copy(childNode))) {
1913                if (scew_element_add_elem(retNode, new_elem)) {
1914                    // maybe we want to count the number of children
1915                    // that we have successfully added?
1916                    retVal = 0;
1917                }
1918                else {
1919                    // adding new element failed
1920                    status.error("error while adding child node");
1921                    status.addContext("RpLibrary::put()");
1922                }
1923            }
1924            else {
1925                // copying new element failed
1926                status.error("error while copying child node");
1927                status.addContext("RpLibrary::put()");
1928            }
1929        }
1930
1931        if (deleteTmpNode == 1) {
1932            scew_element_free(tmpNode);
1933        }
1934    }
1935    else {
1936        // path did not exist and was not created.
1937        status.error("error while creating child node");
1938        status.addContext("RpLibrary::put()");
1939    }
1940
1941    return *this;
1942}
1943
1944
1945/**********************************************************************/
1946// METHOD: putData()
1947/// Put a data from a buffer into the xml.
1948/**
1949 *  Append flag adds additional nodes, it does not merge same
1950 *  named nodes together
1951 */
1952
1953RpLibrary&
1954RpLibrary::putData (std::string path,
1955                    const char* bytes,
1956                    int nbytes,
1957                    unsigned int append  )
1958{
1959    scew_element* retNode = NULL;
1960    const char* contents = NULL;
1961    Rappture::Buffer inData;
1962    unsigned int bytesWritten = 0;
1963    size_t flags = 0;
1964
1965    if (!this->root) {
1966        // library doesn't exist, do nothing;
1967        return *this;
1968    }
1969
1970    retNode = _find(path,CREATE_PATH);
1971
1972    if (retNode) {
1973
1974        if (append == RPLIB_APPEND) {
1975            if ( (contents = scew_element_contents(retNode)) ) {
1976                inData.append(contents);
1977                // base64 decode and un-gzip the data
1978                status &= Rappture::encoding::decode(inData,0);
1979                if (int(status) != 0) {
1980                    status.addContext("RpLibrary::putData()");
1981                    return *this;
1982                }
1983            }
1984        }
1985
1986        inData.append(bytes,nbytes);
1987        // gzip and base64 encode the data
1988        flags = RPENC_Z|RPENC_B64|RPENC_HDR;
1989        status &= Rappture::encoding::encode(inData,flags);
1990
1991        bytesWritten = (unsigned int) inData.size();
1992        scew_element_set_contents_binary(retNode,inData.bytes(),&bytesWritten);
1993    }
1994    else {
1995        // node not found, set error
1996        if (!status) {
1997            status.error("Error while searching for node: node not found");
1998        }
1999    }
2000
2001    status.addContext("RpLibrary::putData()");
2002    return *this;
2003}
2004
2005
2006/**********************************************************************/
2007// METHOD: putFile()
2008/// Put data from a file into the xml.
2009/**
2010 *  Append flag adds additional nodes, it does not merge same
2011 *  named nodes together
2012 */
2013
2014RpLibrary&
2015RpLibrary::putFile (std::string path,
2016                    std::string fileName,
2017                    unsigned int compress,
2018                    unsigned int append  )
2019{
2020    Rappture::Buffer buf;
2021    Rappture::Buffer fileBuf;
2022    Rappture::Outcome err;
2023
2024    if (!this->root) {
2025        // library doesn't exist, do nothing;
2026        return *this;
2027    }
2028
2029    fileBuf.load(fileName.c_str());
2030    if (compress == RPLIB_COMPRESS) {
2031        putData(path,fileBuf.bytes(),fileBuf.size(),append);
2032    }
2033    else {
2034        fileBuf.append("\0",1);
2035        put(path,fileBuf.bytes(),"",append,RPLIB_TRANSLATE);
2036    }
2037    status.addContext("RpLibrary::putFile()");
2038    return *this;
2039}
2040
2041
2042/**********************************************************************/
2043// METHOD: remove()
2044/// Remove the provided path from this RpLibrary
2045/**
2046 */
2047
2048RpLibrary*
2049RpLibrary::remove ( std::string path )
2050{
2051    scew_element* ele = NULL;
2052    int setNULL = 0;
2053    RpLibrary* retLib = NULL;
2054
2055    if (!this->root) {
2056        // library doesn't exist, do nothing;
2057        return NULL;
2058    }
2059
2060    if ( !path.empty() ) {
2061        ele = _find(path,NO_CREATE_PATH);
2062    }
2063    else {
2064        // telling this function to remove "" is essentially destroying
2065        // the object. most functions will fail after a call like this.
2066        ele = this->root;
2067        setNULL++;
2068    }
2069
2070    if (ele) {
2071        scew_element_free(ele);
2072        if (setNULL != 0) {
2073            // this is the case where user specified an empty path.
2074            // the object is useless, and will be deleted.
2075            this->root = NULL;
2076            retLib = NULL;
2077        }
2078        else {
2079            retLib = this;
2080        }
2081    }
2082
2083    return retLib;
2084}
2085
2086/**********************************************************************/
2087// METHOD: xml()
2088/// Return the xml text held in this RpLibrary
2089/**
2090 */
2091
2092std::string
2093RpLibrary::xml () const
2094{
2095    std::stringstream outString;
2096
2097    if (!this->root) {
2098        // library doesn't exist, do nothing;
2099        return std::string("");
2100    }
2101
2102    outString << "<?xml version=\"1.0\"?>\n";
2103    print_element(this->root, 0, outString);
2104
2105    return outString.str();
2106}
2107
2108/**********************************************************************/
2109// METHOD: nodeType()
2110/// Return the type name of this node
2111/**
2112 */
2113
2114std::string
2115RpLibrary::nodeType () const
2116{
2117    if (!this->root) {
2118        // library doesn't exist, do nothing;
2119        return std::string("");
2120    }
2121
2122    return std::string(scew_element_name(root));
2123}
2124
2125/**********************************************************************/
2126// METHOD: nodeId()
2127/// Return the id of this node.
2128/**
2129 */
2130
2131std::string
2132RpLibrary::nodeId () const
2133{
2134    if (!this->root) {
2135        // library doesn't exist, do nothing;
2136        return std::string("");
2137    }
2138
2139    return _node2name(root);
2140}
2141
2142/**********************************************************************/
2143// METHOD: nodeComp()
2144/// Return the component name of this node.
2145/**
2146 */
2147
2148std::string
2149RpLibrary::nodeComp () const
2150{
2151    if (!this->root) {
2152        // library doesn't exist, do nothing;
2153        return std::string("");
2154    }
2155
2156    return _node2comp(root);
2157}
2158
2159/**********************************************************************/
2160// METHOD: nodePath()
2161/// Return the component name of this node's path.
2162/**
2163 */
2164
2165std::string
2166RpLibrary::nodePath () const
2167{
2168    if (!this->root) {
2169        // library doesn't exist, do nothing;
2170        return std::string("");
2171    }
2172
2173    return _node2path(root);
2174}
2175
2176/**********************************************************************/
2177// METHOD: outcome()
2178/// Return the status object of this library object.
2179/**
2180 */
2181
2182Rappture::Outcome&
2183RpLibrary::outcome() const
2184{
2185    return status;
2186}
2187
2188/*
2189 * ----------------------------------------------------------------------
2190 *  METHOD: result
2191 *
2192 *  Clients call this function at the end of their simulation, to
2193 *  pass the simulation result back to the Rappture GUI.  It writes
2194 *  out the given XML object to a runXXX.xml file, and then writes
2195 *  out the name of that file to stdout.
2196 * ======================================================================
2197 *  AUTHOR:  Michael McLennan, Purdue University
2198 *  Copyright (c) 2004-2007
2199 *  Purdue Research Foundation, West Lafayette, IN
2200 * ======================================================================
2201 */
2202void
2203RpLibrary::result(int exitStatus)
2204{
2205    std::stringstream outputFile;
2206    std::fstream file;
2207    std::string xmlText = "";
2208    time_t t = 0;
2209    struct tm* timeinfo = NULL;
2210    std::string timestamp = "";
2211    std::string username = "";
2212    std::string hostname = "";
2213    char *user = NULL;
2214
2215    if (this->root) {
2216        outputFile << "run" << (int)time(&t) << ".xml";
2217        file.open(outputFile.str().c_str(),std::ios::out);
2218
2219        put("tool.version.rappture.revision","$LastChangedRevision: 1264 $");
2220        put("tool.version.rappture.modified","$LastChangedDate: 2009-01-07 17:31:14 +0000 (Wed, 07 Jan 2009) $");
2221        if ( "" == get("tool.version.rappture.language") ) {
2222            put("tool.version.rappture.language","c++");
2223        }
2224
2225        // generate a timestamp for the run file
2226        timeinfo = localtime(&t);
2227        timestamp = std::string(ctime(&t));
2228        // erase the 24th character because it is a newline
2229        timestamp.erase(24);
2230        // concatinate the timezone
2231        timestamp.append(" ");
2232#ifdef _WIN32
2233        timestamp.append(_tzname[_daylight]);
2234        // username is left blank for windows because i dont know
2235        // how to retrieve username on win32 environment.
2236        username = "";
2237        hostname = "";
2238#else
2239        timestamp.append(timeinfo->tm_zone);
2240        user = getenv("USER");
2241        if (user != NULL) {
2242            username = std::string(user);
2243        } else {
2244            user = getenv("LOGNAME");
2245            if (user != NULL) {
2246                username = std::string(user);
2247            }
2248        }
2249#endif
2250
2251        // add the timestamp to the run file
2252        put("output.time", timestamp);
2253        put("output.status",exitStatus);
2254        put("output.user",username);
2255        put("output.host",hostname);
2256
2257        if ( file.is_open() ) {
2258            xmlText = xml();
2259            if (!xmlText.empty()) {
2260                file << xmlText;
2261            }
2262            // check to make sure there were no
2263            // errors while writing the run.xml file.
2264            if (   (!file.good())
2265                || ((long)xmlText.length() != ((long)file.tellp()-(long)1))
2266               ) {
2267                 status.error("Error while writing run file");
2268                 status.addContext("RpLibrary::result()");
2269            }
2270            file.close();
2271        }
2272        else {
2273            status.error("Error while opening run file");
2274            status.addContext("RpLibrary::result()");
2275        }
2276        std::cout << "=RAPPTURE-RUN=>" << outputFile.str() << std::endl;
2277    }
2278}
2279
2280/**********************************************************************/
2281// METHOD: print_indent()
2282/// Add indentations to the requested stringstream object.
2283/**
2284 */
2285
2286void
2287RpLibrary::print_indent(    unsigned int indent,
2288                            std::stringstream& outString ) const
2289{
2290
2291    // keep this around incase you want to use tabs instead of spaces
2292    // while ( (indent--) > 0)
2293    // {
2294    //     outString << "\t";
2295    // }
2296
2297    // keep this around incase you want to use spaces instead of tabs
2298    int cnt = indent*INDENT_SIZE;
2299    while ( (cnt--) > 0)
2300    {
2301        outString << " ";
2302    }
2303
2304}
2305
2306/**********************************************************************/
2307// METHOD: print_attributes()
2308/// Print the attribute names and values for the provided xml node
2309/**
2310 */
2311
2312void
2313RpLibrary::print_attributes(    scew_element* element,
2314                                std::stringstream& outString ) const
2315{
2316    scew_attribute* attribute = NULL;
2317
2318    if (element != NULL)
2319    {
2320        if (scew_attribute_count(element) > 0) {
2321            /**
2322             * Iterates through the element's attribute list, printing the
2323             * pair name-value.
2324             */
2325            attribute = NULL;
2326            while((attribute=scew_attribute_next(element, attribute)) != NULL)
2327            {
2328                outString << " " << scew_attribute_name(attribute) << "=\"" <<
2329                       scew_attribute_value(attribute) << "\"";
2330            }
2331        }
2332    }
2333}
2334
2335
2336/**********************************************************************/
2337// METHOD: print_element()
2338/// Print the value of the node and its attributes to a stringstream object
2339/**
2340 */
2341
2342void
2343RpLibrary::print_element(   scew_element* element,
2344                            unsigned int indent,
2345                            std::stringstream& outString    ) const
2346{
2347    scew_element* child = NULL;
2348    XML_Char const* contents = NULL;
2349
2350    if (element == NULL)
2351    {
2352        return;
2353    }
2354
2355    /**
2356     * Prints the starting element tag with its attributes.
2357     */
2358    print_indent(indent, outString);
2359    outString << "<" << scew_element_name(element);
2360    print_attributes(element,outString);
2361    outString << ">";
2362    contents = scew_element_contents(element);
2363    if (contents == NULL)
2364    {
2365        outString << "\n";
2366    }
2367
2368    /**
2369     * Call print_element function again for each child of the
2370     * current element.
2371     */
2372    child = NULL;
2373    while ((child = scew_element_next(element, child)) != NULL)
2374    {
2375        print_element(child, indent + 1, outString);
2376    }
2377
2378    /* Prints element's content. */
2379    if (contents != NULL)
2380    {
2381        outString << contents;
2382    }
2383    else
2384    {
2385        print_indent(indent, outString);
2386    }
2387
2388    /**
2389     * Prints the closing element tag.
2390     */
2391    outString << "</" << scew_element_name(element) << ">\n" ;
2392}
Note: See TracBrowser for help on using the repository browser.