libdap  Updated for version 3.20.6
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 
53 using std::cerr;
54 using std::string;
55 using std::endl;
56 using std::vector;
57 
58 namespace libdap {
59 
61 string 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 
78 string 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 
97 string AttrType_to_String(const AttrType at)
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 
127 AttrType 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 
189 AttrTable::AttrTable() :
190  DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true)
191 {
192 }
193 
194 AttrTable::AttrTable(const AttrTable &rhs) :
195  DapObj()
196 {
197  clone(rhs);
198 }
199 
200 // Private
201 void 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 
209 AttrTable::~AttrTable()
210 {
211  delete_attr_table();
212 }
213 
214 AttrTable &
215 AttrTable::operator=(const AttrTable &rhs)
216 {
217  if (this != &rhs) {
218  delete_attr_table();
219  clone(rhs);
220  }
221 
222  return *this;
223 }
225 
231 unsigned int AttrTable::get_size() const
232 {
233  return attr_map.size();
234 }
235 
238 string AttrTable::get_name() const
239 {
240  return d_name;
241 }
242 
245 void 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)
258 static 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 
307 unsigned 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 
362 unsigned 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 
409 AttrTable *
410 AttrTable::append_container(const string &name)
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 
439 AttrTable *
440 AttrTable::append_container(AttrTable *at, const string &name)
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 
481 void 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 
512 AttrTable *
513 AttrTable::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]
541 AttrTable::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 
565 AttrTable *
566 AttrTable::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]
582 AttrTable *
583 AttrTable::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 
606 AttrTable *
607 AttrTable::get_attr_table(const string &name)
608 {
609  return find_container(name);
610 }
611 
613 string 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 
634 unsigned 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 
652 vector<string> *
653 AttrTable::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 
675 void 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 
711 AttrTable::Attr_iter AttrTable::attr_begin()
712 {
713  return attr_map.begin();
714 }
715 
719 AttrTable::Attr_iter AttrTable::attr_end()
720 {
721  return attr_map.end();
722 }
723 
732 AttrTable::Attr_iter AttrTable::get_attr_iter(int i)
733 {
734  return attr_map.begin() + i;
735 }
736 
738 string AttrTable::get_name(Attr_iter iter)
739 {
740  assert(iter != attr_map.end());
741 
742  return (*iter)->name;
743 }
744 
746 bool AttrTable::is_container(Attr_iter i)
747 {
748  return (*i)->type == Attr_container;
749 }
750 
756 AttrTable *
758 {
759  assert(iter != attr_map.end());
760  return (*iter)->type == Attr_container ? (*iter)->attributes : 0;
761 }
762 
781 AttrTable::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 
808 string 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 
829 unsigned 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 
851 string 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 
858 string 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 
875 vector<string> *
877 {
878  assert(iter != attr_map.end());
879  return (*iter)->type != Attr_container ? (*iter)->attr : 0;
880 }
881 
882 bool 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 
891 void 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.
908 void 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 
942 void 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
1015 bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name)
1016 {
1017  add_value_alias(at, alias, name);
1018  return true;
1019 }
1020 
1028 bool 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 
1048 const 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 
1061 static 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
1070 static void
1071 write_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.
1082 static 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
1091 static void
1092 write_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 
1103 void 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 
1173 void 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 
1243 void 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 
1285 void 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 
1313 void 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 
1378 void 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 
1497 void
1499 {
1500  print_xml_writer(xml);
1501 }
1502 
1510 void 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 
virtual Attr_iter attr_end()
Definition: AttrTable.cc:719
void downcase(string &s)
Definition: util.cc:563
Contains the attributes for a dataset.
Definition: AttrTable.h:142
string AttrType_to_String(const AttrType at)
Definition: AttrTable.cc:97
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition: AttrTable.cc:613
string add_space_encoding(const string &s)
Definition: AttrTable.cc:78
void clone(const AttrTable &at)
Definition: AttrTable.cc:160
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:238
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 void print_xml(FILE *out, string pad=" ", bool constrained=false)
Definition: AttrTable.cc:1313
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:675
string escape_double_quotes(string source)
Definition: escaping.cc:470
virtual AttrTable * recurrsive_find(const string &target, Attr_iter *location)
Definition: AttrTable.cc:513
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1425
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1243
string remove_space_encoding(const string &s)
Definition: AttrTable.cc:61
virtual AttrTable * find_container(const string &target)
Find an attribute with a given name.
Definition: AttrTable.cc:566
top level DAP object to house generic methods
Definition: AISConnect.cc:30
void print_dap4(XMLWriter &xml)
Definition: AttrTable.cc:1498
A class for software fault reporting.
Definition: InternalErr.h:64
virtual Attr_iter get_attr_iter(int i)
Definition: AttrTable.cc:732
virtual void add_value_alias(AttrTable *at, const string &name, const string &source)
Add an alias for an attribute.
Definition: AttrTable.cc:942
virtual bool is_container(Attr_iter iter)
Definition: AttrTable.cc:746
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:607
virtual void erase()
Erase the attribute table.
Definition: AttrTable.cc:1036
bool is_quoted(const string &s)
Definition: util.cc:574
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 Attr_iter attr_begin()
Definition: AttrTable.cc:711
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:634
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:307
libdap base object for common functionality of libdap objects
Definition: DapObj.h:50
void simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
Definition: AttrTable.cc:1103
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:621
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:653
A class for error processing.
Definition: Error.h:92
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition: AttrTable.cc:231
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:245
virtual void dump(ostream &strm) const
dumps information about this object
Definition: AttrTable.cc:1510
virtual Attr_iter del_attr_table(Attr_iter iter)
Definition: AttrTable.cc:781
virtual void find(const string &target, AttrTable **at, Attr_iter *iter)
Definition: AttrTable.cc:481
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:541