libdap++
Updated for version 3.8.2
|
00001 // -*- mode: c++; c-basic-offset:4 -*- 00002 00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00004 // Access Protocol. 00005 00006 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00007 // Author: James Gallagher <jgallagher@opendap.org> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00024 00025 // (c) COPYRIGHT URI/MIT 1994-1999 00026 // Please read the full copyright statement in the file COPYRIGHT_URI. 00027 // 00028 // Authors: 00029 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00030 00031 // jhrg 7/29/94 00032 00033 #include "config.h" 00034 00035 //#define DODS_DEBUG 00036 00037 static char rcsid[]not_used = 00038 "$Id: AttrTable.cc 25066 2011-11-30 18:39:37Z jimg $"; 00039 00040 #include <cassert> 00041 #include <sstream> 00042 00043 #include "AttrTable.h" 00044 00045 #include "util.h" 00046 #include "escaping.h" 00047 00048 #include "debug.h" 00049 00050 // Should the www2id and id2www functions be used to encode attribute names? 00051 // Probably not... jhrg 11/16/11 00052 #define WWW_ENCODING 0 00053 00054 using std::cerr; 00055 using std::string; 00056 using std::endl; 00057 using std::vector; 00058 00059 namespace libdap { 00060 00062 static string remove_space_encoding(const string &s) 00063 { 00064 string::size_type pos = s.find("%20"); 00065 if (pos != string::npos) { 00066 string n = s; 00067 do { 00068 n.replace(pos, 3, " "); 00069 pos = n.find("%20"); 00070 } while (pos != string::npos); 00071 return n; 00072 } 00073 else { 00074 return s; 00075 } 00076 } 00077 00079 static string add_space_encoding(const string &s) 00080 { 00081 string::size_type pos = s.find(" "); 00082 if (pos != string::npos) { 00083 string n = s; 00084 do { 00085 n.replace(pos, 1, "%20"); 00086 pos = n.find(" "); 00087 } while (pos != string::npos); 00088 return n; 00089 } 00090 else { 00091 return s; 00092 } 00093 } 00094 00098 string AttrType_to_String(const AttrType at) 00099 { 00100 switch (at) { 00101 case Attr_container: 00102 return "Container"; 00103 case Attr_byte: 00104 return "Byte"; 00105 case Attr_int16: 00106 return "Int16"; 00107 case Attr_uint16: 00108 return "UInt16"; 00109 case Attr_int32: 00110 return "Int32"; 00111 case Attr_uint32: 00112 return "UInt32"; 00113 case Attr_float32: 00114 return "Float32"; 00115 case Attr_float64: 00116 return "Float64"; 00117 case Attr_string: 00118 return "String"; 00119 case Attr_url: 00120 return "Url"; 00121 case Attr_other_xml: 00122 return "OtherXML"; 00123 default: 00124 return ""; 00125 } 00126 } 00127 00128 AttrType String_to_AttrType(const string &s) 00129 { 00130 string s2 = s; 00131 downcase(s2); 00132 00133 if (s2 == "container") 00134 return Attr_container; 00135 else if (s2 == "byte") 00136 return Attr_byte; 00137 else if (s2 == "int16") 00138 return Attr_int16; 00139 else if (s2 == "uint16") 00140 return Attr_uint16; 00141 else if (s2 == "int32") 00142 return Attr_int32; 00143 else if (s2 == "uint32") 00144 return Attr_uint32; 00145 else if (s2 == "float32") 00146 return Attr_float32; 00147 else if (s2 == "float64") 00148 return Attr_float64; 00149 else if (s2 == "string") 00150 return Attr_string; 00151 else if (s2 == "url") 00152 return Attr_url; 00153 else if (s2 == "otherxml") 00154 return Attr_other_xml; 00155 else 00156 return Attr_unknown; 00157 } 00158 00161 void AttrTable::clone(const AttrTable &at) 00162 { 00163 d_name = at.d_name; 00164 d_is_global_attribute = at.d_is_global_attribute; 00165 00166 // Set the parent to null (no parent, not in container) 00167 // since using at.d_parent is semantically incorrect 00168 // and potentially dangerous. 00169 d_parent = 0; 00170 00171 Attr_citer i = at.attr_map.begin(); 00172 Attr_citer ie = at.attr_map.end(); 00173 for (; i != ie; ++i) { 00174 // this deep-copies containers recursively 00175 entry *e = new entry(*(*i)); 00176 attr_map.push_back(e); 00177 00178 // If the entry being added was a container, 00179 // set its parent to this to maintain invariant. 00180 if (e->type == Attr_container) { 00181 assert(e->attributes); 00182 e->attributes->d_parent = this; 00183 } 00184 } 00185 } 00186 00190 AttrTable::AttrTable() : 00191 DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true) 00192 { 00193 } 00194 00195 AttrTable::AttrTable(const AttrTable &rhs) : 00196 DapObj() 00197 { 00198 clone(rhs); 00199 } 00200 00201 // Private 00202 void AttrTable::delete_attr_table() 00203 { 00204 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00205 delete *i; 00206 *i = 0; 00207 } 00208 attr_map.clear(); 00209 } 00210 00211 AttrTable::~AttrTable() 00212 { 00213 DBG(cerr << "Entering ~AttrTable (" << this << ")" << endl); 00214 delete_attr_table(); 00215 DBG(cerr << "Exiting ~AttrTable" << endl); 00216 } 00217 00218 AttrTable & 00219 AttrTable::operator=(const AttrTable &rhs) 00220 { 00221 if (this != &rhs) { 00222 delete_attr_table(); 00223 clone(rhs); 00224 } 00225 00226 return *this; 00227 } 00229 00235 unsigned int AttrTable::get_size() const 00236 { 00237 return attr_map.size(); 00238 } 00239 00242 string AttrTable::get_name() const 00243 { 00244 return d_name; 00245 } 00246 00249 void AttrTable::set_name(const string &n) 00250 { 00251 #if WWW_ENCODING 00252 d_name = www2id(n); 00253 #else 00254 d_name = remove_space_encoding(n); 00255 #endif 00256 } 00257 00258 #if 0 00259 // This was taken from das.y and could be used here to make the 'dods_errors' 00260 // attribute container like the parser used to. Then again, maybe this feature 00261 // was just BS. jhrg (ticket 1469) 00262 static void add_bad_attribute(AttrTable *attr, const string &type, const string &name, const string &value, 00263 const string &msg) { 00264 // First, if this bad value is already in a *_dods_errors container, 00265 // then just add it. This can happen when the server side processes a DAS 00266 // and then hands it off to a client which does the same. 00267 // Make a new container. Call it <attr's name>_errors. If that container 00268 // already exists, use it. 00269 // Add the attribute. 00270 // Add the error string to an attribute in the container called 00271 // `<name_explanation.'. 00272 00273 if (attr->get_name().find("_dods_errors") != string::npos) { 00274 attr->append_attr(name, type, value); 00275 } 00276 else { 00277 // I think _dods_errors should be _dap_error. jhrg 11/16/11 00278 string error_cont_name = attr->get_name() + "_dods_errors"; 00279 AttrTable *error_cont = attr->get_attr_table(error_cont_name); 00280 if (!error_cont) 00281 error_cont = attr->append_container(error_cont_name); 00282 00283 error_cont->append_attr(name, type, value); 00284 00285 #ifndef ATTR_STRING_QUOTE_FIX 00286 error_cont->append_attr(name + "_dap_explanation", "String", "\"" + msg + "\""); 00287 #else 00288 error_cont->append_attr(name + "_dap_explanation", "String", msg); 00289 #endif 00290 } 00291 } 00292 #endif 00293 00311 unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value) 00312 { 00313 DBG(cerr << "Entering AttrTable::append_attr" << endl); 00314 #if WWW_ENCODING 00315 string lname = www2id(name); 00316 #else 00317 string lname = remove_space_encoding(name); 00318 #endif 00319 00320 Attr_iter iter = simple_find(lname); 00321 00322 // If the types don't match OR this attribute is a container, calling 00323 // this mfunc is an error! 00324 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type))) 00325 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type")); 00326 if (iter != attr_map.end() && (get_type(iter) == "Container")) 00327 throw Error(string("An attribute called `") + name + string("' already exists but is a container.")); 00328 00329 if (iter != attr_map.end()) { // Must be a new attribute value; add it. 00330 (*iter)->attr->push_back(value); 00331 return (*iter)->attr->size(); 00332 } 00333 else { // Must be a completely new attribute; add it 00334 entry *e = new entry; 00335 00336 e->name = lname; 00337 e->is_alias = false; 00338 e->type = String_to_AttrType(type); // Record type using standard names. 00339 e->attr = new vector<string> ; 00340 e->attr->push_back(value); 00341 00342 attr_map.push_back(e); 00343 00344 return e->attr->size(); // return the length of the attr vector 00345 } 00346 } 00347 00366 unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values) 00367 { 00368 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl); 00369 #if WWW_ENCODING 00370 string lname = www2id(name); 00371 #else 00372 string lname = remove_space_encoding(name); 00373 #endif 00374 Attr_iter iter = simple_find(lname); 00375 00376 // If the types don't match OR this attribute is a container, calling 00377 // this mfunc is an error! 00378 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type))) 00379 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type")); 00380 if (iter != attr_map.end() && (get_type(iter) == "Container")) 00381 throw Error(string("An attribute called `") + name + string("' already exists but is a container.")); 00382 00383 if (iter != attr_map.end()) { // Must be new attribute values; add. 00384 vector<string>::iterator i = values->begin(); 00385 while (i != values->end()) 00386 (*iter)->attr->push_back(*i++); 00387 00388 return (*iter)->attr->size(); 00389 } 00390 else { // Must be a completely new attribute; add it 00391 entry *e = new entry; 00392 00393 e->name = lname; 00394 e->is_alias = false; 00395 e->type = String_to_AttrType(type); // Record type using standard names. 00396 e->attr = new vector<string> (*values); 00397 00398 attr_map.push_back(e); 00399 00400 return e->attr->size(); // return the length of the attr vector 00401 } 00402 } 00403 00413 AttrTable * 00414 AttrTable::append_container(const string &name) 00415 { 00416 AttrTable *new_at = new AttrTable; 00417 AttrTable *ret = NULL; 00418 try { 00419 ret = append_container(new_at, name); 00420 } catch (Error &e) { 00421 // an error occurred, attribute with that name already exists 00422 delete new_at; 00423 new_at = 0; 00424 throw; 00425 } 00426 return ret; 00427 } 00428 00443 AttrTable * 00444 AttrTable::append_container(AttrTable *at, const string &name) 00445 { 00446 #if WWW_ENCODING 00447 string lname = www2id(name); 00448 #else 00449 string lname = remove_space_encoding(name); 00450 #endif 00451 00452 if (simple_find(name) != attr_end()) 00453 throw Error( 00454 string("There already exists a container called `") + name + string("' in this attribute table. (1)")); 00455 DBG(cerr << "Setting appended attribute container name to: " 00456 << lname << endl); 00457 at->set_name(lname); 00458 00459 entry *e = new entry; 00460 e->name = lname; 00461 e->is_alias = false; 00462 e->type = Attr_container; 00463 e->attributes = at; 00464 00465 attr_map.push_back(e); 00466 00467 at->d_parent = this; 00468 00469 return e->attributes; 00470 } 00471 00486 void AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter) 00487 { 00488 string::size_type dotpos = target.rfind('.'); 00489 if (dotpos != string::npos) { 00490 string container = target.substr(0, dotpos); 00491 string field = target.substr(dotpos + 1); 00492 00493 *at = find_container(container); 00494 if (*at) { 00495 *iter = (*at)->simple_find(field); 00496 } 00497 else { 00498 *iter = attr_map.end(); 00499 } 00500 } 00501 else { 00502 *at = recurrsive_find(target, iter); 00503 } 00504 } 00505 00517 AttrTable * 00518 AttrTable::recurrsive_find(const string &target, Attr_iter *location) 00519 { 00520 Attr_iter i = attr_begin(); 00521 while (i != attr_end()) { 00522 if (target == (*i)->name) { 00523 *location = i; 00524 return this; 00525 } 00526 else if ((*i)->type == Attr_container) { 00527 AttrTable *at = (*i)->attributes->recurrsive_find(target, location); 00528 if (at) 00529 return at; 00530 } 00531 00532 ++i; 00533 } 00534 00535 *location = i; 00536 return 0; 00537 } 00538 00539 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09] 00546 AttrTable::Attr_iter AttrTable::simple_find(const string &target) 00547 { 00548 Attr_iter i; 00549 for (i = attr_map.begin(); i != attr_map.end(); ++i) { 00550 if (target == (*i)->name) { 00551 break; 00552 } 00553 } 00554 return i; 00555 } 00556 00570 AttrTable * 00571 AttrTable::find_container(const string &target) 00572 { 00573 string::size_type dotpos = target.find('.'); 00574 if (dotpos != string::npos) { 00575 string container = target.substr(0, dotpos); 00576 string field = target.substr(dotpos + 1); 00577 00578 AttrTable *at = simple_find_container(container); 00579 return (at) ? at->find_container(field) : 0; 00580 } 00581 else { 00582 return simple_find_container(target); 00583 } 00584 } 00585 00586 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09] 00587 AttrTable * 00588 AttrTable::simple_find_container(const string &target) 00589 { 00590 if (get_name() == target) 00591 return this; 00592 00593 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00594 if (is_container(i) && target == (*i)->name) { 00595 return (*i)->attributes; 00596 } 00597 } 00598 00599 return 0; 00600 } 00601 00609 00611 AttrTable * 00612 AttrTable::get_attr_table(const string &name) 00613 { 00614 return find_container(name); 00615 } 00616 00618 string AttrTable::get_type(const string &name) 00619 { 00620 Attr_iter p = simple_find(name); 00621 return (p != attr_map.end()) ? get_type(p) : (string) ""; 00622 } 00623 00626 AttrType AttrTable::get_attr_type(const string &name) 00627 { 00628 Attr_iter p = simple_find(name); 00629 return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown; 00630 } 00631 00639 unsigned int AttrTable::get_attr_num(const string &name) 00640 { 00641 Attr_iter iter = simple_find(name); 00642 return (iter != attr_map.end()) ? get_attr_num(iter) : 0; 00643 } 00644 00657 vector<string> * 00658 AttrTable::get_attr_vector(const string &name) 00659 { 00660 Attr_iter p = simple_find(name); 00661 return (p != attr_map.end()) ? get_attr_vector(p) : 0; 00662 } 00663 00680 void AttrTable::del_attr(const string &name, int i) 00681 { 00682 #if WWW_ENCODING 00683 string lname = www2id(name); 00684 #else 00685 string lname = remove_space_encoding(name); 00686 #endif 00687 00688 Attr_iter iter = simple_find(lname); 00689 if (iter != attr_map.end()) { 00690 if (i == -1) { // Delete the whole attribute 00691 entry *e = *iter; 00692 attr_map.erase(iter); 00693 delete e; 00694 e = 0; 00695 } 00696 else { // Delete one element from attribute array 00697 // Don't try to delete elements from the vector of values if the 00698 // map is a container! 00699 if ((*iter)->type == Attr_container) 00700 return; 00701 00702 vector<string> *sxp = (*iter)->attr; 00703 00704 assert(i >= 0 && i < (int) sxp->size()); 00705 sxp->erase(sxp->begin() + i); // rm the element 00706 } 00707 } 00708 } 00709 00711 00716 AttrTable::Attr_iter AttrTable::attr_begin() 00717 { 00718 return attr_map.begin(); 00719 } 00720 00724 AttrTable::Attr_iter AttrTable::attr_end() 00725 { 00726 return attr_map.end(); 00727 } 00728 00737 AttrTable::Attr_iter AttrTable::get_attr_iter(int i) 00738 { 00739 return attr_map.begin() + i; 00740 } 00741 00743 string AttrTable::get_name(Attr_iter iter) 00744 { 00745 assert(iter != attr_map.end()); 00746 00747 return (*iter)->name; 00748 } 00749 00751 bool AttrTable::is_container(Attr_iter i) 00752 { 00753 return (*i)->type == Attr_container; 00754 } 00755 00761 AttrTable * 00762 AttrTable::get_attr_table(Attr_iter iter) 00763 { 00764 assert(iter != attr_map.end()); 00765 return (*iter)->type == Attr_container ? (*iter)->attributes : 0; 00766 } 00767 00776 AttrTable::Attr_iter AttrTable::del_attr_table(Attr_iter iter) 00777 { 00778 if ((*iter)->type != Attr_container) 00779 return ++iter; 00780 00781 // the caller intends to delete/reuse the contained AttrTable, 00782 // so zero it out so it doesn't get deleted before we delete the entry 00783 // [mjohnson] 00784 struct entry* e = *iter; 00785 // container no longer has a parent. 00786 if (e->attributes) { 00787 e->attributes->d_parent = 0; 00788 } 00789 e->attributes = 0; 00790 delete e; 00791 00792 return attr_map.erase(iter); 00793 } 00794 00798 string AttrTable::get_type(Attr_iter iter) 00799 { 00800 assert(iter != attr_map.end()); 00801 return AttrType_to_String((*iter)->type); 00802 } 00803 00807 AttrType AttrTable::get_attr_type(Attr_iter iter) 00808 { 00809 return (*iter)->type; 00810 } 00811 00819 unsigned int AttrTable::get_attr_num(Attr_iter iter) 00820 { 00821 assert(iter != attr_map.end()); 00822 return ((*iter)->type == Attr_container) ? (*iter)->attributes->get_size() : (*iter)->attr->size(); 00823 } 00824 00841 string AttrTable::get_attr(Attr_iter iter, unsigned int i) 00842 { 00843 assert(iter != attr_map.end()); 00844 00845 return (*iter)->type == Attr_container ? (string) "None" : (*(*iter)->attr)[i]; 00846 } 00847 00848 string AttrTable::get_attr(const string &name, unsigned int i) 00849 { 00850 Attr_iter p = simple_find(name); 00851 return (p != attr_map.end()) ? get_attr(p, i) : (string) ""; 00852 } 00853 00865 vector<string> * 00866 AttrTable::get_attr_vector(Attr_iter iter) 00867 { 00868 assert(iter != attr_map.end()); 00869 return (*iter)->type != Attr_container ? (*iter)->attr : 0; 00870 } 00871 00872 bool AttrTable::is_global_attribute(Attr_iter iter) 00873 { 00874 assert(iter != attr_map.end()); 00875 if ((*iter)->type == Attr_container) 00876 return (*iter)->attributes->is_global_attribute(); 00877 else 00878 return (*iter)->is_global; 00879 } 00880 00881 void AttrTable::set_is_global_attribute(Attr_iter iter, bool ga) 00882 { 00883 assert(iter != attr_map.end()); 00884 if ((*iter)->type == Attr_container) 00885 (*iter)->attributes->set_is_global_attribute(ga); 00886 else 00887 (*iter)->is_global = ga; 00888 } 00889 00891 00892 // Alias an attribute table. The alias should be added to this object. 00898 void AttrTable::add_container_alias(const string &name, AttrTable *src) 00899 { 00900 #if WWW_ENCODING 00901 string lname = www2id(name); 00902 #else 00903 string lname = remove_space_encoding(name); 00904 #endif 00905 00906 if (simple_find(lname) != attr_end()) 00907 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (2)")); 00908 00909 entry *e = new entry; 00910 e->name = lname; 00911 e->is_alias = true; 00912 e->aliased_to = src->get_name(); 00913 e->type = Attr_container; 00914 00915 e->attributes = src; 00916 00917 attr_map.push_back(e); 00918 } 00919 00932 void AttrTable::add_value_alias(AttrTable *das, const string &name, const string &source) 00933 { 00934 #if WWW_ENCODING 00935 string lname = www2id(name); 00936 #else 00937 string lname = remove_space_encoding(name); 00938 #endif 00939 00940 #if WWW_ENCODING 00941 string lsource = www2id(source); 00942 #else 00943 string lsource = remove_space_encoding(source); 00944 #endif 00945 00946 // find the container that holds source and its (sources's) iterator 00947 // within that container. Search at the uppermost level of the attribute 00948 // object to find values defined `above' the current container. 00949 AttrTable *at; 00950 Attr_iter iter; 00951 das->find(lsource, &at, &iter); 00952 00953 // If source is not found by looking at the topmost level, look in the 00954 // current table (i.e., alias z x where x is in the current container 00955 // won't be found by looking for `x' at the top level). See test case 26 00956 // in das-testsuite. 00957 if (!at || (iter == at->attr_end()) || !*iter) { 00958 find(lsource, &at, &iter); 00959 if (!at || (iter == at->attr_end()) || !*iter) 00960 throw Error(string("Could not find the attribute `") + source + string("' in the attribute object.")); 00961 } 00962 00963 // If we've got a value to alias and it's being added at the top level of 00964 // the DAS, that's an error. 00965 if (at && !at->is_container(iter) && this == das) 00966 throw Error( 00967 string( 00968 "A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS.")); 00969 00970 if (simple_find(lname) != attr_end()) 00971 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (3)")); 00972 00973 entry *e = new entry; 00974 e->name = lname; 00975 e->is_alias = true; 00976 e->aliased_to = lsource; 00977 e->type = get_attr_type(iter); 00978 if (at && e->type == Attr_container) 00979 e->attributes = at->get_attr_table(iter); 00980 else 00981 e->attr = (*iter)->attr; 00982 00983 attr_map.push_back(e); 00984 } 00985 00986 // Deprecated 01005 bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name) 01006 { 01007 add_value_alias(at, alias, name); 01008 return true; 01009 } 01010 01018 bool AttrTable::attr_alias(const string &alias, const string &name) 01019 { 01020 return attr_alias(alias, this, name); 01021 } 01022 01026 void AttrTable::erase() 01027 { 01028 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01029 delete *i; 01030 *i = 0; 01031 } 01032 01033 attr_map.erase(attr_map.begin(), attr_map.end()); 01034 01035 d_name = ""; 01036 } 01037 01038 const string double_quote = "\""; 01039 01040 // This is here as a result of the problem described in ticket #1163 where 01041 // the data handlers are adding quotes to string attributes so the DAS will 01042 // be printed correctly. But that has the affect of adding the quotes to the 01043 // attribute's _value_ not just it's print representation. As part of the fix 01044 // I made the code here add the quotes if the handlers are fixed (but not if 01045 // handlers are still adding them). The other part of 1163 is to fix all of 01046 // the handlers... What this fix means is that attributes whose values really 01047 // do contain bracketing quotes might be misunderstood, since we're assuming 01048 // those quotes were added by the handlers as a hack to get the output 01049 // formatting correct for the DAS. jhrg 7/30/08 01050 01051 static void write_string_attribute_for_das(ostream &out, const string &value, const string &term) 01052 { 01053 if (is_quoted(value)) 01054 out << value << term; 01055 else 01056 out << double_quote << value << double_quote << term; 01057 } 01058 01059 #if 0 01060 static void 01061 write_string_attribute_for_das(FILE *out, const string &value, const string &term) 01062 { 01063 if (is_quoted(value)) 01064 fprintf(out, "%s%s", value.c_str(), term.c_str()); 01065 else 01066 fprintf(out, "\"%s\"%s", value.c_str(), term.c_str()); 01067 } 01068 #endif 01069 01070 // Special treatment for XML: Make sure to escape double quotes when XML is 01071 // printed in a DAS. 01072 static void write_xml_attribute_for_das(ostream &out, const string &value, const string &term) 01073 { 01074 if (is_quoted(value)) 01075 out << escape_double_quotes(value) << term; 01076 else 01077 out << double_quote << escape_double_quotes(value) << double_quote << term; 01078 } 01079 01080 #if 0 01081 static void 01082 write_xml_attribute_for_das(FILE *out, const string &value, const string &term) 01083 { 01084 if (is_quoted(value)) 01085 fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str()); 01086 else 01087 fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str()); 01088 } 01089 #endif 01090 01093 void AttrTable::simple_print(FILE *out, string pad, Attr_iter i, bool dereference) 01094 { 01095 ostringstream oss; 01096 simple_print(oss, pad, i, dereference); 01097 fwrite(oss.str().data(), 1, oss.str().length(), out); 01098 01099 #if 0 01100 switch ((*i)->type) { 01101 case Attr_container: 01102 #if WWW_ENCODING 01103 fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str()); 01104 #else 01105 fprintf(out, "%s%s {\n", pad.c_str(), get_name(i).c_str()); 01106 #endif 01107 (*i)->attributes->print(out, pad + " ", dereference); 01108 01109 fprintf(out, "%s}\n", pad.c_str()); 01110 break; 01111 01112 case Attr_string: { 01113 #if WWW_ENCODING 01114 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str()); 01115 #else 01116 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str()); 01117 #endif 01118 vector<string> *sxp = (*i)->attr; 01119 vector<string>::iterator last = sxp->end() - 1; 01120 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01121 write_string_attribute_for_das(out, *i, ", "); 01122 } 01123 write_string_attribute_for_das(out, *last, ";\n"); 01124 } 01125 break; 01126 01127 case Attr_other_xml: { 01128 #if WWW_ENCODING 01129 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str()); 01130 #else 01131 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str()); 01132 #endif 01133 vector<string> *sxp = (*i)->attr; 01134 vector<string>::iterator last = sxp->end() - 1; 01135 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01136 write_xml_attribute_for_das(out, *i, ", "); 01137 } 01138 write_xml_attribute_for_das(out, *last, ";\n"); 01139 } 01140 break; 01141 01142 default: { 01143 #if WWW_ENCODING 01144 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str()); 01145 #else 01146 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str()); 01147 #endif 01148 01149 vector<string> *sxp = (*i)->attr; 01150 vector<string>::iterator last = sxp->end() - 1; 01151 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01152 fprintf(out, "%s%s", (*i).c_str(), ", "); 01153 } 01154 fprintf(out, "%s%s", (*last).c_str(), ";\n"); 01155 } 01156 break; 01157 } 01158 #endif 01159 } 01160 01163 void AttrTable::simple_print(ostream &out, string pad, Attr_iter i, bool dereference) 01164 { 01165 switch ((*i)->type) { 01166 case Attr_container: 01167 #if WWW_ENCODING 01168 out << pad << id2www(get_name(i)) << " {\n"; 01169 #else 01170 out << pad << add_space_encoding(get_name(i)) << " {\n"; 01171 #endif 01172 (*i)->attributes->print(out, pad + " ", dereference); 01173 out << pad << "}\n"; 01174 break; 01175 01176 case Attr_string: { 01177 #if WWW_ENCODING 01178 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01179 #else 01180 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " "; 01181 #endif 01182 vector<string> *sxp = (*i)->attr; 01183 vector<string>::iterator last = sxp->end() - 1; 01184 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01185 write_string_attribute_for_das(out, *i, ", "); 01186 } 01187 write_string_attribute_for_das(out, *last, ";\n"); 01188 } 01189 break; 01190 01191 case Attr_other_xml: { 01192 #if WWW_ENCODING 01193 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01194 #else 01195 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " "; 01196 #endif 01197 vector<string> *sxp = (*i)->attr; 01198 vector<string>::iterator last = sxp->end() - 1; 01199 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01200 write_xml_attribute_for_das(out, *i, ", "); 01201 } 01202 write_xml_attribute_for_das(out, *last, ";\n"); 01203 } 01204 break; 01205 01206 default: { 01207 #if WWW_ENCODING 01208 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01209 #else 01210 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " "; 01211 #endif 01212 vector<string> *sxp = (*i)->attr; 01213 vector<string>::iterator last = sxp->end() - 1; 01214 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01215 out << *i << ", "; 01216 } 01217 out << *last << ";\n"; 01218 } 01219 break; 01220 } 01221 } 01222 01233 void AttrTable::print(FILE *out, string pad, bool dereference) 01234 { 01235 ostringstream oss; 01236 print(oss, pad, dereference); 01237 fwrite(oss.str().data(), 1, oss.str().length(), out); 01238 01239 #if 0 01240 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01241 if ((*i)->is_alias) { 01242 if (dereference) { 01243 simple_print(out, pad, i, dereference); 01244 } 01245 else { 01246 #if WWW_ENCODING 01247 fprintf(out, "%sAlias %s %s;\n", 01248 pad.c_str(), 01249 id2www(get_name(i)).c_str(), 01250 id2www((*i)->aliased_to).c_str()); 01251 #else 01252 fprintf(out, "%sAlias %s %s;\n", 01253 pad.c_str(), add_space_encoding(get_name(i)).c_str(), add_space_encoding((*i)->aliased_to).c_str()); 01254 01255 #endif 01256 } 01257 } 01258 else { 01259 simple_print(out, pad, i, dereference); 01260 } 01261 } 01262 #endif 01263 } 01264 01275 void AttrTable::print(ostream &out, string pad, bool dereference) 01276 { 01277 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01278 if ((*i)->is_alias) { 01279 if (dereference) { 01280 simple_print(out, pad, i, dereference); 01281 } 01282 else { 01283 #if WWW_ENCODING 01284 out << pad << "Alias " << id2www(get_name(i)) 01285 << " " << id2www((*i)->aliased_to) << ";\n"; 01286 #else 01287 out << pad << "Alias " << add_space_encoding(get_name(i)) << " " 01288 << add_space_encoding((*i)->aliased_to) << ";\n"; 01289 #endif 01290 } 01291 } 01292 else { 01293 simple_print(out, pad, i, dereference); 01294 } 01295 } 01296 } 01297 01303 void AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/) 01304 { 01305 ostringstream oss; 01306 print_xml(oss, pad); 01307 fwrite(oss.str().data(), 1, oss.str().length(), out); 01308 01309 #if 0 01310 // Why this works: AttrTable is really a hacked class that used to 01311 // implement a single-level set of attributes. Containers 01312 // were added several years later by dropping in the 'entry' structure. 01313 // It's not a class in its own right; instead accessors from AttrTable 01314 // are used to access information from entry. So... the loop below 01315 // actually iterates over the entries of *this* (which is an instance of 01316 // AttrTable). A container is an entry whose sole value is an AttrTable 01317 // instance. 05/19/03 jhrg 01318 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01319 if ((*i)->is_alias) { 01320 fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n", 01321 pad.c_str(), id2xml(get_name(i)).c_str(), 01322 (*i)->aliased_to.c_str()); 01323 01324 } 01325 else if (is_container(i)) { 01326 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n", 01327 pad.c_str(), id2xml(get_name(i)).c_str(), 01328 get_type(i).c_str()); 01329 01330 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/); 01331 01332 fprintf(out, "%s</Attribute>\n", pad.c_str()); 01333 } 01334 else { 01335 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n", 01336 pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str()); 01337 01338 string value_pad = pad + " "; 01339 // Special handling for the OtherXML attribute type - don't escape 01340 // the XML and don't include the <value> element. Note that there 01341 // cannot be an vector of XML things as can be with the other types. 01342 if (get_attr_type(i) == Attr_other_xml) { 01343 if (get_attr_num(i) != 1) 01344 throw Error("OtherXML attributes cannot be vector-valued."); 01345 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str()); 01346 } 01347 else { 01348 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01349 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(), 01350 id2xml(get_attr(i, j)).c_str()); 01351 } 01352 } 01353 fprintf(out, "%s</Attribute>\n", pad.c_str()); 01354 } 01355 } 01356 #endif 01357 } 01358 01362 void AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/) 01363 { 01364 XMLWriter xml(pad); 01365 print_xml_writer(xml); 01366 out << xml.get_doc(); 01367 01368 #if 0 01369 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01370 if ((*i)->is_alias) { 01371 out << pad << "<Alias name=\"" << id2xml(get_name(i)) 01372 << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n"; 01373 01374 } 01375 else if (is_container(i)) { 01376 out << pad << "<Attribute name=\"" << id2xml(get_name(i)) 01377 << "\" type=\"" << get_type(i) << "\">\n"; 01378 01379 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/); 01380 01381 out << pad << "</Attribute>\n"; 01382 } 01383 else { 01384 out << pad << "<Attribute name=\"" << id2xml(get_name(i)) 01385 << "\" type=\"" << get_type(i) << "\">\n"; 01386 01387 string value_pad = pad + " "; 01388 if (get_attr_type(i) == Attr_other_xml) { 01389 if (get_attr_num(i) != 1) 01390 throw Error("OtherXML attributes cannot be vector-valued."); 01391 out << value_pad << get_attr(i, 0) << "\n"; 01392 } 01393 else { 01394 string value_pad = pad + " "; 01395 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01396 out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n"; 01397 } 01398 } 01399 out << pad << "</Attribute>\n"; 01400 } 01401 } 01402 #endif 01403 } 01404 01409 void AttrTable::print_xml_writer(XMLWriter &xml) 01410 { 01411 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01412 if ((*i)->is_alias) { 01413 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Alias") < 0) 01414 throw InternalErr(__FILE__, __LINE__, "Could not write Alias element"); 01415 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", 01416 (const xmlChar*) get_name(i).c_str()) < 0) 01417 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01418 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "Attribute", 01419 (const xmlChar*) (*i)->aliased_to.c_str()) < 0) 01420 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01421 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01422 throw InternalErr(__FILE__, __LINE__, "Could not end Alias element"); 01423 } 01424 else if (is_container(i)) { 01425 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0) 01426 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element"); 01427 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", 01428 (const xmlChar*) get_name(i).c_str()) < 0) 01429 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01430 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", 01431 (const xmlChar*) get_type(i).c_str()) < 0) 01432 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01433 01434 get_attr_table(i)->print_xml_writer(xml); 01435 01436 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01437 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element"); 01438 } 01439 else { 01440 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0) 01441 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element"); 01442 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", 01443 (const xmlChar*) get_name(i).c_str()) < 0) 01444 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01445 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", 01446 (const xmlChar*) get_type(i).c_str()) < 0) 01447 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01448 01449 if (get_attr_type(i) == Attr_other_xml) { 01450 if (get_attr_num(i) != 1) 01451 throw Error("OtherXML attributes cannot be vector-valued."); 01452 // Replaced xmltextWriterWriteString with xmlTextWriterWriteRaw to keep the 01453 // libxml2 code from escaping the xml (which was breaking all of the inferencing 01454 // code. jhrg 01455 if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) get_attr(i, 0).c_str()) < 0) 01456 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value"); 01457 } 01458 else { 01459 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01460 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "value") < 0) 01461 throw InternalErr(__FILE__, __LINE__, "Could not write value element"); 01462 01463 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) get_attr(i, j).c_str()) < 0) 01464 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value"); 01465 01466 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01467 throw InternalErr(__FILE__, __LINE__, "Could not end value element"); 01468 } 01469 } 01470 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01471 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element"); 01472 } 01473 } 01474 } 01475 01483 void AttrTable::dump(ostream &strm) const 01484 { 01485 strm << DapIndent::LMarg << "AttrTable::dump - (" << (void *) this << ")" << endl; 01486 DapIndent::Indent(); 01487 strm << DapIndent::LMarg << "table name: " << d_name << endl; 01488 if (attr_map.size()) { 01489 strm << DapIndent::LMarg << "attributes: " << endl; 01490 DapIndent::Indent(); 01491 Attr_citer i = attr_map.begin(); 01492 Attr_citer ie = attr_map.end(); 01493 for (; i != ie; ++i) { 01494 entry *e = (*i); 01495 string type = AttrType_to_String(e->type); 01496 if (e->is_alias) { 01497 strm << DapIndent::LMarg << "alias: " << e->name << " aliased to: " << e->aliased_to << endl; 01498 } 01499 else if (e->type == Attr_container) { 01500 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl; 01501 DapIndent::Indent(); 01502 e->attributes->dump(strm); 01503 DapIndent::UnIndent(); 01504 } 01505 else { 01506 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl; 01507 DapIndent::Indent(); 01508 strm << DapIndent::LMarg; 01509 vector<string>::const_iterator iter = e->attr->begin(); 01510 vector<string>::const_iterator last = e->attr->end() - 1; 01511 for (; iter != last; ++iter) { 01512 strm << (*iter) << ", "; 01513 } 01514 strm << (*(e->attr->end() - 1)) << endl; 01515 DapIndent::UnIndent(); 01516 } 01517 } 01518 DapIndent::UnIndent(); 01519 } 01520 else { 01521 strm << DapIndent::LMarg << "attributes: empty" << endl; 01522 } 01523 if (d_parent) { 01524 strm << DapIndent::LMarg << "parent table:" << d_name << ":" << (void *) d_parent << endl; 01525 } 01526 else { 01527 strm << DapIndent::LMarg << "parent table: none" << d_name << endl; 01528 } 01529 DapIndent::UnIndent(); 01530 } 01531 01532 } // namespace libdap 01533