libdap
Updated for version 3.17.0
|
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 #include <cassert> 00036 #include <sstream> 00037 00038 #include "AttrTable.h" 00039 00040 #include "util.h" 00041 #include "escaping.h" 00042 00043 #include "debug.h" 00044 00045 // Should the www2id and id2www functions be used to encode attribute names? 00046 // Probably not... jhrg 11/16/11 00047 #define WWW_ENCODING 0 00048 // See the note for del_attr_table(). That method now deletes the contained 00049 // AttrTable. 00050 #define NEW_DEL_ATTR_TABLE_BEHAVIOR 0 00051 00052 using std::cerr; 00053 using std::string; 00054 using std::endl; 00055 using std::vector; 00056 00057 namespace libdap { 00058 00060 static string remove_space_encoding(const string &s) 00061 { 00062 string::size_type pos = s.find("%20"); 00063 if (pos != string::npos) { 00064 string n = s; 00065 do { 00066 n.replace(pos, 3, " "); 00067 pos = n.find("%20"); 00068 } while (pos != string::npos); 00069 return n; 00070 } 00071 else { 00072 return s; 00073 } 00074 } 00075 00077 static string add_space_encoding(const string &s) 00078 { 00079 string::size_type pos = s.find(" "); 00080 if (pos != string::npos) { 00081 string n = s; 00082 do { 00083 n.replace(pos, 1, "%20"); 00084 pos = n.find(" "); 00085 } while (pos != string::npos); 00086 return n; 00087 } 00088 else { 00089 return s; 00090 } 00091 } 00092 00096 string AttrType_to_String(const AttrType at) 00097 { 00098 switch (at) { 00099 case Attr_container: 00100 return "Container"; 00101 case Attr_byte: 00102 return "Byte"; 00103 case Attr_int16: 00104 return "Int16"; 00105 case Attr_uint16: 00106 return "UInt16"; 00107 case Attr_int32: 00108 return "Int32"; 00109 case Attr_uint32: 00110 return "UInt32"; 00111 case Attr_float32: 00112 return "Float32"; 00113 case Attr_float64: 00114 return "Float64"; 00115 case Attr_string: 00116 return "String"; 00117 case Attr_url: 00118 return "Url"; 00119 case Attr_other_xml: 00120 return "OtherXML"; 00121 default: 00122 return ""; 00123 } 00124 } 00125 00126 AttrType String_to_AttrType(const string &s) 00127 { 00128 string s2 = s; 00129 downcase(s2); 00130 00131 if (s2 == "container") 00132 return Attr_container; 00133 else if (s2 == "byte") 00134 return Attr_byte; 00135 else if (s2 == "int16") 00136 return Attr_int16; 00137 else if (s2 == "uint16") 00138 return Attr_uint16; 00139 else if (s2 == "int32") 00140 return Attr_int32; 00141 else if (s2 == "uint32") 00142 return Attr_uint32; 00143 else if (s2 == "float32") 00144 return Attr_float32; 00145 else if (s2 == "float64") 00146 return Attr_float64; 00147 else if (s2 == "string") 00148 return Attr_string; 00149 else if (s2 == "url") 00150 return Attr_url; 00151 else if (s2 == "otherxml") 00152 return Attr_other_xml; 00153 else 00154 return Attr_unknown; 00155 } 00156 00159 void AttrTable::clone(const AttrTable &at) 00160 { 00161 d_name = at.d_name; 00162 d_is_global_attribute = at.d_is_global_attribute; 00163 00164 // Set the parent to null (no parent, not in container) 00165 // since using at.d_parent is semantically incorrect 00166 // and potentially dangerous. 00167 d_parent = 0; 00168 00169 Attr_citer i = at.attr_map.begin(); 00170 Attr_citer ie = at.attr_map.end(); 00171 for (; i != ie; ++i) { 00172 // this deep-copies containers recursively 00173 entry *e = new entry(*(*i)); 00174 attr_map.push_back(e); 00175 00176 // If the entry being added was a container, 00177 // set its parent to this to maintain invariant. 00178 if (e->type == Attr_container) { 00179 assert(e->attributes); 00180 e->attributes->d_parent = this; 00181 } 00182 } 00183 } 00184 00188 AttrTable::AttrTable() : 00189 DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true) 00190 { 00191 } 00192 00193 AttrTable::AttrTable(const AttrTable &rhs) : 00194 DapObj() 00195 { 00196 clone(rhs); 00197 } 00198 00199 // Private 00200 void AttrTable::delete_attr_table() 00201 { 00202 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00203 delete *i; 00204 } 00205 attr_map.clear(); 00206 } 00207 00208 AttrTable::~AttrTable() 00209 { 00210 delete_attr_table(); 00211 } 00212 00213 AttrTable & 00214 AttrTable::operator=(const AttrTable &rhs) 00215 { 00216 if (this != &rhs) { 00217 delete_attr_table(); 00218 clone(rhs); 00219 } 00220 00221 return *this; 00222 } 00224 00230 unsigned int AttrTable::get_size() const 00231 { 00232 return attr_map.size(); 00233 } 00234 00237 string AttrTable::get_name() const 00238 { 00239 return d_name; 00240 } 00241 00244 void AttrTable::set_name(const string &n) 00245 { 00246 #if WWW_ENCODING 00247 d_name = www2id(n); 00248 #else 00249 d_name = remove_space_encoding(n); 00250 #endif 00251 } 00252 00253 #if 0 00254 // This was taken from das.y and could be used here to make the 'dods_errors' 00255 // attribute container like the parser used to. Then again, maybe this feature 00256 // was just BS. jhrg (ticket 1469) 00257 static void add_bad_attribute(AttrTable *attr, const string &type, const string &name, const string &value, 00258 const string &msg) { 00259 // First, if this bad value is already in a *_dods_errors container, 00260 // then just add it. This can happen when the server side processes a DAS 00261 // and then hands it off to a client which does the same. 00262 // Make a new container. Call it <attr's name>_errors. If that container 00263 // already exists, use it. 00264 // Add the attribute. 00265 // Add the error string to an attribute in the container called 00266 // `<name_explanation.'. 00267 00268 if (attr->get_name().find("_dods_errors") != string::npos) { 00269 attr->append_attr(name, type, value); 00270 } 00271 else { 00272 // I think _dods_errors should be _dap_error. jhrg 11/16/11 00273 string error_cont_name = attr->get_name() + "_dods_errors"; 00274 AttrTable *error_cont = attr->get_attr_table(error_cont_name); 00275 if (!error_cont) 00276 error_cont = attr->append_container(error_cont_name); 00277 00278 error_cont->append_attr(name, type, value); 00279 00280 #ifndef ATTR_STRING_QUOTE_FIX 00281 error_cont->append_attr(name + "_dap_explanation", "String", "\"" + msg + "\""); 00282 #else 00283 error_cont->append_attr(name + "_dap_explanation", "String", msg); 00284 #endif 00285 } 00286 } 00287 #endif 00288 00306 unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value) 00307 { 00308 DBG(cerr << "Entering AttrTable::append_attr" << endl); 00309 #if WWW_ENCODING 00310 string lname = www2id(name); 00311 #else 00312 string lname = remove_space_encoding(name); 00313 #endif 00314 00315 Attr_iter iter = simple_find(lname); 00316 00317 // If the types don't match OR this attribute is a container, calling 00318 // this mfunc is an error! 00319 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type))) 00320 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type")); 00321 if (iter != attr_map.end() && (get_type(iter) == "Container")) 00322 throw Error(string("An attribute called `") + name + string("' already exists but is a container.")); 00323 00324 if (iter != attr_map.end()) { // Must be a new attribute value; add it. 00325 (*iter)->attr->push_back(value); 00326 return (*iter)->attr->size(); 00327 } 00328 else { // Must be a completely new attribute; add it 00329 entry *e = new entry; 00330 00331 e->name = lname; 00332 e->is_alias = false; 00333 e->type = String_to_AttrType(type); // Record type using standard names. 00334 e->attr = new vector<string> ; 00335 e->attr->push_back(value); 00336 00337 attr_map.push_back(e); 00338 00339 return e->attr->size(); // return the length of the attr vector 00340 } 00341 } 00342 00361 unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values) 00362 { 00363 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl); 00364 #if WWW_ENCODING 00365 string lname = www2id(name); 00366 #else 00367 string lname = remove_space_encoding(name); 00368 #endif 00369 Attr_iter iter = simple_find(lname); 00370 00371 // If the types don't match OR this attribute is a container, calling 00372 // this mfunc is an error! 00373 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type))) 00374 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type")); 00375 if (iter != attr_map.end() && (get_type(iter) == "Container")) 00376 throw Error(string("An attribute called `") + name + string("' already exists but is a container.")); 00377 00378 if (iter != attr_map.end()) { // Must be new attribute values; add. 00379 vector<string>::iterator i = values->begin(); 00380 while (i != values->end()) 00381 (*iter)->attr->push_back(*i++); 00382 00383 return (*iter)->attr->size(); 00384 } 00385 else { // Must be a completely new attribute; add it 00386 entry *e = new entry; 00387 00388 e->name = lname; 00389 e->is_alias = false; 00390 e->type = String_to_AttrType(type); // Record type using standard names. 00391 e->attr = new vector<string> (*values); 00392 00393 attr_map.push_back(e); 00394 00395 return e->attr->size(); // return the length of the attr vector 00396 } 00397 } 00398 00408 AttrTable * 00409 AttrTable::append_container(const string &name) 00410 { 00411 AttrTable *new_at = new AttrTable; 00412 AttrTable *ret = NULL; 00413 try { 00414 ret = append_container(new_at, name); 00415 } catch (Error &e) { 00416 // an error occurred, attribute with that name already exists 00417 delete new_at; 00418 new_at = 0; 00419 throw; 00420 } 00421 return ret; 00422 } 00423 00438 AttrTable * 00439 AttrTable::append_container(AttrTable *at, const string &name) 00440 { 00441 #if WWW_ENCODING 00442 string lname = www2id(name); 00443 #else 00444 string lname = remove_space_encoding(name); 00445 #endif 00446 00447 if (simple_find(name) != attr_end()) 00448 throw Error("There already exists a container called '" + name + "' in this attribute table (" + at->get_name() + "). (1)"); 00449 00450 DBG(cerr << "Setting appended attribute container name to: " << lname << endl); 00451 at->set_name(lname); 00452 00453 entry *e = new entry; 00454 e->name = lname; 00455 e->is_alias = false; 00456 e->type = Attr_container; 00457 e->attributes = at; 00458 00459 attr_map.push_back(e); 00460 00461 at->d_parent = this; 00462 00463 return e->attributes; 00464 } 00465 00480 void AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter) 00481 { 00482 string::size_type dotpos = target.rfind('.'); 00483 if (dotpos != string::npos) { 00484 string container = target.substr(0, dotpos); 00485 string field = target.substr(dotpos + 1); 00486 00487 *at = find_container(container); 00488 if (*at) { 00489 *iter = (*at)->simple_find(field); 00490 } 00491 else { 00492 *iter = attr_map.end(); 00493 } 00494 } 00495 else { 00496 *at = recurrsive_find(target, iter); 00497 } 00498 } 00499 00511 AttrTable * 00512 AttrTable::recurrsive_find(const string &target, Attr_iter *location) 00513 { 00514 Attr_iter i = attr_begin(); 00515 while (i != attr_end()) { 00516 if (target == (*i)->name) { 00517 *location = i; 00518 return this; 00519 } 00520 else if ((*i)->type == Attr_container) { 00521 AttrTable *at = (*i)->attributes->recurrsive_find(target, location); 00522 if (at) 00523 return at; 00524 } 00525 00526 ++i; 00527 } 00528 00529 *location = i; 00530 return 0; 00531 } 00532 00533 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09] 00540 AttrTable::Attr_iter AttrTable::simple_find(const string &target) 00541 { 00542 Attr_iter i; 00543 for (i = attr_map.begin(); i != attr_map.end(); ++i) { 00544 if (target == (*i)->name) { 00545 break; 00546 } 00547 } 00548 return i; 00549 } 00550 00564 AttrTable * 00565 AttrTable::find_container(const string &target) 00566 { 00567 string::size_type dotpos = target.find('.'); 00568 if (dotpos != string::npos) { 00569 string container = target.substr(0, dotpos); 00570 string field = target.substr(dotpos + 1); 00571 00572 AttrTable *at = simple_find_container(container); 00573 return (at) ? at->find_container(field) : 0; 00574 } 00575 else { 00576 return simple_find_container(target); 00577 } 00578 } 00579 00580 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09] 00581 AttrTable * 00582 AttrTable::simple_find_container(const string &target) 00583 { 00584 if (get_name() == target) 00585 return this; 00586 00587 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00588 if (is_container(i) && target == (*i)->name) { 00589 return (*i)->attributes; 00590 } 00591 } 00592 00593 return 0; 00594 } 00595 00603 00605 AttrTable * 00606 AttrTable::get_attr_table(const string &name) 00607 { 00608 return find_container(name); 00609 } 00610 00612 string AttrTable::get_type(const string &name) 00613 { 00614 Attr_iter p = simple_find(name); 00615 return (p != attr_map.end()) ? get_type(p) : (string) ""; 00616 } 00617 00620 AttrType AttrTable::get_attr_type(const string &name) 00621 { 00622 Attr_iter p = simple_find(name); 00623 return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown; 00624 } 00625 00633 unsigned int AttrTable::get_attr_num(const string &name) 00634 { 00635 Attr_iter iter = simple_find(name); 00636 return (iter != attr_map.end()) ? get_attr_num(iter) : 0; 00637 } 00638 00651 vector<string> * 00652 AttrTable::get_attr_vector(const string &name) 00653 { 00654 Attr_iter p = simple_find(name); 00655 return (p != attr_map.end()) ? get_attr_vector(p) : 0; 00656 } 00657 00674 void AttrTable::del_attr(const string &name, int i) 00675 { 00676 #if WWW_ENCODING 00677 string lname = www2id(name); 00678 #else 00679 string lname = remove_space_encoding(name); 00680 #endif 00681 00682 Attr_iter iter = simple_find(lname); 00683 if (iter != attr_map.end()) { 00684 if (i == -1) { // Delete the whole attribute 00685 entry *e = *iter; 00686 attr_map.erase(iter); 00687 delete e; 00688 e = 0; 00689 } 00690 else { // Delete one element from attribute array 00691 // Don't try to delete elements from the vector of values if the 00692 // map is a container! 00693 if ((*iter)->type == Attr_container) 00694 return; 00695 00696 vector<string> *sxp = (*iter)->attr; 00697 00698 assert(i >= 0 && i < (int) sxp->size()); 00699 sxp->erase(sxp->begin() + i); // rm the element 00700 } 00701 } 00702 } 00703 00705 00710 AttrTable::Attr_iter AttrTable::attr_begin() 00711 { 00712 return attr_map.begin(); 00713 } 00714 00718 AttrTable::Attr_iter AttrTable::attr_end() 00719 { 00720 return attr_map.end(); 00721 } 00722 00731 AttrTable::Attr_iter AttrTable::get_attr_iter(int i) 00732 { 00733 return attr_map.begin() + i; 00734 } 00735 00737 string AttrTable::get_name(Attr_iter iter) 00738 { 00739 assert(iter != attr_map.end()); 00740 00741 return (*iter)->name; 00742 } 00743 00745 bool AttrTable::is_container(Attr_iter i) 00746 { 00747 return (*i)->type == Attr_container; 00748 } 00749 00755 AttrTable * 00756 AttrTable::get_attr_table(Attr_iter iter) 00757 { 00758 assert(iter != attr_map.end()); 00759 return (*iter)->type == Attr_container ? (*iter)->attributes : 0; 00760 } 00761 00780 AttrTable::Attr_iter AttrTable::del_attr_table(Attr_iter iter) 00781 { 00782 if ((*iter)->type != Attr_container) 00783 return ++iter; 00784 00785 // the caller intends to delete/reuse the contained AttrTable, 00786 // so zero it out so it doesn't get deleted before we delete the entry 00787 // [mjohnson] 00788 struct entry *e = *iter; 00789 // container no longer has a parent. 00790 if (e->attributes) { 00791 e->attributes->d_parent = 0; 00792 00793 #if NEW_DEL_ATTR_TABLE_BEHAVIOR 00794 delete e->attributes; 00795 #endif 00796 e->attributes = 0; 00797 } 00798 00799 delete e; 00800 00801 return attr_map.erase(iter); 00802 } 00803 00807 string AttrTable::get_type(Attr_iter iter) 00808 { 00809 assert(iter != attr_map.end()); 00810 return AttrType_to_String((*iter)->type); 00811 } 00812 00816 AttrType AttrTable::get_attr_type(Attr_iter iter) 00817 { 00818 return (*iter)->type; 00819 } 00820 00828 unsigned int AttrTable::get_attr_num(Attr_iter iter) 00829 { 00830 assert(iter != attr_map.end()); 00831 return ((*iter)->type == Attr_container) ? (*iter)->attributes->get_size() : (*iter)->attr->size(); 00832 } 00833 00850 string AttrTable::get_attr(Attr_iter iter, unsigned int i) 00851 { 00852 assert(iter != attr_map.end()); 00853 00854 return (*iter)->type == Attr_container ? (string) "None" : (*(*iter)->attr)[i]; 00855 } 00856 00857 string AttrTable::get_attr(const string &name, unsigned int i) 00858 { 00859 Attr_iter p = simple_find(name); 00860 return (p != attr_map.end()) ? get_attr(p, i) : (string) ""; 00861 } 00862 00874 vector<string> * 00875 AttrTable::get_attr_vector(Attr_iter iter) 00876 { 00877 assert(iter != attr_map.end()); 00878 return (*iter)->type != Attr_container ? (*iter)->attr : 0; 00879 } 00880 00881 bool AttrTable::is_global_attribute(Attr_iter iter) 00882 { 00883 assert(iter != attr_map.end()); 00884 if ((*iter)->type == Attr_container) 00885 return (*iter)->attributes->is_global_attribute(); 00886 else 00887 return (*iter)->is_global; 00888 } 00889 00890 void AttrTable::set_is_global_attribute(Attr_iter iter, bool ga) 00891 { 00892 assert(iter != attr_map.end()); 00893 if ((*iter)->type == Attr_container) 00894 (*iter)->attributes->set_is_global_attribute(ga); 00895 else 00896 (*iter)->is_global = ga; 00897 } 00898 00900 00901 // Alias an attribute table. The alias should be added to this object. 00907 void AttrTable::add_container_alias(const string &name, AttrTable *src) 00908 { 00909 #if WWW_ENCODING 00910 string lname = www2id(name); 00911 #else 00912 string lname = remove_space_encoding(name); 00913 #endif 00914 00915 if (simple_find(lname) != attr_end()) 00916 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (2)")); 00917 00918 entry *e = new entry; 00919 e->name = lname; 00920 e->is_alias = true; 00921 e->aliased_to = src->get_name(); 00922 e->type = Attr_container; 00923 00924 e->attributes = src; 00925 00926 attr_map.push_back(e); 00927 } 00928 00941 void AttrTable::add_value_alias(AttrTable *das, const string &name, const string &source) 00942 { 00943 #if WWW_ENCODING 00944 string lname = www2id(name); 00945 #else 00946 string lname = remove_space_encoding(name); 00947 #endif 00948 00949 #if WWW_ENCODING 00950 string lsource = www2id(source); 00951 #else 00952 string lsource = remove_space_encoding(source); 00953 #endif 00954 00955 // find the container that holds source and its (sources's) iterator 00956 // within that container. Search at the uppermost level of the attribute 00957 // object to find values defined `above' the current container. 00958 AttrTable *at; 00959 Attr_iter iter; 00960 das->find(lsource, &at, &iter); 00961 00962 // If source is not found by looking at the topmost level, look in the 00963 // current table (i.e., alias z x where x is in the current container 00964 // won't be found by looking for `x' at the top level). See test case 26 00965 // in das-testsuite. 00966 if (!at || (iter == at->attr_end()) || !*iter) { 00967 find(lsource, &at, &iter); 00968 if (!at || (iter == at->attr_end()) || !*iter) 00969 throw Error(string("Could not find the attribute `") + source + string("' in the attribute object.")); 00970 } 00971 00972 // If we've got a value to alias and it's being added at the top level of 00973 // the DAS, that's an error. 00974 if (at && !at->is_container(iter) && this == das) 00975 throw Error( 00976 string( 00977 "A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS.")); 00978 00979 if (simple_find(lname) != attr_end()) 00980 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (3)")); 00981 00982 entry *e = new entry; 00983 e->name = lname; 00984 e->is_alias = true; 00985 e->aliased_to = lsource; 00986 e->type = get_attr_type(iter); 00987 if (at && e->type == Attr_container) 00988 e->attributes = at->get_attr_table(iter); 00989 else 00990 e->attr = (*iter)->attr; 00991 00992 attr_map.push_back(e); 00993 } 00994 00995 // Deprecated 01014 bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name) 01015 { 01016 add_value_alias(at, alias, name); 01017 return true; 01018 } 01019 01027 bool AttrTable::attr_alias(const string &alias, const string &name) 01028 { 01029 return attr_alias(alias, this, name); 01030 } 01031 01035 void AttrTable::erase() 01036 { 01037 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01038 delete *i; 01039 *i = 0; 01040 } 01041 01042 attr_map.erase(attr_map.begin(), attr_map.end()); 01043 01044 d_name = ""; 01045 } 01046 01047 const string double_quote = "\""; 01048 01049 // This is here as a result of the problem described in ticket #1163 where 01050 // the data handlers are adding quotes to string attributes so the DAS will 01051 // be printed correctly. But that has the affect of adding the quotes to the 01052 // attribute's _value_ not just it's print representation. As part of the fix 01053 // I made the code here add the quotes if the handlers are fixed (but not if 01054 // handlers are still adding them). The other part of 1163 is to fix all of 01055 // the handlers... What this fix means is that attributes whose values really 01056 // do contain bracketing quotes might be misunderstood, since we're assuming 01057 // those quotes were added by the handlers as a hack to get the output 01058 // formatting correct for the DAS. jhrg 7/30/08 01059 01060 static void write_string_attribute_for_das(ostream &out, const string &value, const string &term) 01061 { 01062 if (is_quoted(value)) 01063 out << value << term; 01064 else 01065 out << double_quote << value << double_quote << term; 01066 } 01067 01068 #if 0 01069 static void 01070 write_string_attribute_for_das(FILE *out, const string &value, const string &term) 01071 { 01072 if (is_quoted(value)) 01073 fprintf(out, "%s%s", value.c_str(), term.c_str()); 01074 else 01075 fprintf(out, "\"%s\"%s", value.c_str(), term.c_str()); 01076 } 01077 #endif 01078 01079 // Special treatment for XML: Make sure to escape double quotes when XML is 01080 // printed in a DAS. 01081 static void write_xml_attribute_for_das(ostream &out, const string &value, const string &term) 01082 { 01083 if (is_quoted(value)) 01084 out << escape_double_quotes(value) << term; 01085 else 01086 out << double_quote << escape_double_quotes(value) << double_quote << term; 01087 } 01088 01089 #if 0 01090 static void 01091 write_xml_attribute_for_das(FILE *out, const string &value, const string &term) 01092 { 01093 if (is_quoted(value)) 01094 fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str()); 01095 else 01096 fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str()); 01097 } 01098 #endif 01099 01102 void AttrTable::simple_print(FILE *out, string pad, Attr_iter i, bool dereference) 01103 { 01104 ostringstream oss; 01105 simple_print(oss, pad, i, dereference); 01106 fwrite(oss.str().data(), 1, oss.str().length(), out); 01107 01108 #if 0 01109 switch ((*i)->type) { 01110 case Attr_container: 01111 #if WWW_ENCODING 01112 fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str()); 01113 #else 01114 fprintf(out, "%s%s {\n", pad.c_str(), get_name(i).c_str()); 01115 #endif 01116 (*i)->attributes->print(out, pad + " ", dereference); 01117 01118 fprintf(out, "%s}\n", pad.c_str()); 01119 break; 01120 01121 case Attr_string: { 01122 #if WWW_ENCODING 01123 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str()); 01124 #else 01125 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str()); 01126 #endif 01127 vector<string> *sxp = (*i)->attr; 01128 vector<string>::iterator last = sxp->end() - 1; 01129 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01130 write_string_attribute_for_das(out, *i, ", "); 01131 } 01132 write_string_attribute_for_das(out, *last, ";\n"); 01133 } 01134 break; 01135 01136 case Attr_other_xml: { 01137 #if WWW_ENCODING 01138 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str()); 01139 #else 01140 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str()); 01141 #endif 01142 vector<string> *sxp = (*i)->attr; 01143 vector<string>::iterator last = sxp->end() - 1; 01144 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01145 write_xml_attribute_for_das(out, *i, ", "); 01146 } 01147 write_xml_attribute_for_das(out, *last, ";\n"); 01148 } 01149 break; 01150 01151 default: { 01152 #if WWW_ENCODING 01153 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str()); 01154 #else 01155 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str()); 01156 #endif 01157 01158 vector<string> *sxp = (*i)->attr; 01159 vector<string>::iterator last = sxp->end() - 1; 01160 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01161 fprintf(out, "%s%s", (*i).c_str(), ", "); 01162 } 01163 fprintf(out, "%s%s", (*last).c_str(), ";\n"); 01164 } 01165 break; 01166 } 01167 #endif 01168 } 01169 01172 void AttrTable::simple_print(ostream &out, string pad, Attr_iter i, bool dereference) 01173 { 01174 switch ((*i)->type) { 01175 case Attr_container: 01176 #if WWW_ENCODING 01177 out << pad << id2www(get_name(i)) << " {\n"; 01178 #else 01179 out << pad << add_space_encoding(get_name(i)) << " {\n"; 01180 #endif 01181 (*i)->attributes->print(out, pad + " ", dereference); 01182 out << pad << "}\n"; 01183 break; 01184 01185 case Attr_string: { 01186 #if WWW_ENCODING 01187 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01188 #else 01189 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " "; 01190 #endif 01191 vector<string> *sxp = (*i)->attr; 01192 vector<string>::iterator last = sxp->end() - 1; 01193 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01194 write_string_attribute_for_das(out, *i, ", "); 01195 } 01196 write_string_attribute_for_das(out, *last, ";\n"); 01197 } 01198 break; 01199 01200 case Attr_other_xml: { 01201 #if WWW_ENCODING 01202 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01203 #else 01204 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " "; 01205 #endif 01206 vector<string> *sxp = (*i)->attr; 01207 vector<string>::iterator last = sxp->end() - 1; 01208 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01209 write_xml_attribute_for_das(out, *i, ", "); 01210 } 01211 write_xml_attribute_for_das(out, *last, ";\n"); 01212 } 01213 break; 01214 01215 default: { 01216 #if WWW_ENCODING 01217 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01218 #else 01219 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " "; 01220 #endif 01221 vector<string> *sxp = (*i)->attr; 01222 vector<string>::iterator last = sxp->end() - 1; 01223 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01224 out << *i << ", "; 01225 } 01226 out << *last << ";\n"; 01227 } 01228 break; 01229 } 01230 } 01231 01242 void AttrTable::print(FILE *out, string pad, bool dereference) 01243 { 01244 ostringstream oss; 01245 print(oss, pad, dereference); 01246 fwrite(oss.str().data(), 1, oss.str().length(), out); 01247 01248 #if 0 01249 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01250 if ((*i)->is_alias) { 01251 if (dereference) { 01252 simple_print(out, pad, i, dereference); 01253 } 01254 else { 01255 #if WWW_ENCODING 01256 fprintf(out, "%sAlias %s %s;\n", 01257 pad.c_str(), 01258 id2www(get_name(i)).c_str(), 01259 id2www((*i)->aliased_to).c_str()); 01260 #else 01261 fprintf(out, "%sAlias %s %s;\n", 01262 pad.c_str(), add_space_encoding(get_name(i)).c_str(), add_space_encoding((*i)->aliased_to).c_str()); 01263 01264 #endif 01265 } 01266 } 01267 else { 01268 simple_print(out, pad, i, dereference); 01269 } 01270 } 01271 #endif 01272 } 01273 01284 void AttrTable::print(ostream &out, string pad, bool dereference) 01285 { 01286 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01287 if ((*i)->is_alias) { 01288 if (dereference) { 01289 simple_print(out, pad, i, dereference); 01290 } 01291 else { 01292 #if WWW_ENCODING 01293 out << pad << "Alias " << id2www(get_name(i)) 01294 << " " << id2www((*i)->aliased_to) << ";\n"; 01295 #else 01296 out << pad << "Alias " << add_space_encoding(get_name(i)) << " " 01297 << add_space_encoding((*i)->aliased_to) << ";\n"; 01298 #endif 01299 } 01300 } 01301 else { 01302 simple_print(out, pad, i, dereference); 01303 } 01304 } 01305 } 01306 01312 void AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/) 01313 { 01314 XMLWriter xml(pad); 01315 print_xml_writer(xml); 01316 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out); 01317 01318 #if OLD_XML_MOETHODS 01319 ostringstream oss; 01320 print_xml(oss, pad); 01321 fwrite(oss.str().data(), 1, oss.str().length(), out); 01322 #endif 01323 01324 #if 0 01325 // Why this works: AttrTable is really a hacked class that used to 01326 // implement a single-level set of attributes. Containers 01327 // were added several years later by dropping in the 'entry' structure. 01328 // It's not a class in its own right; instead accessors from AttrTable 01329 // are used to access information from entry. So... the loop below 01330 // actually iterates over the entries of *this* (which is an instance of 01331 // AttrTable). A container is an entry whose sole value is an AttrTable 01332 // instance. 05/19/03 jhrg 01333 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01334 if ((*i)->is_alias) { 01335 fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n", 01336 pad.c_str(), id2xml(get_name(i)).c_str(), 01337 (*i)->aliased_to.c_str()); 01338 01339 } 01340 else if (is_container(i)) { 01341 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n", 01342 pad.c_str(), id2xml(get_name(i)).c_str(), 01343 get_type(i).c_str()); 01344 01345 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/); 01346 01347 fprintf(out, "%s</Attribute>\n", pad.c_str()); 01348 } 01349 else { 01350 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n", 01351 pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str()); 01352 01353 string value_pad = pad + " "; 01354 // Special handling for the OtherXML attribute type - don't escape 01355 // the XML and don't include the <value> element. Note that there 01356 // cannot be an vector of XML things as can be with the other types. 01357 if (get_attr_type(i) == Attr_other_xml) { 01358 if (get_attr_num(i) != 1) 01359 throw Error("OtherXML attributes cannot be vector-valued."); 01360 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str()); 01361 } 01362 else { 01363 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01364 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(), 01365 id2xml(get_attr(i, j)).c_str()); 01366 } 01367 } 01368 fprintf(out, "%s</Attribute>\n", pad.c_str()); 01369 } 01370 } 01371 #endif 01372 } 01373 01377 void AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/) 01378 { 01379 XMLWriter xml(pad); 01380 print_xml_writer(xml); 01381 out << xml.get_doc(); 01382 01383 #if 0 01384 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01385 if ((*i)->is_alias) { 01386 out << pad << "<Alias name=\"" << id2xml(get_name(i)) 01387 << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n"; 01388 01389 } 01390 else if (is_container(i)) { 01391 out << pad << "<Attribute name=\"" << id2xml(get_name(i)) 01392 << "\" type=\"" << get_type(i) << "\">\n"; 01393 01394 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/); 01395 01396 out << pad << "</Attribute>\n"; 01397 } 01398 else { 01399 out << pad << "<Attribute name=\"" << id2xml(get_name(i)) 01400 << "\" type=\"" << get_type(i) << "\">\n"; 01401 01402 string value_pad = pad + " "; 01403 if (get_attr_type(i) == Attr_other_xml) { 01404 if (get_attr_num(i) != 1) 01405 throw Error("OtherXML attributes cannot be vector-valued."); 01406 out << value_pad << get_attr(i, 0) << "\n"; 01407 } 01408 else { 01409 string value_pad = pad + " "; 01410 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01411 out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n"; 01412 } 01413 } 01414 out << pad << "</Attribute>\n"; 01415 } 01416 } 01417 #endif 01418 } 01419 01424 void AttrTable::print_xml_writer(XMLWriter &xml) 01425 { 01426 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01427 if ((*i)->is_alias) { 01428 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Alias") < 0) 01429 throw InternalErr(__FILE__, __LINE__, "Could not write Alias element"); 01430 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", 01431 (const xmlChar*) get_name(i).c_str()) < 0) 01432 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01433 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "Attribute", 01434 (const xmlChar*) (*i)->aliased_to.c_str()) < 0) 01435 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01436 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01437 throw InternalErr(__FILE__, __LINE__, "Could not end Alias element"); 01438 } 01439 else if (is_container(i)) { 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 get_attr_table(i)->print_xml_writer(xml); 01450 01451 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01452 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element"); 01453 } 01454 else { 01455 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0) 01456 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element"); 01457 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", 01458 (const xmlChar*) get_name(i).c_str()) < 0) 01459 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01460 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", 01461 (const xmlChar*) get_type(i).c_str()) < 0) 01462 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01463 01464 if (get_attr_type(i) == Attr_other_xml) { 01465 if (get_attr_num(i) != 1) 01466 throw Error("OtherXML attributes cannot be vector-valued."); 01467 // Replaced xmltextWriterWriteString with xmlTextWriterWriteRaw to keep the 01468 // libxml2 code from escaping the xml (which was breaking all of the inferencing 01469 // code. jhrg 01470 if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) get_attr(i, 0).c_str()) < 0) 01471 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value"); 01472 } 01473 else { 01474 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01475 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "value") < 0) 01476 throw InternalErr(__FILE__, __LINE__, "Could not write value element"); 01477 01478 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) get_attr(i, j).c_str()) < 0) 01479 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value"); 01480 01481 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01482 throw InternalErr(__FILE__, __LINE__, "Could not end value element"); 01483 } 01484 } 01485 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01486 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element"); 01487 } 01488 } 01489 } 01490 01496 void 01497 AttrTable::print_dap4(XMLWriter &xml) 01498 { 01499 print_xml_writer(xml); 01500 } 01501 01509 void AttrTable::dump(ostream &strm) const 01510 { 01511 strm << DapIndent::LMarg << "AttrTable::dump - (" << (void *) this << ")" << endl; 01512 DapIndent::Indent(); 01513 strm << DapIndent::LMarg << "table name: " << d_name << endl; 01514 if (attr_map.size()) { 01515 strm << DapIndent::LMarg << "attributes: " << endl; 01516 DapIndent::Indent(); 01517 Attr_citer i = attr_map.begin(); 01518 Attr_citer ie = attr_map.end(); 01519 for (; i != ie; ++i) { 01520 entry *e = (*i); 01521 string type = AttrType_to_String(e->type); 01522 if (e->is_alias) { 01523 strm << DapIndent::LMarg << "alias: " << e->name << " aliased to: " << e->aliased_to << endl; 01524 } 01525 else if (e->type == Attr_container) { 01526 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl; 01527 DapIndent::Indent(); 01528 e->attributes->dump(strm); 01529 DapIndent::UnIndent(); 01530 } 01531 else { 01532 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl; 01533 DapIndent::Indent(); 01534 strm << DapIndent::LMarg; 01535 vector<string>::const_iterator iter = e->attr->begin(); 01536 vector<string>::const_iterator last = e->attr->end() - 1; 01537 for (; iter != last; ++iter) { 01538 strm << (*iter) << ", "; 01539 } 01540 strm << (*(e->attr->end() - 1)) << endl; 01541 DapIndent::UnIndent(); 01542 } 01543 } 01544 DapIndent::UnIndent(); 01545 } 01546 else { 01547 strm << DapIndent::LMarg << "attributes: empty" << endl; 01548 } 01549 if (d_parent) { 01550 strm << DapIndent::LMarg << "parent table:" << d_name << ":" << (void *) d_parent << endl; 01551 } 01552 else { 01553 strm << DapIndent::LMarg << "parent table: none" << d_name << endl; 01554 } 01555 DapIndent::UnIndent(); 01556 } 01557 01558 } // namespace libdap 01559