libdap Updated for version 3.20.11
libdap4 is an implementation of OPeNDAP's DAP protocol.
AttrTable.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2002,2003 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// (c) COPYRIGHT URI/MIT 1994-1999
26// Please read the full copyright statement in the file COPYRIGHT_URI.
27//
28// Authors:
29// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30
31// jhrg 7/29/94
32
33#include "config.h"
34
35#include <cassert>
36#include <sstream>
37
38#include "AttrTable.h"
39
40#include "util.h"
41#include "escaping.h"
42#include "DapIndent.h"
43
44#include "debug.h"
45
46// Should the www2id and id2www functions be used to encode attribute names?
47// Probably not... jhrg 11/16/11
48#define WWW_ENCODING 0
49// See the note for del_attr_table(). That method now deletes the contained
50// AttrTable.
51#define NEW_DEL_ATTR_TABLE_BEHAVIOR 0
52
53using std::cerr;
54using std::string;
55using std::endl;
56using std::vector;
57
58namespace libdap {
59
61string remove_space_encoding(const string &s)
62{
63 string::size_type pos = s.find("%20");
64 if (pos != string::npos) {
65 string n = s;
66 do {
67 n.replace(pos, 3, " ");
68 pos = n.find("%20");
69 } while (pos != string::npos);
70 return n;
71 }
72 else {
73 return s;
74 }
75}
76
78string add_space_encoding(const string &s)
79{
80 string::size_type pos = s.find(" ");
81 if (pos != string::npos) {
82 string n = s;
83 do {
84 n.replace(pos, 1, "%20");
85 pos = n.find(" ");
86 } while (pos != string::npos);
87 return n;
88 }
89 else {
90 return s;
91 }
92}
93
98{
99 switch (at) {
100 case Attr_container:
101 return "Container";
102 case Attr_byte:
103 return "Byte";
104 case Attr_int16:
105 return "Int16";
106 case Attr_uint16:
107 return "UInt16";
108 case Attr_int32:
109 return "Int32";
110 case Attr_uint32:
111 return "UInt32";
112 case Attr_float32:
113 return "Float32";
114 case Attr_float64:
115 return "Float64";
116 case Attr_string:
117 return "String";
118 case Attr_url:
119 return "Url";
120 case Attr_other_xml:
121 return "OtherXML";
122 default:
123 return "";
124 }
125}
126
127AttrType String_to_AttrType(const string &s)
128{
129 string s2 = s;
130 downcase(s2);
131
132 if (s2 == "container")
133 return Attr_container;
134 else if (s2 == "byte")
135 return Attr_byte;
136 else if (s2 == "int16")
137 return Attr_int16;
138 else if (s2 == "uint16")
139 return Attr_uint16;
140 else if (s2 == "int32")
141 return Attr_int32;
142 else if (s2 == "uint32")
143 return Attr_uint32;
144 else if (s2 == "float32")
145 return Attr_float32;
146 else if (s2 == "float64")
147 return Attr_float64;
148 else if (s2 == "string")
149 return Attr_string;
150 else if (s2 == "url")
151 return Attr_url;
152 else if (s2 == "otherxml")
153 return Attr_other_xml;
154 else
155 return Attr_unknown;
156}
157
161{
162 d_name = at.d_name;
163 d_is_global_attribute = at.d_is_global_attribute;
164
165 // Set the parent to null (no parent, not in container)
166 // since using at.d_parent is semantically incorrect
167 // and potentially dangerous.
168 d_parent = 0;
169
170 Attr_citer i = at.attr_map.begin();
171 Attr_citer ie = at.attr_map.end();
172 for (; i != ie; ++i) {
173 // this deep-copies containers recursively
174 entry *e = new entry(*(*i));
175 attr_map.push_back(e);
176
177 // If the entry being added was a container,
178 // set its parent to this to maintain invariant.
179 if (e->type == Attr_container) {
180 assert(e->attributes);
181 e->attributes->d_parent = this;
182 }
183 }
184}
185
189AttrTable::AttrTable() :
190 DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true)
191{
192}
193
194AttrTable::AttrTable(const AttrTable &rhs) :
195 DapObj()
196{
197 clone(rhs);
198}
199
200// Private
201void AttrTable::delete_attr_table()
202{
203 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
204 delete *i;
205 }
206 attr_map.clear();
207}
208
209AttrTable::~AttrTable()
210{
211 delete_attr_table();
212}
213
214AttrTable &
215AttrTable::operator=(const AttrTable &rhs)
216{
217 if (this != &rhs) {
218 delete_attr_table();
219 clone(rhs);
220 }
221
222 return *this;
223}
225
231unsigned int AttrTable::get_size() const
232{
233 return attr_map.size();
234}
235
239{
240 return d_name;
241}
242
245void AttrTable::set_name(const string &n)
246{
247#if WWW_ENCODING
248 d_name = www2id(n);
249#else
250 d_name = remove_space_encoding(n);
251#endif
252}
253
254#if 0
255// This was taken from das.y and could be used here to make the 'dods_errors'
256// attribute container like the parser used to. Then again, maybe this feature
257// was just BS. jhrg (ticket 1469)
258static void add_bad_attribute(AttrTable *attr, const string &type, const string &name, const string &value,
259 const string &msg) {
260 // First, if this bad value is already in a *_dods_errors container,
261 // then just add it. This can happen when the server side processes a DAS
262 // and then hands it off to a client which does the same.
263 // Make a new container. Call it <attr's name>_errors. If that container
264 // already exists, use it.
265 // Add the attribute.
266 // Add the error string to an attribute in the container called
267 // `<name_explanation.'.
268
269 if (attr->get_name().find("_dods_errors") != string::npos) {
270 attr->append_attr(name, type, value);
271 }
272 else {
273 // I think _dods_errors should be _dap_error. jhrg 11/16/11
274 string error_cont_name = attr->get_name() + "_dods_errors";
275 AttrTable *error_cont = attr->get_attr_table(error_cont_name);
276 if (!error_cont)
277 error_cont = attr->append_container(error_cont_name);
278
279 error_cont->append_attr(name, type, value);
280
281#ifndef ATTR_STRING_QUOTE_FIX
282 error_cont->append_attr(name + "_dap_explanation", "String", "\"" + msg + "\"");
283#else
284 error_cont->append_attr(name + "_dap_explanation", "String", msg);
285#endif
286 }
287}
288#endif
289
307unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value)
308{
309 DBG(cerr << "Entering AttrTable::append_attr" << endl);
310#if WWW_ENCODING
311 string lname = www2id(name);
312#else
313 string lname = remove_space_encoding(name);
314#endif
315
316 Attr_iter iter = simple_find(lname);
317
318 // If the types don't match OR this attribute is a container, calling
319 // this mfunc is an error!
320 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
321 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
322 if (iter != attr_map.end() && (get_type(iter) == "Container"))
323 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
324
325 if (iter != attr_map.end()) { // Must be a new attribute value; add it.
326 (*iter)->attr->push_back(value);
327 return (*iter)->attr->size();
328 }
329 else { // Must be a completely new attribute; add it
330 entry *e = new entry;
331
332 e->name = lname;
333 e->is_alias = false;
334 e->type = String_to_AttrType(type); // Record type using standard names.
335 e->attr = new vector<string> ;
336 e->attr->push_back(value);
337
338 attr_map.push_back(e);
339
340 return e->attr->size(); // return the length of the attr vector
341 }
342}
343
362unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values)
363{
364 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
365#if WWW_ENCODING
366 string lname = www2id(name);
367#else
368 string lname = remove_space_encoding(name);
369#endif
370 Attr_iter iter = simple_find(lname);
371
372 // If the types don't match OR this attribute is a container, calling
373 // this mfunc is an error!
374 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
375 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
376 if (iter != attr_map.end() && (get_type(iter) == "Container"))
377 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
378
379 if (iter != attr_map.end()) { // Must be new attribute values; add.
380 vector<string>::iterator i = values->begin();
381 while (i != values->end())
382 (*iter)->attr->push_back(*i++);
383
384 return (*iter)->attr->size();
385 }
386 else { // Must be a completely new attribute; add it
387 entry *e = new entry;
388
389 e->name = lname;
390 e->is_alias = false;
391 e->type = String_to_AttrType(type); // Record type using standard names.
392 e->attr = new vector<string> (*values);
393
394 attr_map.push_back(e);
395
396 return e->attr->size(); // return the length of the attr vector
397 }
398}
399
409AttrTable *
411{
412 AttrTable *new_at = new AttrTable;
413 AttrTable *ret = NULL;
414 try {
415 ret = append_container(new_at, name);
416 } catch (Error &e) {
417 // an error occurred, attribute with that name already exists
418 delete new_at;
419 new_at = 0;
420 throw;
421 }
422 return ret;
423}
424
439AttrTable *
441{
442#if WWW_ENCODING
443 string lname = www2id(name);
444#else
445 string lname = remove_space_encoding(name);
446#endif
447
448 if (simple_find(name) != attr_end())
449 throw Error("There already exists a container called '" + name + "' in this attribute table (" + at->get_name() + "). (1)");
450
451 DBG(cerr << "Setting appended attribute container name to: " << lname << endl);
452 at->set_name(lname);
453
454 entry *e = new entry;
455 e->name = lname;
456 e->is_alias = false;
457 e->type = Attr_container;
458 e->attributes = at;
459
460 attr_map.push_back(e);
461
462 at->d_parent = this;
463
464 return e->attributes;
465}
466
481void AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter)
482{
483 string::size_type dotpos = target.rfind('.');
484 if (dotpos != string::npos) {
485 string container = target.substr(0, dotpos);
486 string field = target.substr(dotpos + 1);
487
488 *at = find_container(container);
489 if (*at) {
490 *iter = (*at)->simple_find(field);
491 }
492 else {
493 *iter = attr_map.end();
494 }
495 }
496 else {
497 *at = recurrsive_find(target, iter);
498 }
499}
500
512AttrTable *
513AttrTable::recurrsive_find(const string &target, Attr_iter *location)
514{
515 Attr_iter i = attr_begin();
516 while (i != attr_end()) {
517 if (target == (*i)->name) {
518 *location = i;
519 return this;
520 }
521 else if ((*i)->type == Attr_container) {
522 AttrTable *at = (*i)->attributes->recurrsive_find(target, location);
523 if (at)
524 return at;
525 }
526
527 ++i;
528 }
529
530 *location = i;
531 return 0;
532}
533
534// Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
541AttrTable::Attr_iter AttrTable::simple_find(const string &target)
542{
543 Attr_iter i;
544 for (i = attr_map.begin(); i != attr_map.end(); ++i) {
545 if (target == (*i)->name) {
546 break;
547 }
548 }
549 return i;
550}
551
565AttrTable *
566AttrTable::find_container(const string &target)
567{
568 string::size_type dotpos = target.find('.');
569 if (dotpos != string::npos) {
570 string container = target.substr(0, dotpos);
571 string field = target.substr(dotpos + 1);
572
573 AttrTable *at = simple_find_container(container);
574 return (at) ? at->find_container(field) : 0;
575 }
576 else {
577 return simple_find_container(target);
578 }
579}
580
581// Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
582AttrTable *
583AttrTable::simple_find_container(const string &target)
584{
585 if (get_name() == target)
586 return this;
587
588 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
589 if (is_container(i) && target == (*i)->name) {
590 return (*i)->attributes;
591 }
592 }
593
594 return 0;
595}
596
604
606AttrTable *
607AttrTable::get_attr_table(const string &name)
608{
609 return find_container(name);
610}
611
613string AttrTable::get_type(const string &name)
614{
615 Attr_iter p = simple_find(name);
616 return (p != attr_map.end()) ? get_type(p) : (string) "";
617}
618
622{
623 Attr_iter p = simple_find(name);
624 return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown;
625}
626
634unsigned int AttrTable::get_attr_num(const string &name)
635{
636 Attr_iter iter = simple_find(name);
637 return (iter != attr_map.end()) ? get_attr_num(iter) : 0;
638}
639
652vector<string> *
653AttrTable::get_attr_vector(const string &name)
654{
655 Attr_iter p = simple_find(name);
656 return (p != attr_map.end()) ? get_attr_vector(p) : 0;
657}
658
675void AttrTable::del_attr(const string &name, int i)
676{
677#if WWW_ENCODING
678 string lname = www2id(name);
679#else
680 string lname = remove_space_encoding(name);
681#endif
682
683 Attr_iter iter = simple_find(lname);
684 if (iter != attr_map.end()) {
685 if (i == -1) { // Delete the whole attribute
686 entry *e = *iter;
687 attr_map.erase(iter);
688 delete e;
689 e = 0;
690 }
691 else { // Delete one element from attribute array
692 // Don't try to delete elements from the vector of values if the
693 // map is a container!
694 if ((*iter)->type == Attr_container)
695 return;
696
697 vector<string> *sxp = (*iter)->attr;
698
699 assert(i >= 0 && i < (int) sxp->size());
700 sxp->erase(sxp->begin() + i); // rm the element
701 }
702 }
703}
704
706
711AttrTable::Attr_iter AttrTable::attr_begin()
712{
713 return attr_map.begin();
714}
715
719AttrTable::Attr_iter AttrTable::attr_end()
720{
721 return attr_map.end();
722}
723
732AttrTable::Attr_iter AttrTable::get_attr_iter(int i)
733{
734 return attr_map.begin() + i;
735}
736
738string AttrTable::get_name(Attr_iter iter)
739{
740 assert(iter != attr_map.end());
741
742 return (*iter)->name;
743}
744
746bool AttrTable::is_container(Attr_iter i)
747{
748 return (*i)->type == Attr_container;
749}
750
756AttrTable *
758{
759 assert(iter != attr_map.end());
760 return (*iter)->type == Attr_container ? (*iter)->attributes : 0;
761}
762
781AttrTable::Attr_iter AttrTable::del_attr_table(Attr_iter iter)
782{
783 if ((*iter)->type != Attr_container)
784 return ++iter;
785
786 // the caller intends to delete/reuse the contained AttrTable,
787 // so zero it out so it doesn't get deleted before we delete the entry
788 // [mjohnson]
789 struct entry *e = *iter;
790 // container no longer has a parent.
791 if (e->attributes) {
792 e->attributes->d_parent = 0;
793
794#if NEW_DEL_ATTR_TABLE_BEHAVIOR
795 delete e->attributes;
796#endif
797 e->attributes = 0;
798 }
799
800 delete e;
801
802 return attr_map.erase(iter);
803}
804
808string AttrTable::get_type(Attr_iter iter)
809{
810 assert(iter != attr_map.end());
811 return AttrType_to_String((*iter)->type);
812}
813
818{
819 return (*iter)->type;
820}
821
829unsigned int AttrTable::get_attr_num(Attr_iter iter)
830{
831 assert(iter != attr_map.end());
832 return ((*iter)->type == Attr_container) ? (*iter)->attributes->get_size() : (*iter)->attr->size();
833}
834
851string AttrTable::get_attr(Attr_iter iter, unsigned int i)
852{
853 assert(iter != attr_map.end());
854
855 return (*iter)->type == Attr_container ? (string) "None" : (*(*iter)->attr)[i];
856}
857
858string AttrTable::get_attr(const string &name, unsigned int i)
859{
860 Attr_iter p = simple_find(name);
861 return (p != attr_map.end()) ? get_attr(p, i) : (string) "";
862}
863
875vector<string> *
877{
878 assert(iter != attr_map.end());
879 return (*iter)->type != Attr_container ? (*iter)->attr : 0;
880}
881
882bool AttrTable::is_global_attribute(Attr_iter iter)
883{
884 assert(iter != attr_map.end());
885 if ((*iter)->type == Attr_container)
886 return (*iter)->attributes->is_global_attribute();
887 else
888 return (*iter)->is_global;
889}
890
891void AttrTable::set_is_global_attribute(Attr_iter iter, bool ga)
892{
893 assert(iter != attr_map.end());
894 if ((*iter)->type == Attr_container)
895 (*iter)->attributes->set_is_global_attribute(ga);
896 else
897 (*iter)->is_global = ga;
898}
899
901
902// Alias an attribute table. The alias should be added to this object.
908void AttrTable::add_container_alias(const string &name, AttrTable *src)
909{
910#if WWW_ENCODING
911 string lname = www2id(name);
912#else
913 string lname = remove_space_encoding(name);
914#endif
915
916 if (simple_find(lname) != attr_end())
917 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (2)"));
918
919 entry *e = new entry;
920 e->name = lname;
921 e->is_alias = true;
922 e->aliased_to = src->get_name();
923 e->type = Attr_container;
924
925 e->attributes = src;
926
927 attr_map.push_back(e);
928}
929
942void AttrTable::add_value_alias(AttrTable *das, const string &name, const string &source)
943{
944#if WWW_ENCODING
945 string lname = www2id(name);
946#else
947 string lname = remove_space_encoding(name);
948#endif
949
950#if WWW_ENCODING
951 string lsource = www2id(source);
952#else
953 string lsource = remove_space_encoding(source);
954#endif
955
956 // find the container that holds source and its (sources's) iterator
957 // within that container. Search at the uppermost level of the attribute
958 // object to find values defined `above' the current container.
959 AttrTable *at;
960 Attr_iter iter;
961 das->find(lsource, &at, &iter);
962
963 // If source is not found by looking at the topmost level, look in the
964 // current table (i.e., alias z x where x is in the current container
965 // won't be found by looking for `x' at the top level). See test case 26
966 // in das-testsuite.
967 if (!at || (iter == at->attr_end()) || !*iter) {
968 find(lsource, &at, &iter);
969 if (!at || (iter == at->attr_end()) || !*iter)
970 throw Error(string("Could not find the attribute `") + source + string("' in the attribute object."));
971 }
972
973 // If we've got a value to alias and it's being added at the top level of
974 // the DAS, that's an error.
975 if (at && !at->is_container(iter) && this == das)
976 throw Error(
977 string(
978 "A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS."));
979
980 if (simple_find(lname) != attr_end())
981 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (3)"));
982
983 entry *e = new entry;
984 e->name = lname;
985 e->is_alias = true;
986 e->aliased_to = lsource;
987 e->type = get_attr_type(iter);
988 if (at && e->type == Attr_container)
989 e->attributes = at->get_attr_table(iter);
990 else
991 e->attr = (*iter)->attr;
992
993 attr_map.push_back(e);
994}
995
996// Deprecated
1015bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name)
1016{
1017 add_value_alias(at, alias, name);
1018 return true;
1019}
1020
1028bool AttrTable::attr_alias(const string &alias, const string &name)
1029{
1030 return attr_alias(alias, this, name);
1031}
1032
1037{
1038 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1039 delete *i;
1040 *i = 0;
1041 }
1042
1043 attr_map.erase(attr_map.begin(), attr_map.end());
1044
1045 d_name = "";
1046}
1047
1048const string double_quote = "\"";
1049
1050// This is here as a result of the problem described in ticket #1163 where
1051// the data handlers are adding quotes to string attributes so the DAS will
1052// be printed correctly. But that has the affect of adding the quotes to the
1053// attribute's _value_ not just it's print representation. As part of the fix
1054// I made the code here add the quotes if the handlers are fixed (but not if
1055// handlers are still adding them). The other part of 1163 is to fix all of
1056// the handlers... What this fix means is that attributes whose values really
1057// do contain bracketing quotes might be misunderstood, since we're assuming
1058// those quotes were added by the handlers as a hack to get the output
1059// formatting correct for the DAS. jhrg 7/30/08
1060
1061static void write_string_attribute_for_das(ostream &out, const string &value, const string &term)
1062{
1063 if (is_quoted(value))
1064 out << value << term;
1065 else
1066 out << double_quote << value << double_quote << term;
1067}
1068
1069#if 0
1070static void
1071write_string_attribute_for_das(FILE *out, const string &value, const string &term)
1072{
1073 if (is_quoted(value))
1074 fprintf(out, "%s%s", value.c_str(), term.c_str());
1075 else
1076 fprintf(out, "\"%s\"%s", value.c_str(), term.c_str());
1077}
1078#endif
1079
1080// Special treatment for XML: Make sure to escape double quotes when XML is
1081// printed in a DAS.
1082static void write_xml_attribute_for_das(ostream &out, const string &value, const string &term)
1083{
1084 if (is_quoted(value))
1085 out << escape_double_quotes(value) << term;
1086 else
1087 out << double_quote << escape_double_quotes(value) << double_quote << term;
1088}
1089
1090#if 0
1091static void
1092write_xml_attribute_for_das(FILE *out, const string &value, const string &term)
1093{
1094 if (is_quoted(value))
1095 fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str());
1096 else
1097 fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str());
1098}
1099#endif
1100
1103void AttrTable::simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
1104{
1105 ostringstream oss;
1106 simple_print(oss, pad, i, dereference);
1107 fwrite(oss.str().data(), 1, oss.str().length(), out);
1108
1109#if 0
1110 switch ((*i)->type) {
1111 case Attr_container:
1112#if WWW_ENCODING
1113 fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str());
1114#else
1115 fprintf(out, "%s%s {\n", pad.c_str(), get_name(i).c_str());
1116#endif
1117 (*i)->attributes->print(out, pad + " ", dereference);
1118
1119 fprintf(out, "%s}\n", pad.c_str());
1120 break;
1121
1122 case Attr_string: {
1123#if WWW_ENCODING
1124 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1125#else
1126 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1127#endif
1128 vector<string> *sxp = (*i)->attr;
1129 vector<string>::iterator last = sxp->end() - 1;
1130 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1131 write_string_attribute_for_das(out, *i, ", ");
1132 }
1133 write_string_attribute_for_das(out, *last, ";\n");
1134 }
1135 break;
1136
1137 case Attr_other_xml: {
1138#if WWW_ENCODING
1139 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1140#else
1141 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1142#endif
1143 vector<string> *sxp = (*i)->attr;
1144 vector<string>::iterator last = sxp->end() - 1;
1145 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1146 write_xml_attribute_for_das(out, *i, ", ");
1147 }
1148 write_xml_attribute_for_das(out, *last, ";\n");
1149 }
1150 break;
1151
1152 default: {
1153#if WWW_ENCODING
1154 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1155#else
1156 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1157#endif
1158
1159 vector<string> *sxp = (*i)->attr;
1160 vector<string>::iterator last = sxp->end() - 1;
1161 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1162 fprintf(out, "%s%s", (*i).c_str(), ", ");
1163 }
1164 fprintf(out, "%s%s", (*last).c_str(), ";\n");
1165 }
1166 break;
1167 }
1168#endif
1169}
1170
1173void AttrTable::simple_print(ostream &out, string pad, Attr_iter i, bool dereference)
1174{
1175 switch ((*i)->type) {
1176 case Attr_container:
1177#if WWW_ENCODING
1178 out << pad << id2www(get_name(i)) << " {\n";
1179#else
1180 out << pad << add_space_encoding(get_name(i)) << " {\n";
1181#endif
1182 (*i)->attributes->print(out, pad + " ", dereference);
1183 out << pad << "}\n";
1184 break;
1185
1186 case Attr_string: {
1187#if WWW_ENCODING
1188 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1189#else
1190 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1191#endif
1192 vector<string> *sxp = (*i)->attr;
1193 vector<string>::iterator last = sxp->end() - 1;
1194 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1195 write_string_attribute_for_das(out, *i, ", ");
1196 }
1197 write_string_attribute_for_das(out, *last, ";\n");
1198 }
1199 break;
1200
1201 case Attr_other_xml: {
1202#if WWW_ENCODING
1203 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1204#else
1205 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1206#endif
1207 vector<string> *sxp = (*i)->attr;
1208 vector<string>::iterator last = sxp->end() - 1;
1209 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1210 write_xml_attribute_for_das(out, *i, ", ");
1211 }
1212 write_xml_attribute_for_das(out, *last, ";\n");
1213 }
1214 break;
1215
1216 default: {
1217#if WWW_ENCODING
1218 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1219#else
1220 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1221#endif
1222 vector<string> *sxp = (*i)->attr;
1223 vector<string>::iterator last = sxp->end() - 1;
1224 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1225 out << *i << ", ";
1226 }
1227 out << *last << ";\n";
1228 }
1229 break;
1230 }
1231}
1232
1243void AttrTable::print(FILE *out, string pad, bool dereference)
1244{
1245 ostringstream oss;
1246 print(oss, pad, dereference);
1247 fwrite(oss.str().data(), 1, oss.str().length(), out);
1248
1249#if 0
1250 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1251 if ((*i)->is_alias) {
1252 if (dereference) {
1253 simple_print(out, pad, i, dereference);
1254 }
1255 else {
1256#if WWW_ENCODING
1257 fprintf(out, "%sAlias %s %s;\n",
1258 pad.c_str(),
1259 id2www(get_name(i)).c_str(),
1260 id2www((*i)->aliased_to).c_str());
1261#else
1262 fprintf(out, "%sAlias %s %s;\n",
1263 pad.c_str(), add_space_encoding(get_name(i)).c_str(), add_space_encoding((*i)->aliased_to).c_str());
1264
1265#endif
1266 }
1267 }
1268 else {
1269 simple_print(out, pad, i, dereference);
1270 }
1271 }
1272#endif
1273}
1274
1285void AttrTable::print(ostream &out, string pad, bool dereference)
1286{
1287 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1288 if ((*i)->is_alias) {
1289 if (dereference) {
1290 simple_print(out, pad, i, dereference);
1291 }
1292 else {
1293#if WWW_ENCODING
1294 out << pad << "Alias " << id2www(get_name(i))
1295 << " " << id2www((*i)->aliased_to) << ";\n";
1296#else
1297 out << pad << "Alias " << add_space_encoding(get_name(i)) << " "
1298 << add_space_encoding((*i)->aliased_to) << ";\n";
1299#endif
1300 }
1301 }
1302 else {
1303 simple_print(out, pad, i, dereference);
1304 }
1305 }
1306}
1307
1313void AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/)
1314{
1315 XMLWriter xml(pad);
1316 print_xml_writer(xml);
1317 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1318
1319#if OLD_XML_MOETHODS
1320 ostringstream oss;
1321 print_xml(oss, pad);
1322 fwrite(oss.str().data(), 1, oss.str().length(), out);
1323#endif
1324
1325#if 0
1326 // Why this works: AttrTable is really a hacked class that used to
1327 // implement a single-level set of attributes. Containers
1328 // were added several years later by dropping in the 'entry' structure.
1329 // It's not a class in its own right; instead accessors from AttrTable
1330 // are used to access information from entry. So... the loop below
1331 // actually iterates over the entries of *this* (which is an instance of
1332 // AttrTable). A container is an entry whose sole value is an AttrTable
1333 // instance. 05/19/03 jhrg
1334 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1335 if ((*i)->is_alias) {
1336 fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n",
1337 pad.c_str(), id2xml(get_name(i)).c_str(),
1338 (*i)->aliased_to.c_str());
1339
1340 }
1341 else if (is_container(i)) {
1342 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1343 pad.c_str(), id2xml(get_name(i)).c_str(),
1344 get_type(i).c_str());
1345
1346 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1347
1348 fprintf(out, "%s</Attribute>\n", pad.c_str());
1349 }
1350 else {
1351 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1352 pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str());
1353
1354 string value_pad = pad + " ";
1355 // Special handling for the OtherXML attribute type - don't escape
1356 // the XML and don't include the <value> element. Note that there
1357 // cannot be an vector of XML things as can be with the other types.
1358 if (get_attr_type(i) == Attr_other_xml) {
1359 if (get_attr_num(i) != 1)
1360 throw Error("OtherXML attributes cannot be vector-valued.");
1361 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str());
1362 }
1363 else {
1364 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1365 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(),
1366 id2xml(get_attr(i, j)).c_str());
1367 }
1368 }
1369 fprintf(out, "%s</Attribute>\n", pad.c_str());
1370 }
1371 }
1372#endif
1373}
1374
1378void AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/)
1379{
1380 XMLWriter xml(pad);
1381 print_xml_writer(xml);
1382 out << xml.get_doc();
1383
1384#if 0
1385 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1386 if ((*i)->is_alias) {
1387 out << pad << "<Alias name=\"" << id2xml(get_name(i))
1388 << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n";
1389
1390 }
1391 else if (is_container(i)) {
1392 out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1393 << "\" type=\"" << get_type(i) << "\">\n";
1394
1395 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1396
1397 out << pad << "</Attribute>\n";
1398 }
1399 else {
1400 out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1401 << "\" type=\"" << get_type(i) << "\">\n";
1402
1403 string value_pad = pad + " ";
1404 if (get_attr_type(i) == Attr_other_xml) {
1405 if (get_attr_num(i) != 1)
1406 throw Error("OtherXML attributes cannot be vector-valued.");
1407 out << value_pad << get_attr(i, 0) << "\n";
1408 }
1409 else {
1410 string value_pad = pad + " ";
1411 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1412 out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n";
1413 }
1414 }
1415 out << pad << "</Attribute>\n";
1416 }
1417 }
1418#endif
1419}
1420
1426{
1427 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1428 if ((*i)->is_alias) {
1429 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Alias") < 0)
1430 throw InternalErr(__FILE__, __LINE__, "Could not write Alias element");
1431 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1432 (const xmlChar*) get_name(i).c_str()) < 0)
1433 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1434 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "Attribute",
1435 (const xmlChar*) (*i)->aliased_to.c_str()) < 0)
1436 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1437 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1438 throw InternalErr(__FILE__, __LINE__, "Could not end Alias element");
1439 }
1440 else if (is_container(i)) {
1441 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
1442 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1443 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1444 (const xmlChar*) get_name(i).c_str()) < 0)
1445 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1446 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
1447 (const xmlChar*) get_type(i).c_str()) < 0)
1448 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1449
1451
1452 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1453 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1454 }
1455 else {
1456 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
1457 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1458 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1459 (const xmlChar*) get_name(i).c_str()) < 0)
1460 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1461 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
1462 (const xmlChar*) get_type(i).c_str()) < 0)
1463 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1464
1465 if (get_attr_type(i) == Attr_other_xml) {
1466 if (get_attr_num(i) != 1)
1467 throw Error("OtherXML attributes cannot be vector-valued.");
1468 // Replaced xmltextWriterWriteString with xmlTextWriterWriteRaw to keep the
1469 // libxml2 code from escaping the xml (which was breaking all of the inferencing
1470 // code. jhrg
1471 if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) get_attr(i, 0).c_str()) < 0)
1472 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
1473 }
1474 else {
1475 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1476 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "value") < 0)
1477 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
1478
1479 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) get_attr(i, j).c_str()) < 0)
1480 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
1481
1482 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1483 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
1484 }
1485 }
1486 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1487 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1488 }
1489 }
1490}
1491
1497void
1499{
1500 print_xml_writer(xml);
1501}
1502
1510void AttrTable::dump(ostream &strm) const
1511{
1512 strm << DapIndent::LMarg << "AttrTable::dump - (" << (void *) this << ")" << endl;
1513 DapIndent::Indent();
1514 strm << DapIndent::LMarg << "table name: " << d_name << endl;
1515 if (attr_map.size()) {
1516 strm << DapIndent::LMarg << "attributes: " << endl;
1517 DapIndent::Indent();
1518 Attr_citer i = attr_map.begin();
1519 Attr_citer ie = attr_map.end();
1520 for (; i != ie; ++i) {
1521 entry *e = (*i);
1522 string type = AttrType_to_String(e->type);
1523 if (e->is_alias) {
1524 strm << DapIndent::LMarg << "alias: " << e->name << " aliased to: " << e->aliased_to << endl;
1525 }
1526 else if (e->type == Attr_container) {
1527 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1528 DapIndent::Indent();
1529 e->attributes->dump(strm);
1530 DapIndent::UnIndent();
1531 }
1532 else {
1533 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1534 DapIndent::Indent();
1535 strm << DapIndent::LMarg;
1536 vector<string>::const_iterator iter = e->attr->begin();
1537 vector<string>::const_iterator last = e->attr->end() - 1;
1538 for (; iter != last; ++iter) {
1539 strm << (*iter) << ", ";
1540 }
1541 strm << (*(e->attr->end() - 1)) << endl;
1542 DapIndent::UnIndent();
1543 }
1544 }
1545 DapIndent::UnIndent();
1546 }
1547 else {
1548 strm << DapIndent::LMarg << "attributes: empty" << endl;
1549 }
1550 if (d_parent) {
1551 strm << DapIndent::LMarg << "parent table:" << d_name << ":" << (void *) d_parent << endl;
1552 }
1553 else {
1554 strm << DapIndent::LMarg << "parent table: none" << d_name << endl;
1555 }
1556 DapIndent::UnIndent();
1557}
1558
1559} // namespace libdap
1560
Contains the attributes for a dataset.
Definition: AttrTable.h:143
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
void simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
Definition: AttrTable.cc:1103
virtual unsigned int get_attr_num(const string &name)
Get the number of attributes in this container.
Definition: AttrTable.cc:634
virtual bool attr_alias(const string &alias, AttrTable *at, const string &name)
Adds an alias to the set of attributes.
Definition: AttrTable.cc:1015
virtual bool is_container(Attr_iter iter)
Definition: AttrTable.cc:746
virtual void find(const string &target, AttrTable **at, Attr_iter *iter)
Definition: AttrTable.cc:481
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:245
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:607
void clone(const AttrTable &at)
Definition: AttrTable.cc:160
virtual Attr_iter attr_end()
Definition: AttrTable.cc:719
virtual void print_xml(FILE *out, string pad=" ", bool constrained=false)
Definition: AttrTable.cc:1313
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition: AttrTable.cc:613
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:653
virtual void add_value_alias(AttrTable *at, const string &name, const string &source)
Add an alias for an attribute.
Definition: AttrTable.cc:942
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:307
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:711
virtual Attr_iter get_attr_iter(int i)
Definition: AttrTable.cc:732
void print_dap4(XMLWriter &xml)
Definition: AttrTable.cc:1498
virtual void del_attr(const string &name, int i=-1)
Deletes an attribute.
Definition: AttrTable.cc:675
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:238
virtual void erase()
Erase the attribute table.
Definition: AttrTable.cc:1036
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1425
virtual Attr_iter del_attr_table(Attr_iter iter)
Definition: AttrTable.cc:781
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1243
virtual void add_container_alias(const string &name, AttrTable *src)
Add an alias to a container held by this attribute table.
Definition: AttrTable.cc:908
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition: AttrTable.cc:231
virtual void dump(ostream &strm) const
dumps information about this object
Definition: AttrTable.cc:1510
virtual AttrTable * find_container(const string &target)
Find an attribute with a given name.
Definition: AttrTable.cc:566
Attr_iter simple_find(const string &target)
Definition: AttrTable.cc:541
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:621
virtual AttrTable * recurrsive_find(const string &target, Attr_iter *location)
Definition: AttrTable.cc:513
libdap base object for common functionality of libdap objects
Definition: DapObj.h:51
A class for error processing.
Definition: Error.h:94
A class for software fault reporting.
Definition: InternalErr.h:65
top level DAP object to house generic methods
Definition: AlarmHandler.h:36
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
string id2xml(string in, const string &not_allowed)
Definition: escaping.cc:272
string add_space_encoding(const string &s)
Definition: AttrTable.cc:78
void downcase(string &s)
Definition: util.cc:566
string AttrType_to_String(const AttrType at)
Definition: AttrTable.cc:97
string escape_double_quotes(string source)
Definition: escaping.cc:470
string remove_space_encoding(const string &s)
Definition: AttrTable.cc:61
AttrType
Definition: AttrTable.h:81
bool is_quoted(const string &s)
Definition: util.cc:577
string id2www(string in, const string &allowable)
Definition: escaping.cc:153