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