libdap++  Updated for version 3.12.0
AttrTable.cc
Go to the documentation of this file.
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 //#define DODS_DEBUG
36 
37 static char rcsid[]not_used =
38 "$Id: AttrTable.cc 27197 2013-10-01 21:29:54Z jimg $";
39 
40 #include <cassert>
41 #include <sstream>
42 
43 #include "AttrTable.h"
44 
45 #include "util.h"
46 #include "escaping.h"
47 
48 #include "debug.h"
49 
50 // Should the www2id and id2www functions be used to encode attribute names?
51 // Probably not... jhrg 11/16/11
52 #define WWW_ENCODING 0
53 
54 using std::cerr;
55 using std::string;
56 using std::endl;
57 using std::vector;
58 
59 namespace libdap {
60 
62 static string remove_space_encoding(const string &s)
63 {
64  string::size_type pos = s.find("%20");
65  if (pos != string::npos) {
66  string n = s;
67  do {
68  n.replace(pos, 3, " ");
69  pos = n.find("%20");
70  } while (pos != string::npos);
71  return n;
72  }
73  else {
74  return s;
75  }
76 }
77 
79 static string add_space_encoding(const string &s)
80 {
81  string::size_type pos = s.find(" ");
82  if (pos != string::npos) {
83  string n = s;
84  do {
85  n.replace(pos, 1, "%20");
86  pos = n.find(" ");
87  } while (pos != string::npos);
88  return n;
89  }
90  else {
91  return s;
92  }
93 }
94 
98 string AttrType_to_String(const AttrType at)
99 {
100  switch (at) {
101  case Attr_container:
102  return "Container";
103  case Attr_byte:
104  return "Byte";
105  case Attr_int16:
106  return "Int16";
107  case Attr_uint16:
108  return "UInt16";
109  case Attr_int32:
110  return "Int32";
111  case Attr_uint32:
112  return "UInt32";
113  case Attr_float32:
114  return "Float32";
115  case Attr_float64:
116  return "Float64";
117  case Attr_string:
118  return "String";
119  case Attr_url:
120  return "Url";
121  case Attr_other_xml:
122  return "OtherXML";
123  default:
124  return "";
125  }
126 }
127 
128 AttrType String_to_AttrType(const string &s)
129 {
130  string s2 = s;
131  downcase(s2);
132 
133  if (s2 == "container")
134  return Attr_container;
135  else if (s2 == "byte")
136  return Attr_byte;
137  else if (s2 == "int16")
138  return Attr_int16;
139  else if (s2 == "uint16")
140  return Attr_uint16;
141  else if (s2 == "int32")
142  return Attr_int32;
143  else if (s2 == "uint32")
144  return Attr_uint32;
145  else if (s2 == "float32")
146  return Attr_float32;
147  else if (s2 == "float64")
148  return Attr_float64;
149  else if (s2 == "string")
150  return Attr_string;
151  else if (s2 == "url")
152  return Attr_url;
153  else if (s2 == "otherxml")
154  return Attr_other_xml;
155  else
156  return Attr_unknown;
157 }
158 
162 {
163  d_name = at.d_name;
164  d_is_global_attribute = at.d_is_global_attribute;
165 
166  // Set the parent to null (no parent, not in container)
167  // since using at.d_parent is semantically incorrect
168  // and potentially dangerous.
169  d_parent = 0;
170 
171  Attr_citer i = at.attr_map.begin();
172  Attr_citer ie = at.attr_map.end();
173  for (; i != ie; ++i) {
174  // this deep-copies containers recursively
175  entry *e = new entry(*(*i));
176  attr_map.push_back(e);
177 
178  // If the entry being added was a container,
179  // set its parent to this to maintain invariant.
180  if (e->type == Attr_container) {
181  assert(e->attributes);
182  e->attributes->d_parent = this;
183  }
184  }
185 }
186 
191  DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true)
192 {
193 }
194 
196  DapObj()
197 {
198  clone(rhs);
199 }
200 
201 // Private
202 void AttrTable::delete_attr_table()
203 {
204  for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
205  delete *i;
206  *i = 0;
207  }
208  attr_map.clear();
209 }
210 
212 {
213  DBG(cerr << "Entering ~AttrTable (" << this << ")" << endl);
214  delete_attr_table();
215  DBG(cerr << "Exiting ~AttrTable" << endl);
216 }
217 
218 AttrTable &
220 {
221  if (this != &rhs) {
222  delete_attr_table();
223  clone(rhs);
224  }
225 
226  return *this;
227 }
229 
235 unsigned int AttrTable::get_size() const
236 {
237  return attr_map.size();
238 }
239 
242 string AttrTable::get_name() const
243 {
244  return d_name;
245 }
246 
249 void AttrTable::set_name(const string &n)
250 {
251 #if WWW_ENCODING
252  d_name = www2id(n);
253 #else
254  d_name = remove_space_encoding(n);
255 #endif
256 }
257 
258 #if 0
259 // This was taken from das.y and could be used here to make the 'dods_errors'
260 // attribute container like the parser used to. Then again, maybe this feature
261 // was just BS. jhrg (ticket 1469)
262 static void add_bad_attribute(AttrTable *attr, const string &type, const string &name, const string &value,
263  const string &msg) {
264  // First, if this bad value is already in a *_dods_errors container,
265  // then just add it. This can happen when the server side processes a DAS
266  // and then hands it off to a client which does the same.
267  // Make a new container. Call it <attr's name>_errors. If that container
268  // already exists, use it.
269  // Add the attribute.
270  // Add the error string to an attribute in the container called
271  // `<name_explanation.'.
272 
273  if (attr->get_name().find("_dods_errors") != string::npos) {
274  attr->append_attr(name, type, value);
275  }
276  else {
277  // I think _dods_errors should be _dap_error. jhrg 11/16/11
278  string error_cont_name = attr->get_name() + "_dods_errors";
279  AttrTable *error_cont = attr->get_attr_table(error_cont_name);
280  if (!error_cont)
281  error_cont = attr->append_container(error_cont_name);
282 
283  error_cont->append_attr(name, type, value);
284 
285 #ifndef ATTR_STRING_QUOTE_FIX
286  error_cont->append_attr(name + "_dap_explanation", "String", "\"" + msg + "\"");
287 #else
288  error_cont->append_attr(name + "_dap_explanation", "String", msg);
289 #endif
290  }
291 }
292 #endif
293 
311 unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value)
312 {
313  DBG(cerr << "Entering AttrTable::append_attr" << endl);
314 #if WWW_ENCODING
315  string lname = www2id(name);
316 #else
317  string lname = remove_space_encoding(name);
318 #endif
319 
320  Attr_iter iter = simple_find(lname);
321 
322  // If the types don't match OR this attribute is a container, calling
323  // this mfunc is an error!
324  if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
325  throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
326  if (iter != attr_map.end() && (get_type(iter) == "Container"))
327  throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
328 
329  if (iter != attr_map.end()) { // Must be a new attribute value; add it.
330  (*iter)->attr->push_back(value);
331  return (*iter)->attr->size();
332  }
333  else { // Must be a completely new attribute; add it
334  entry *e = new entry;
335 
336  e->name = lname;
337  e->is_alias = false;
338  e->type = String_to_AttrType(type); // Record type using standard names.
339  e->attr = new vector<string> ;
340  e->attr->push_back(value);
341 
342  attr_map.push_back(e);
343 
344  return e->attr->size(); // return the length of the attr vector
345  }
346 }
347 
366 unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values)
367 {
368  DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
369 #if WWW_ENCODING
370  string lname = www2id(name);
371 #else
372  string lname = remove_space_encoding(name);
373 #endif
374  Attr_iter iter = simple_find(lname);
375 
376  // If the types don't match OR this attribute is a container, calling
377  // this mfunc is an error!
378  if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
379  throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
380  if (iter != attr_map.end() && (get_type(iter) == "Container"))
381  throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
382 
383  if (iter != attr_map.end()) { // Must be new attribute values; add.
384  vector<string>::iterator i = values->begin();
385  while (i != values->end())
386  (*iter)->attr->push_back(*i++);
387 
388  return (*iter)->attr->size();
389  }
390  else { // Must be a completely new attribute; add it
391  entry *e = new entry;
392 
393  e->name = lname;
394  e->is_alias = false;
395  e->type = String_to_AttrType(type); // Record type using standard names.
396  e->attr = new vector<string> (*values);
397 
398  attr_map.push_back(e);
399 
400  return e->attr->size(); // return the length of the attr vector
401  }
402 }
403 
413 AttrTable *
414 AttrTable::append_container(const string &name)
415 {
416  AttrTable *new_at = new AttrTable;
417  AttrTable *ret = NULL;
418  try {
419  ret = append_container(new_at, name);
420  } catch (Error &e) {
421  // an error occurred, attribute with that name already exists
422  delete new_at;
423  new_at = 0;
424  throw;
425  }
426  return ret;
427 }
428 
443 AttrTable *
444 AttrTable::append_container(AttrTable *at, const string &name)
445 {
446 #if WWW_ENCODING
447  string lname = www2id(name);
448 #else
449  string lname = remove_space_encoding(name);
450 #endif
451 
452  if (simple_find(name) != attr_end())
453  throw Error(
454  string("There already exists a container called `") + name + string("' in this attribute table. (1)"));
455  DBG(cerr << "Setting appended attribute container name to: "
456  << lname << endl);
457  at->set_name(lname);
458 
459  entry *e = new entry;
460  e->name = lname;
461  e->is_alias = false;
462  e->type = Attr_container;
463  e->attributes = at;
464 
465  attr_map.push_back(e);
466 
467  at->d_parent = this;
468 
469  return e->attributes;
470 }
471 
486 void AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter)
487 {
488  string::size_type dotpos = target.rfind('.');
489  if (dotpos != string::npos) {
490  string container = target.substr(0, dotpos);
491  string field = target.substr(dotpos + 1);
492 
493  *at = find_container(container);
494  if (*at) {
495  *iter = (*at)->simple_find(field);
496  }
497  else {
498  *iter = attr_map.end();
499  }
500  }
501  else {
502  *at = recurrsive_find(target, iter);
503  }
504 }
505 
517 AttrTable *
518 AttrTable::recurrsive_find(const string &target, Attr_iter *location)
519 {
520  Attr_iter i = attr_begin();
521  while (i != attr_end()) {
522  if (target == (*i)->name) {
523  *location = i;
524  return this;
525  }
526  else if ((*i)->type == Attr_container) {
527  AttrTable *at = (*i)->attributes->recurrsive_find(target, location);
528  if (at)
529  return at;
530  }
531 
532  ++i;
533  }
534 
535  *location = i;
536  return 0;
537 }
538 
539 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
547 {
548  Attr_iter i;
549  for (i = attr_map.begin(); i != attr_map.end(); ++i) {
550  if (target == (*i)->name) {
551  break;
552  }
553  }
554  return i;
555 }
556 
570 AttrTable *
571 AttrTable::find_container(const string &target)
572 {
573  string::size_type dotpos = target.find('.');
574  if (dotpos != string::npos) {
575  string container = target.substr(0, dotpos);
576  string field = target.substr(dotpos + 1);
577 
578  AttrTable *at = simple_find_container(container);
579  return (at) ? at->find_container(field) : 0;
580  }
581  else {
582  return simple_find_container(target);
583  }
584 }
585 
586 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
587 AttrTable *
588 AttrTable::simple_find_container(const string &target)
589 {
590  if (get_name() == target)
591  return this;
592 
593  for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
594  if (is_container(i) && target == (*i)->name) {
595  return (*i)->attributes;
596  }
597  }
598 
599  return 0;
600 }
601 
609 
611 AttrTable *
612 AttrTable::get_attr_table(const string &name)
613 {
614  return find_container(name);
615 }
616 
618 string AttrTable::get_type(const string &name)
619 {
620  Attr_iter p = simple_find(name);
621  return (p != attr_map.end()) ? get_type(p) : (string) "";
622 }
623 
627 {
628  Attr_iter p = simple_find(name);
629  return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown;
630 }
631 
639 unsigned int AttrTable::get_attr_num(const string &name)
640 {
641  Attr_iter iter = simple_find(name);
642  return (iter != attr_map.end()) ? get_attr_num(iter) : 0;
643 }
644 
657 vector<string> *
658 AttrTable::get_attr_vector(const string &name)
659 {
660  Attr_iter p = simple_find(name);
661  return (p != attr_map.end()) ? get_attr_vector(p) : 0;
662 }
663 
680 void AttrTable::del_attr(const string &name, int i)
681 {
682 #if WWW_ENCODING
683  string lname = www2id(name);
684 #else
685  string lname = remove_space_encoding(name);
686 #endif
687 
688  Attr_iter iter = simple_find(lname);
689  if (iter != attr_map.end()) {
690  if (i == -1) { // Delete the whole attribute
691  entry *e = *iter;
692  attr_map.erase(iter);
693  delete e;
694  e = 0;
695  }
696  else { // Delete one element from attribute array
697  // Don't try to delete elements from the vector of values if the
698  // map is a container!
699  if ((*iter)->type == Attr_container)
700  return;
701 
702  vector<string> *sxp = (*iter)->attr;
703 
704  assert(i >= 0 && i < (int) sxp->size());
705  sxp->erase(sxp->begin() + i); // rm the element
706  }
707  }
708 }
709 
711 
717 {
718  return attr_map.begin();
719 }
720 
725 {
726  return attr_map.end();
727 }
728 
738 {
739  return attr_map.begin() + i;
740 }
741 
744 {
745  assert(iter != attr_map.end());
746 
747  return (*iter)->name;
748 }
749 
752 {
753  return (*i)->type == Attr_container;
754 }
755 
761 AttrTable *
763 {
764  assert(iter != attr_map.end());
765  return (*iter)->type == Attr_container ? (*iter)->attributes : 0;
766 }
767 
777 {
778  if ((*iter)->type != Attr_container)
779  return ++iter;
780 
781  // the caller intends to delete/reuse the contained AttrTable,
782  // so zero it out so it doesn't get deleted before we delete the entry
783  // [mjohnson]
784  struct entry* e = *iter;
785  // container no longer has a parent.
786  if (e->attributes) {
787  e->attributes->d_parent = 0;
788  }
789  e->attributes = 0;
790  delete e;
791 
792  return attr_map.erase(iter);
793 }
794 
799 {
800  assert(iter != attr_map.end());
801  return AttrType_to_String((*iter)->type);
802 }
803 
808 {
809  return (*iter)->type;
810 }
811 
820 {
821  assert(iter != attr_map.end());
822  return ((*iter)->type == Attr_container) ? (*iter)->attributes->get_size() : (*iter)->attr->size();
823 }
824 
841 string AttrTable::get_attr(Attr_iter iter, unsigned int i)
842 {
843  assert(iter != attr_map.end());
844 
845  return (*iter)->type == Attr_container ? (string) "None" : (*(*iter)->attr)[i];
846 }
847 
848 string AttrTable::get_attr(const string &name, unsigned int i)
849 {
850  Attr_iter p = simple_find(name);
851  return (p != attr_map.end()) ? get_attr(p, i) : (string) "";
852 }
853 
865 vector<string> *
867 {
868  assert(iter != attr_map.end());
869  return (*iter)->type != Attr_container ? (*iter)->attr : 0;
870 }
871 
873 {
874  assert(iter != attr_map.end());
875  if ((*iter)->type == Attr_container)
876  return (*iter)->attributes->is_global_attribute();
877  else
878  return (*iter)->is_global;
879 }
880 
882 {
883  assert(iter != attr_map.end());
884  if ((*iter)->type == Attr_container)
885  (*iter)->attributes->set_is_global_attribute(ga);
886  else
887  (*iter)->is_global = ga;
888 }
889 
891 
892 // Alias an attribute table. The alias should be added to this object.
898 void AttrTable::add_container_alias(const string &name, AttrTable *src)
899 {
900 #if WWW_ENCODING
901  string lname = www2id(name);
902 #else
903  string lname = remove_space_encoding(name);
904 #endif
905 
906  if (simple_find(lname) != attr_end())
907  throw Error(string("There already exists a container called `") + name + string("in this attribute table. (2)"));
908 
909  entry *e = new entry;
910  e->name = lname;
911  e->is_alias = true;
912  e->aliased_to = src->get_name();
913  e->type = Attr_container;
914 
915  e->attributes = src;
916 
917  attr_map.push_back(e);
918 }
919 
932 void AttrTable::add_value_alias(AttrTable *das, const string &name, const string &source)
933 {
934 #if WWW_ENCODING
935  string lname = www2id(name);
936 #else
937  string lname = remove_space_encoding(name);
938 #endif
939 
940 #if WWW_ENCODING
941  string lsource = www2id(source);
942 #else
943  string lsource = remove_space_encoding(source);
944 #endif
945 
946  // find the container that holds source and its (sources's) iterator
947  // within that container. Search at the uppermost level of the attribute
948  // object to find values defined `above' the current container.
949  AttrTable *at;
950  Attr_iter iter;
951  das->find(lsource, &at, &iter);
952 
953  // If source is not found by looking at the topmost level, look in the
954  // current table (i.e., alias z x where x is in the current container
955  // won't be found by looking for `x' at the top level). See test case 26
956  // in das-testsuite.
957  if (!at || (iter == at->attr_end()) || !*iter) {
958  find(lsource, &at, &iter);
959  if (!at || (iter == at->attr_end()) || !*iter)
960  throw Error(string("Could not find the attribute `") + source + string("' in the attribute object."));
961  }
962 
963  // If we've got a value to alias and it's being added at the top level of
964  // the DAS, that's an error.
965  if (at && !at->is_container(iter) && this == das)
966  throw Error(
967  string(
968  "A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS."));
969 
970  if (simple_find(lname) != attr_end())
971  throw Error(string("There already exists a container called `") + name + string("in this attribute table. (3)"));
972 
973  entry *e = new entry;
974  e->name = lname;
975  e->is_alias = true;
976  e->aliased_to = lsource;
977  e->type = get_attr_type(iter);
978  if (at && e->type == Attr_container)
979  e->attributes = at->get_attr_table(iter);
980  else
981  e->attr = (*iter)->attr;
982 
983  attr_map.push_back(e);
984 }
985 
986 // Deprecated
1005 bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name)
1006 {
1007  add_value_alias(at, alias, name);
1008  return true;
1009 }
1010 
1018 bool AttrTable::attr_alias(const string &alias, const string &name)
1019 {
1020  return attr_alias(alias, this, name);
1021 }
1022 
1027 {
1028  for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1029  delete *i;
1030  *i = 0;
1031  }
1032 
1033  attr_map.erase(attr_map.begin(), attr_map.end());
1034 
1035  d_name = "";
1036 }
1037 
1038 const string double_quote = "\"";
1039 
1040 // This is here as a result of the problem described in ticket #1163 where
1041 // the data handlers are adding quotes to string attributes so the DAS will
1042 // be printed correctly. But that has the affect of adding the quotes to the
1043 // attribute's _value_ not just it's print representation. As part of the fix
1044 // I made the code here add the quotes if the handlers are fixed (but not if
1045 // handlers are still adding them). The other part of 1163 is to fix all of
1046 // the handlers... What this fix means is that attributes whose values really
1047 // do contain bracketing quotes might be misunderstood, since we're assuming
1048 // those quotes were added by the handlers as a hack to get the output
1049 // formatting correct for the DAS. jhrg 7/30/08
1050 
1051 static void write_string_attribute_for_das(ostream &out, const string &value, const string &term)
1052 {
1053  if (is_quoted(value))
1054  out << value << term;
1055  else
1056  out << double_quote << value << double_quote << term;
1057 }
1058 
1059 #if 0
1060 static void
1061 write_string_attribute_for_das(FILE *out, const string &value, const string &term)
1062 {
1063  if (is_quoted(value))
1064  fprintf(out, "%s%s", value.c_str(), term.c_str());
1065  else
1066  fprintf(out, "\"%s\"%s", value.c_str(), term.c_str());
1067 }
1068 #endif
1069 
1070 // Special treatment for XML: Make sure to escape double quotes when XML is
1071 // printed in a DAS.
1072 static void write_xml_attribute_for_das(ostream &out, const string &value, const string &term)
1073 {
1074  if (is_quoted(value))
1075  out << escape_double_quotes(value) << term;
1076  else
1077  out << double_quote << escape_double_quotes(value) << double_quote << term;
1078 }
1079 
1080 #if 0
1081 static void
1082 write_xml_attribute_for_das(FILE *out, const string &value, const string &term)
1083 {
1084  if (is_quoted(value))
1085  fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str());
1086  else
1087  fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str());
1088 }
1089 #endif
1090 
1093 void AttrTable::simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
1094 {
1095  ostringstream oss;
1096  simple_print(oss, pad, i, dereference);
1097  fwrite(oss.str().data(), 1, oss.str().length(), out);
1098 
1099 #if 0
1100  switch ((*i)->type) {
1101  case Attr_container:
1102 #if WWW_ENCODING
1103  fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str());
1104 #else
1105  fprintf(out, "%s%s {\n", pad.c_str(), get_name(i).c_str());
1106 #endif
1107  (*i)->attributes->print(out, pad + " ", dereference);
1108 
1109  fprintf(out, "%s}\n", pad.c_str());
1110  break;
1111 
1112  case Attr_string: {
1113 #if WWW_ENCODING
1114  fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1115 #else
1116  fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1117 #endif
1118  vector<string> *sxp = (*i)->attr;
1119  vector<string>::iterator last = sxp->end() - 1;
1120  for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1121  write_string_attribute_for_das(out, *i, ", ");
1122  }
1123  write_string_attribute_for_das(out, *last, ";\n");
1124  }
1125  break;
1126 
1127  case Attr_other_xml: {
1128 #if WWW_ENCODING
1129  fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1130 #else
1131  fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1132 #endif
1133  vector<string> *sxp = (*i)->attr;
1134  vector<string>::iterator last = sxp->end() - 1;
1135  for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1136  write_xml_attribute_for_das(out, *i, ", ");
1137  }
1138  write_xml_attribute_for_das(out, *last, ";\n");
1139  }
1140  break;
1141 
1142  default: {
1143 #if WWW_ENCODING
1144  fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1145 #else
1146  fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1147 #endif
1148 
1149  vector<string> *sxp = (*i)->attr;
1150  vector<string>::iterator last = sxp->end() - 1;
1151  for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1152  fprintf(out, "%s%s", (*i).c_str(), ", ");
1153  }
1154  fprintf(out, "%s%s", (*last).c_str(), ";\n");
1155  }
1156  break;
1157  }
1158 #endif
1159 }
1160 
1163 void AttrTable::simple_print(ostream &out, string pad, Attr_iter i, bool dereference)
1164 {
1165  switch ((*i)->type) {
1166  case Attr_container:
1167 #if WWW_ENCODING
1168  out << pad << id2www(get_name(i)) << " {\n";
1169 #else
1170  out << pad << add_space_encoding(get_name(i)) << " {\n";
1171 #endif
1172  (*i)->attributes->print(out, pad + " ", dereference);
1173  out << pad << "}\n";
1174  break;
1175 
1176  case Attr_string: {
1177 #if WWW_ENCODING
1178  out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1179 #else
1180  out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1181 #endif
1182  vector<string> *sxp = (*i)->attr;
1183  vector<string>::iterator last = sxp->end() - 1;
1184  for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1185  write_string_attribute_for_das(out, *i, ", ");
1186  }
1187  write_string_attribute_for_das(out, *last, ";\n");
1188  }
1189  break;
1190 
1191  case Attr_other_xml: {
1192 #if WWW_ENCODING
1193  out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1194 #else
1195  out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1196 #endif
1197  vector<string> *sxp = (*i)->attr;
1198  vector<string>::iterator last = sxp->end() - 1;
1199  for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1200  write_xml_attribute_for_das(out, *i, ", ");
1201  }
1202  write_xml_attribute_for_das(out, *last, ";\n");
1203  }
1204  break;
1205 
1206  default: {
1207 #if WWW_ENCODING
1208  out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1209 #else
1210  out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1211 #endif
1212  vector<string> *sxp = (*i)->attr;
1213  vector<string>::iterator last = sxp->end() - 1;
1214  for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1215  out << *i << ", ";
1216  }
1217  out << *last << ";\n";
1218  }
1219  break;
1220  }
1221 }
1222 
1233 void AttrTable::print(FILE *out, string pad, bool dereference)
1234 {
1235  ostringstream oss;
1236  print(oss, pad, dereference);
1237  fwrite(oss.str().data(), 1, oss.str().length(), out);
1238 
1239 #if 0
1240  for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1241  if ((*i)->is_alias) {
1242  if (dereference) {
1243  simple_print(out, pad, i, dereference);
1244  }
1245  else {
1246 #if WWW_ENCODING
1247  fprintf(out, "%sAlias %s %s;\n",
1248  pad.c_str(),
1249  id2www(get_name(i)).c_str(),
1250  id2www((*i)->aliased_to).c_str());
1251 #else
1252  fprintf(out, "%sAlias %s %s;\n",
1253  pad.c_str(), add_space_encoding(get_name(i)).c_str(), add_space_encoding((*i)->aliased_to).c_str());
1254 
1255 #endif
1256  }
1257  }
1258  else {
1259  simple_print(out, pad, i, dereference);
1260  }
1261  }
1262 #endif
1263 }
1264 
1275 void AttrTable::print(ostream &out, string pad, bool dereference)
1276 {
1277  for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1278  if ((*i)->is_alias) {
1279  if (dereference) {
1280  simple_print(out, pad, i, dereference);
1281  }
1282  else {
1283 #if WWW_ENCODING
1284  out << pad << "Alias " << id2www(get_name(i))
1285  << " " << id2www((*i)->aliased_to) << ";\n";
1286 #else
1287  out << pad << "Alias " << add_space_encoding(get_name(i)) << " "
1288  << add_space_encoding((*i)->aliased_to) << ";\n";
1289 #endif
1290  }
1291  }
1292  else {
1293  simple_print(out, pad, i, dereference);
1294  }
1295  }
1296 }
1297 
1303 void AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/)
1304 {
1305  XMLWriter xml(pad);
1306  print_xml_writer(xml);
1307  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1308 
1309 #if OLD_XML_MOETHODS
1310  ostringstream oss;
1311  print_xml(oss, pad);
1312  fwrite(oss.str().data(), 1, oss.str().length(), out);
1313 #endif
1314 
1315 #if 0
1316  // Why this works: AttrTable is really a hacked class that used to
1317  // implement a single-level set of attributes. Containers
1318  // were added several years later by dropping in the 'entry' structure.
1319  // It's not a class in its own right; instead accessors from AttrTable
1320  // are used to access information from entry. So... the loop below
1321  // actually iterates over the entries of *this* (which is an instance of
1322  // AttrTable). A container is an entry whose sole value is an AttrTable
1323  // instance. 05/19/03 jhrg
1324  for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1325  if ((*i)->is_alias) {
1326  fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n",
1327  pad.c_str(), id2xml(get_name(i)).c_str(),
1328  (*i)->aliased_to.c_str());
1329 
1330  }
1331  else if (is_container(i)) {
1332  fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1333  pad.c_str(), id2xml(get_name(i)).c_str(),
1334  get_type(i).c_str());
1335 
1336  get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1337 
1338  fprintf(out, "%s</Attribute>\n", pad.c_str());
1339  }
1340  else {
1341  fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1342  pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str());
1343 
1344  string value_pad = pad + " ";
1345  // Special handling for the OtherXML attribute type - don't escape
1346  // the XML and don't include the <value> element. Note that there
1347  // cannot be an vector of XML things as can be with the other types.
1348  if (get_attr_type(i) == Attr_other_xml) {
1349  if (get_attr_num(i) != 1)
1350  throw Error("OtherXML attributes cannot be vector-valued.");
1351  fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str());
1352  }
1353  else {
1354  for (unsigned j = 0; j < get_attr_num(i); ++j) {
1355  fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(),
1356  id2xml(get_attr(i, j)).c_str());
1357  }
1358  }
1359  fprintf(out, "%s</Attribute>\n", pad.c_str());
1360  }
1361  }
1362 #endif
1363 }
1364 
1368 void AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/)
1369 {
1370  XMLWriter xml(pad);
1371  print_xml_writer(xml);
1372  out << xml.get_doc();
1373 
1374 #if 0
1375  for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1376  if ((*i)->is_alias) {
1377  out << pad << "<Alias name=\"" << id2xml(get_name(i))
1378  << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n";
1379 
1380  }
1381  else if (is_container(i)) {
1382  out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1383  << "\" type=\"" << get_type(i) << "\">\n";
1384 
1385  get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1386 
1387  out << pad << "</Attribute>\n";
1388  }
1389  else {
1390  out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1391  << "\" type=\"" << get_type(i) << "\">\n";
1392 
1393  string value_pad = pad + " ";
1394  if (get_attr_type(i) == Attr_other_xml) {
1395  if (get_attr_num(i) != 1)
1396  throw Error("OtherXML attributes cannot be vector-valued.");
1397  out << value_pad << get_attr(i, 0) << "\n";
1398  }
1399  else {
1400  string value_pad = pad + " ";
1401  for (unsigned j = 0; j < get_attr_num(i); ++j) {
1402  out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n";
1403  }
1404  }
1405  out << pad << "</Attribute>\n";
1406  }
1407  }
1408 #endif
1409 }
1410 
1416 {
1417  for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1418  if ((*i)->is_alias) {
1419  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Alias") < 0)
1420  throw InternalErr(__FILE__, __LINE__, "Could not write Alias element");
1421  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1422  (const xmlChar*) get_name(i).c_str()) < 0)
1423  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1424  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "Attribute",
1425  (const xmlChar*) (*i)->aliased_to.c_str()) < 0)
1426  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1427  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1428  throw InternalErr(__FILE__, __LINE__, "Could not end Alias element");
1429  }
1430  else if (is_container(i)) {
1431  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
1432  throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1433  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1434  (const xmlChar*) get_name(i).c_str()) < 0)
1435  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1436  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
1437  (const xmlChar*) get_type(i).c_str()) < 0)
1438  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1439 
1441 
1442  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1443  throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1444  }
1445  else {
1446  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
1447  throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1448  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1449  (const xmlChar*) get_name(i).c_str()) < 0)
1450  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1451  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
1452  (const xmlChar*) get_type(i).c_str()) < 0)
1453  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1454 
1455  if (get_attr_type(i) == Attr_other_xml) {
1456  if (get_attr_num(i) != 1)
1457  throw Error("OtherXML attributes cannot be vector-valued.");
1458  // Replaced xmltextWriterWriteString with xmlTextWriterWriteRaw to keep the
1459  // libxml2 code from escaping the xml (which was breaking all of the inferencing
1460  // code. jhrg
1461  if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) get_attr(i, 0).c_str()) < 0)
1462  throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
1463  }
1464  else {
1465  for (unsigned j = 0; j < get_attr_num(i); ++j) {
1466  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "value") < 0)
1467  throw InternalErr(__FILE__, __LINE__, "Could not write value element");
1468 
1469  if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) get_attr(i, j).c_str()) < 0)
1470  throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
1471 
1472  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1473  throw InternalErr(__FILE__, __LINE__, "Could not end value element");
1474  }
1475  }
1476  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1477  throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1478  }
1479  }
1480 }
1481 
1489 void AttrTable::dump(ostream &strm) const
1490 {
1491  strm << DapIndent::LMarg << "AttrTable::dump - (" << (void *) this << ")" << endl;
1493  strm << DapIndent::LMarg << "table name: " << d_name << endl;
1494  if (attr_map.size()) {
1495  strm << DapIndent::LMarg << "attributes: " << endl;
1497  Attr_citer i = attr_map.begin();
1498  Attr_citer ie = attr_map.end();
1499  for (; i != ie; ++i) {
1500  entry *e = (*i);
1501  string type = AttrType_to_String(e->type);
1502  if (e->is_alias) {
1503  strm << DapIndent::LMarg << "alias: " << e->name << " aliased to: " << e->aliased_to << endl;
1504  }
1505  else if (e->type == Attr_container) {
1506  strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1508  e->attributes->dump(strm);
1510  }
1511  else {
1512  strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1514  strm << DapIndent::LMarg;
1515  vector<string>::const_iterator iter = e->attr->begin();
1516  vector<string>::const_iterator last = e->attr->end() - 1;
1517  for (; iter != last; ++iter) {
1518  strm << (*iter) << ", ";
1519  }
1520  strm << (*(e->attr->end() - 1)) << endl;
1522  }
1523  }
1525  }
1526  else {
1527  strm << DapIndent::LMarg << "attributes: empty" << endl;
1528  }
1529  if (d_parent) {
1530  strm << DapIndent::LMarg << "parent table:" << d_name << ":" << (void *) d_parent << endl;
1531  }
1532  else {
1533  strm << DapIndent::LMarg << "parent table: none" << d_name << endl;
1534  }
1536 }
1537 
1538 } // namespace libdap
1539 
std::vector< entry * >::iterator Attr_iter
Definition: AttrTable.h:237
static void UnIndent()
Definition: DapIndent.cc:49
unsigned int get_doc_size()
Definition: XMLWriter.cc:127
virtual Attr_iter attr_end()
Definition: AttrTable.cc:724
void downcase(string &s)
Definition: util.cc:428
Contains the attributes for a dataset.
Definition: AttrTable.h:150
#define not_used
Definition: config.h:1106
string AttrType_to_String(const AttrType at)
Definition: AttrTable.cc:98
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition: AttrTable.cc:618
void clone(const AttrTable &at)
Definition: AttrTable.cc:161
virtual void add_container_alias(const string &name, AttrTable *src)
Add an alias to a container held by this attribute table.
Definition: AttrTable.cc:898
virtual void print_xml(FILE *out, string pad=" ", bool constrained=false)
Definition: AttrTable.cc:1303
virtual ~AttrTable()
Definition: AttrTable.cc:211
virtual bool is_global_attribute() const
Definition: AttrTable.h:284
string id2xml(string in, const string &not_allowed)
Definition: escaping.cc:270
virtual string get_attr(const string &name, unsigned int i=0)
Definition: AttrTable.cc:848
virtual void del_attr(const string &name, int i=-1)
Deletes an attribute.
Definition: AttrTable.cc:680
string escape_double_quotes(string source)
Definition: escaping.cc:468
virtual void set_is_global_attribute(bool ga)
Definition: AttrTable.h:285
virtual AttrTable * recurrsive_find(const string &target, Attr_iter *location)
Definition: AttrTable.cc:518
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1415
const string double_quote
Definition: AttrTable.cc:1038
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1233
virtual AttrTable * find_container(const string &target)
Find an attribute with a given name.
Definition: AttrTable.cc:571
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:242
AttrTable & operator=(const AttrTable &rhs)
Definition: AttrTable.cc:219
A class for software fault reporting.
Definition: InternalErr.h:64
AttrTable * attributes
Definition: AttrTable.h:171
virtual Attr_iter get_attr_iter(int i)
Definition: AttrTable.cc:737
xmlTextWriterPtr get_writer()
Definition: XMLWriter.h:58
#define DBG(x)
Definition: debug.h:58
virtual void add_value_alias(AttrTable *at, const string &name, const string &source)
Add an alias for an attribute.
Definition: AttrTable.cc:932
virtual bool is_container(Attr_iter iter)
Definition: AttrTable.cc:751
AttrType String_to_AttrType(const string &s)
Definition: AttrTable.cc:128
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:414
static void Indent()
Definition: DapIndent.cc:43
AttrTable * simple_find_container(const string &target)
Definition: AttrTable.cc:588
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:612
virtual void erase()
Erase the attribute table.
Definition: AttrTable.cc:1026
bool is_quoted(const string &s)
Definition: util.cc:440
virtual bool attr_alias(const string &alias, AttrTable *at, const string &name)
Adds an alias to the set of attributes.
Definition: AttrTable.cc:1005
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:716
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:218
std::vector< entry * >::const_iterator Attr_citer
Definition: AttrTable.h:236
virtual unsigned int get_attr_num(const string &name)
Get the number of attributes in this container.
Definition: AttrTable.cc:639
static ostream & LMarg(ostream &strm)
Definition: DapIndent.cc:78
const char * get_doc()
Definition: XMLWriter.cc:103
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:311
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:1093
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:626
virtual void dump(ostream &strm) const
dumps information about this object
Definition: AttrTable.cc:1489
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:658
A class for error processing.
Definition: Error.h:90
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:249
std::vector< string > * attr
Definition: AttrTable.h:172
virtual Attr_iter del_attr_table(Attr_iter iter)
Definition: AttrTable.cc:776
virtual void find(const string &target, AttrTable **at, Attr_iter *iter)
Definition: AttrTable.cc:486
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition: AttrTable.cc:235
AttrType
Definition: AttrTable.h:81
string id2www(string in, const string &allowable)
Definition: escaping.cc:151
Attr_iter simple_find(const string &target)
Definition: AttrTable.cc:546