libdap
Updated for version 3.17.0
|
00001 00002 // -*- mode: c++; c-basic-offset:4 -*- 00003 00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00005 // Access Protocol. 00006 00007 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00008 // Author: James Gallagher <jgallagher@opendap.org> 00009 // 00010 // This library is free software; you can redistribute it and/or 00011 // modify it under the terms of the GNU Lesser General Public 00012 // License as published by the Free Software Foundation; either 00013 // version 2.1 of the License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00023 // 00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00025 00026 // (c) COPYRIGHT URI/MIT 1994-1999 00027 // Please read the full copyright statement in the file COPYRIGHT_URI. 00028 // 00029 // Authors: 00030 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00031 00032 // Implementation for Array. 00033 // 00034 // jhrg 9/13/94 00035 00036 #include "config.h" 00037 00038 // #define DODS_DEBUG 00039 00040 #include <algorithm> 00041 #include <functional> 00042 #include <sstream> 00043 00044 #include "Array.h" 00045 00046 #include "D4Attributes.h" 00047 #include "DMR.h" 00048 #include "D4Dimensions.h" 00049 #include "D4Maps.h" 00050 #include "D4Group.h" 00051 #include "D4EnumDefs.h" 00052 #include "D4Enum.h" 00053 #include "XMLWriter.h" 00054 00055 #include "util.h" 00056 #include "debug.h" 00057 #include "InternalErr.h" 00058 #include "escaping.h" 00059 00060 using namespace std; 00061 00062 namespace libdap { 00063 00064 Array::dimension::dimension(D4Dimension *d) : dim(d), use_sdim_for_slice(true) 00065 { 00066 size = d->size(); 00067 name = d->name(); 00068 00069 start = 0; 00070 stop = size - 1; 00071 stride = 1; 00072 c_size = size; 00073 } 00074 00075 void 00076 Array::_duplicate(const Array &a) 00077 { 00078 _shape = a._shape; 00079 00080 // Deep copy the Maps if they are being used. 00081 if (a.d_maps) { 00082 d_maps = new D4Maps(*(a.d_maps)); 00083 } 00084 else { 00085 d_maps = 0; 00086 } 00087 // d_maps = a.d_maps ? new D4Maps(*(a.d_maps)) : 0; 00088 } 00089 00090 // The first method of calculating length works when only one dimension is 00091 // constrained and you want the others to appear in total. This is important 00092 // when selecting from grids since users may not select from all dimensions 00093 // in which case that means they want the whole thing. Array projection 00094 // should probably work this way too, but it doesn't. 9/21/2001 jhrg 00095 00102 void 00103 Array::update_length(int) 00104 { 00105 int length = 1; 00106 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00107 #if 0 00108 // If the size of any dimension is zero, then the array is not 00109 // capable of storing any values. jhrg 1/28/16 00110 length *= (*i).c_size > 0 ? (*i).c_size : 1; 00111 #endif 00112 length *= (*i).c_size; 00113 } 00114 00115 set_length(length); 00116 } 00117 00118 // Construct an instance of Array. The (BaseType *) is assumed to be 00119 // allocated using new - The dtor for Vector will delete this object. 00120 00136 Array::Array(const string &n, BaseType *v, bool is_dap4 /* default:false */) 00137 : Vector(n, 0, dods_array_c, is_dap4), d_maps(0) 00138 { 00139 add_var(v); // Vector::add_var() stores null if v is null 00140 } 00141 00155 Array::Array(const string &n, const string &d, BaseType *v, bool is_dap4 /* default:false */) 00156 : Vector(n, d, 0, dods_array_c, is_dap4), d_maps(0) 00157 { 00158 add_var(v); // Vector::add_var() stores null if v is null 00159 } 00160 00162 Array::Array(const Array &rhs) : Vector(rhs) 00163 { 00164 _duplicate(rhs); 00165 } 00166 00168 Array::~Array() 00169 { 00170 delete d_maps; 00171 } 00172 00173 BaseType * 00174 Array::ptr_duplicate() 00175 { 00176 return new Array(*this); 00177 } 00178 00179 Array & 00180 Array::operator=(const Array &rhs) 00181 { 00182 if (this == &rhs) 00183 return *this; 00184 00185 dynamic_cast<Vector &>(*this) = rhs; 00186 00187 _duplicate(rhs); 00188 00189 return *this; 00190 } 00191 00192 BaseType * 00193 Array::transform_to_dap4(D4Group *root, Constructor */*container*/) 00194 { 00195 Array *dest = static_cast<Array*>(ptr_duplicate()); 00196 00197 // Process the Array's dimensions, making D4 shared dimensions for 00198 // D2 dimensions that are named. If there is just a size, don't make 00199 // a D4Dimension (In DAP4 you cannot share a dimension unless it has 00200 // a name). jhrg 3/18/14 00201 00202 D4Dimensions *dims = root->dims(); 00203 for (Array::Dim_iter d = dest->dim_begin(), e = dest->dim_end(); d != e; ++d) { 00204 if (!(*d).name.empty()) { 00205 // If a D4Dimension with the name already exists, use it. 00206 D4Dimension *d4_dim = dims->find_dim((*d).name); 00207 if (!d4_dim) { 00208 d4_dim = new D4Dimension((*d).name, (*d).size); 00209 dims->add_dim_nocopy(d4_dim); 00210 } 00211 // TODO Revisit this decision. jhrg 3/18/14 00212 // ...in case the name/size are different, make a unique D4Dimension 00213 // but don't fiddle with the name. Not sure I like this idea, so I'm 00214 // making the case explicit (could be rolled in to the block above). 00215 // jhrg 3/18/14 00216 // 00217 // This is causing problems in the FITS handler because there are cases 00218 // where two arrays have dimensions with the same name but different 00219 // sizes. The deserializing code is using the first size listed, which is 00220 // wrong in some cases. I'm going to try making this new D4Dimension using 00221 // the dim name along with the variable name. jhrg 8/15/14 00222 else if (d4_dim->size() != (unsigned long) (*d).size) { 00223 d4_dim = new D4Dimension((*d).name + "_" + name(), (*d).size); 00224 dims->add_dim_nocopy(d4_dim); 00225 } 00226 // At this point d4_dim's name and size == those of (*d) so just set 00227 // the D4Dimension pointer so it matches the one in the D4Group. 00228 (*d).dim = d4_dim; 00229 } 00230 } 00231 00232 // Copy the D2 attributes to D4 Attributes 00233 dest->attributes()->transform_to_dap4(get_attr_table()); 00234 00235 dest->set_is_dap4(true); 00236 00237 return dest; 00238 } 00239 00251 void 00252 Array::update_dimension_pointers(D4Dimensions *old_dims, D4Dimensions *new_dims) 00253 { 00254 std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end(); 00255 while (i != e) { 00256 D4Dimensions::D4DimensionsIter old_i = old_dims->dim_begin(), old_e = old_dims->dim_end(); 00257 while (old_i != old_e) { 00258 if ((*i).dim == *old_i) { 00259 (*i).dim = new_dims->find_dim((*old_i)->name()); 00260 } 00261 ++old_i; 00262 } 00263 00264 ++i; 00265 } 00266 } 00267 00292 void 00293 Array::add_var(BaseType *v, Part) 00294 { 00295 // If 'v' is an Array, add the template instance to this object and 00296 // then copy the dimension information. Odd semantics; I wonder if this 00297 //is ever used. jhrg 6/13/12 00298 if (v && v->type() == dods_array_c) { 00299 Array *a = static_cast<Array*>(v); 00300 Vector::add_var(a->var()); 00301 00302 Dim_iter i = a->dim_begin(); 00303 Dim_iter i_end = a->dim_end(); 00304 while (i != i_end) { 00305 append_dim(a->dimension_size(i), a->dimension_name(i)); 00306 ++i; 00307 } 00308 } 00309 else { 00310 Vector::add_var(v); 00311 } 00312 } 00313 00314 void 00315 Array::add_var_nocopy(BaseType *v, Part) 00316 { 00317 // If 'v' is an Array, add the template instance to this object and 00318 // then copy the dimension information. Odd semantics; I wonder if this 00319 //is ever used. jhrg 6/13/12 00320 if (v && v->type() == dods_array_c) { 00321 Array &a = dynamic_cast<Array&>(*v); 00322 Vector::add_var_nocopy(a.var()); 00323 Dim_iter i = a.dim_begin(); 00324 Dim_iter i_end = a.dim_end(); 00325 while (i != i_end) { 00326 append_dim(a.dimension_size(i), a.dimension_name(i)); 00327 ++i; 00328 } 00329 } 00330 else { 00331 Vector::add_var_nocopy(v); 00332 } 00333 } 00334 00346 void 00347 Array::append_dim(int size, const string &name) 00348 { 00349 dimension d(size, www2id(name)); 00350 _shape.push_back(d); 00351 00352 update_length(); 00353 } 00354 00355 void 00356 Array::append_dim(D4Dimension *dim) 00357 { 00358 dimension d(/*dim->size(), www2id(dim->name()),*/ dim); 00359 _shape.push_back(d); 00360 00361 update_length(); 00362 } 00363 00369 void 00370 Array::prepend_dim(int size, const string& name/* = "" */) 00371 { 00372 dimension d(size, www2id(name)); 00373 // Shifts the whole array, but it's tiny in general 00374 _shape.insert(_shape.begin(), d); 00375 00376 update_length(); // the number is ignored... 00377 } 00378 00379 void 00380 Array::prepend_dim(D4Dimension *dim) 00381 { 00382 dimension d(/*dim->size(), www2id(dim->name()),*/ dim); 00383 // Shifts the whole array, but it's tiny in general 00384 _shape.insert(_shape.begin(), d); 00385 00386 update_length(); // the number is ignored... 00387 } 00388 00392 void 00393 Array::clear_all_dims() 00394 { 00395 _shape.clear(); 00396 } 00403 void 00404 Array::reset_constraint() 00405 { 00406 set_length(-1); 00407 00408 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) { 00409 (*i).start = 0; 00410 (*i).stop = (*i).size - 1; 00411 (*i).stride = 1; 00412 (*i).c_size = (*i).size; 00413 00414 update_length(); 00415 } 00416 } 00417 00418 00428 void 00429 Array::clear_constraint() 00430 { 00431 reset_constraint(); 00432 } 00433 00434 // Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n 00435 // is explicit. 00436 static const char *array_sss = \ 00437 "Invalid constraint parameters: At least one of the start, stride or stop \n\ 00438 specified do not match the array variable."; 00439 00460 void 00461 Array::add_constraint(Dim_iter i, int start, int stride, int stop) 00462 { 00463 dimension &d = *i ; 00464 00465 // if stop is -1, set it to the array's max element index 00466 // jhrg 12/20/12 00467 if (stop == -1) 00468 stop = d.size - 1; 00469 00470 // Check for bad constraints. 00471 // Jose Garcia 00472 // Usually invalid data for a constraint is the user's mistake 00473 // because they build a wrong URL in the client side. 00474 if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0) 00475 throw Error(malformed_expr, array_sss); 00476 00477 if (((stop - start) / stride + 1) > d.size) 00478 throw Error(malformed_expr, array_sss); 00479 00480 d.start = start; 00481 d.stop = stop; 00482 d.stride = stride; 00483 00484 d.c_size = (stop - start) / stride + 1; 00485 00486 DBG(cerr << "add_constraint: c_size = " << d.c_size << endl); 00487 00488 update_length(); 00489 00490 d.use_sdim_for_slice = false; 00491 } 00492 00493 void 00494 Array::add_constraint(Dim_iter i, D4Dimension *dim) 00495 { 00496 dimension &d = *i ; 00497 00498 if (dim->constrained()) 00499 add_constraint(i, dim->c_start(), dim->c_stride(), dim->c_stop()); 00500 00501 dim->set_used_by_projected_var(true); 00502 00503 // In this case the value below overrides the value for use_sdim_for_slice 00504 // set in the above call. jhrg 12/20/13 00505 d.use_sdim_for_slice = true; 00506 } 00507 00509 Array::Dim_iter 00510 Array::dim_begin() 00511 { 00512 return _shape.begin() ; 00513 } 00514 00516 Array::Dim_iter 00517 Array::dim_end() 00518 { 00519 return _shape.end() ; 00520 } 00521 00522 //TODO Many of these methods take a bool parameter that serves no use; remove. 00523 00532 unsigned int 00533 Array::dimensions(bool /*constrained*/) 00534 { 00535 return _shape.size(); 00536 } 00537 00555 int 00556 Array::dimension_size(Dim_iter i, bool constrained) 00557 { 00558 int size = 0; 00559 00560 if (!_shape.empty()) { 00561 if (constrained) 00562 size = (*i).c_size; 00563 else 00564 size = (*i).size; 00565 } 00566 00567 return size; 00568 } 00569 00588 int 00589 Array::dimension_start(Dim_iter i, bool /*constrained*/) 00590 { 00591 return (!_shape.empty()) ? (*i).start : 0; 00592 } 00593 00612 int 00613 Array::dimension_stop(Dim_iter i, bool /*constrained*/) 00614 { 00615 return (!_shape.empty()) ? (*i).stop : 0; 00616 } 00617 00637 int 00638 Array::dimension_stride(Dim_iter i, bool /*constrained*/) 00639 { 00640 return (!_shape.empty()) ? (*i).stride : 0; 00641 } 00642 00653 string 00654 Array::dimension_name(Dim_iter i) 00655 { 00656 // Jose Garcia 00657 // Since this method is public, it is possible for a user 00658 // to call it before the Array object has been properly set 00659 // this will cause an exception which is the user's fault. 00660 // (User in this context is the developer of the surrogate library.) 00661 if (_shape.empty()) 00662 throw InternalErr(__FILE__, __LINE__, 00663 "*This* array has no dimensions."); 00664 return (*i).name; 00665 } 00666 00667 D4Dimension * 00668 Array::dimension_D4dim(Dim_iter i) 00669 { 00670 return (!_shape.empty()) ? (*i).dim : 0; 00671 } 00672 00673 D4Maps * 00674 Array::maps() 00675 { 00676 if (!d_maps) d_maps = new D4Maps(this); // init with this as parent 00677 return d_maps; 00678 } 00679 00680 #if 0 00681 00687 unsigned int Array::width(bool constrained) const 00688 { 00689 00690 if (constrained) { 00691 // This preserves the original method's semantics when we ask for the 00692 // size of the constrained array but no constraint has been applied. 00693 // In this case, length will be -1. Wrong, I know... 00694 return length() * var()->width(constrained); 00695 } 00696 else { 00697 int length = 1; 00698 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) { 00699 length *= dimension_size(i, false); 00700 } 00701 return length * var()->width(false); 00702 } 00703 } 00704 #endif 00705 00706 class PrintD4ArrayDimXMLWriter: public unary_function<Array::dimension&, void> { 00707 XMLWriter &xml; 00708 // Was this variable constrained using local/direct slicing? i.e., is d_local_constraint set? 00709 // If so, don't use shared dimensions; instead emit Dim elements that are anonymous. 00710 bool d_constrained; 00711 public: 00712 00713 PrintD4ArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { } 00714 00715 void operator()(Array::dimension &d) 00716 { 00717 // This duplicates code in D4Dimensions (where D4Dimension::print_dap4() is defined 00718 // because of the need to print the constrained size of a dimension. I think that 00719 // the constraint information has to be kept here and not in the dimension (since they 00720 // are shared dims). Could hack print_dap4() to take the constrained size, however. 00721 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dim") < 0) 00722 throw InternalErr(__FILE__, __LINE__, "Could not write Dim element"); 00723 00724 string name = (d.dim) ? d.dim->fully_qualified_name() : d.name; 00725 // If there is a name, there must be a Dimension (named dimension) in scope 00726 // so write its name but not its size. 00727 if (!d_constrained && !name.empty()) { 00728 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str()) 00729 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00730 } 00731 else if (d.use_sdim_for_slice) { 00732 assert(!name.empty()); 00733 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str()) 00734 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00735 } 00736 else { 00737 ostringstream size; 00738 size << (d_constrained ? d.c_size : d.size); 00739 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", 00740 (const xmlChar*) size.str().c_str()) < 0) 00741 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00742 } 00743 00744 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 00745 throw InternalErr(__FILE__, __LINE__, "Could not end Dim element"); 00746 } 00747 }; 00748 00749 class PrintD4ConstructorVarXMLWriter: public unary_function<BaseType*, void> { 00750 XMLWriter &xml; 00751 bool d_constrained; 00752 public: 00753 PrintD4ConstructorVarXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { } 00754 00755 void operator()(BaseType *btp) 00756 { 00757 btp->print_dap4(xml, d_constrained); 00758 } 00759 }; 00760 00761 class PrintD4MapXMLWriter: public unary_function<D4Map*, void> { 00762 XMLWriter &xml; 00763 00764 public: 00765 PrintD4MapXMLWriter(XMLWriter &xml) : xml(xml) { } 00766 00767 void operator()(D4Map *m) 00768 { 00769 m->print_dap4(xml); 00770 } 00771 }; 00772 00778 void 00779 Array::print_dap4(XMLWriter &xml, bool constrained /* default: false*/) 00780 { 00781 if (constrained && !send_p()) return; 00782 00783 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) var()->type_name().c_str()) < 0) 00784 throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " element"); 00785 00786 if (!name().empty()) 00787 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0) 00788 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00789 00790 // Hack job... Copied from D4Enum::print_xml_writer. jhrg 11/12/13 00791 if (var()->type() == dods_enum_c) { 00792 D4Enum *e = static_cast<D4Enum*>(var()); 00793 string path = e->enumeration()->name(); 00794 if (e->enumeration()->parent()) { 00795 // print the FQN for the enum def; D4Group::FQN() includes the trailing '/' 00796 path = static_cast<D4Group*>(e->enumeration()->parent()->parent())->FQN() + path; 00797 } 00798 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*)path.c_str()) < 0) 00799 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum"); 00800 } 00801 00802 if (prototype()->is_constructor_type()) { 00803 Constructor &c = static_cast<Constructor&>(*prototype()); 00804 for_each(c.var_begin(), c.var_end(), PrintD4ConstructorVarXMLWriter(xml, constrained)); 00805 // bind2nd(mem_fun_ref(&BaseType::print_dap4), xml)); 00806 } 00807 00808 // Drop the local_constraint which is per-array and use a per-dimension on instead 00809 for_each(dim_begin(), dim_end(), PrintD4ArrayDimXMLWriter(xml, constrained)); 00810 00811 attributes()->print_dap4(xml); 00812 00813 for_each(maps()->map_begin(), maps()->map_end(), PrintD4MapXMLWriter(xml)); 00814 00815 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 00816 throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element"); 00817 } 00818 00836 void 00837 Array::print_decl(FILE *out, string space, bool print_semi, 00838 bool constraint_info, bool constrained) 00839 { 00840 ostringstream oss; 00841 print_decl(oss, space, print_semi, constraint_info, constrained); 00842 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 00843 } 00844 00862 void 00863 Array::print_decl(ostream &out, string space, bool print_semi, 00864 bool constraint_info, bool constrained) 00865 { 00866 if (constrained && !send_p()) 00867 return; 00868 00869 // print it, but w/o semicolon 00870 var()->print_decl(out, space, false, constraint_info, constrained); 00871 00872 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00873 out << "[" ; 00874 if ((*i).name != "") { 00875 out << id2www((*i).name) << " = " ; 00876 } 00877 if (constrained) { 00878 out << (*i).c_size << "]" ; 00879 } 00880 else { 00881 out << (*i).size << "]" ; 00882 } 00883 } 00884 00885 if (print_semi) { 00886 out << ";\n" ; 00887 } 00888 } 00889 00893 void 00894 Array::print_xml(FILE *out, string space, bool constrained) 00895 { 00896 XMLWriter xml(space); 00897 print_xml_writer_core(xml, constrained, "Array"); 00898 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out); 00899 } 00900 00904 void 00905 Array::print_xml(ostream &out, string space, bool constrained) 00906 { 00907 XMLWriter xml(space); 00908 print_xml_writer_core(xml, constrained, "Array"); 00909 out << xml.get_doc(); 00910 } 00911 00915 void 00916 Array::print_as_map_xml(FILE *out, string space, bool constrained) 00917 { 00918 XMLWriter xml(space); 00919 print_xml_writer_core(xml, constrained, "Map"); 00920 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out); 00921 } 00922 00926 void 00927 Array::print_as_map_xml(ostream &out, string space, bool constrained) 00928 { 00929 XMLWriter xml(space); 00930 print_xml_writer_core(xml, constrained, "Map"); 00931 out << xml.get_doc(); 00932 } 00933 00937 void 00938 Array::print_xml_core(FILE *out, string space, bool constrained, string tag) 00939 { 00940 XMLWriter xml(space); 00941 print_xml_writer_core(xml, constrained, tag); 00942 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out); 00943 } 00944 00948 void 00949 Array::print_xml_core(ostream &out, string space, bool constrained, string tag) 00950 { 00951 XMLWriter xml(space); 00952 print_xml_writer_core(xml, constrained, tag); 00953 out << xml.get_doc(); 00954 } 00955 00956 void 00957 Array::print_xml_writer(XMLWriter &xml, bool constrained) 00958 { 00959 print_xml_writer_core(xml, constrained, "Array"); 00960 } 00961 00962 void 00963 Array::print_as_map_xml_writer(XMLWriter &xml, bool constrained) 00964 { 00965 print_xml_writer_core(xml, constrained, "Map"); 00966 } 00967 00968 class PrintArrayDimXMLWriter : public unary_function<Array::dimension&, void> 00969 { 00970 XMLWriter &xml; 00971 bool d_constrained; 00972 public: 00973 PrintArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) {} 00974 00975 void operator()(Array::dimension &d) 00976 { 00977 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"dimension") < 0) 00978 throw InternalErr(__FILE__, __LINE__, "Could not write dimension element"); 00979 00980 if (!d.name.empty()) 00981 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d.name.c_str()) < 0) 00982 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00983 00984 ostringstream size; 00985 size << (d_constrained ? d.c_size : d.size); 00986 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", (const xmlChar*)size.str().c_str()) < 0) 00987 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00988 00989 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 00990 throw InternalErr(__FILE__, __LINE__, "Could not end dimension element"); 00991 } 00992 }; 00993 00994 void 00995 Array::print_xml_writer_core(XMLWriter &xml, bool constrained, string tag) 00996 { 00997 if (constrained && !send_p()) 00998 return; 00999 01000 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)tag.c_str()) < 0) 01001 throw InternalErr(__FILE__, __LINE__, "Could not write " + tag + " element"); 01002 01003 if (!name().empty()) 01004 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0) 01005 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01006 01007 get_attr_table().print_xml_writer(xml); 01008 01009 BaseType *btp = var(); 01010 string tmp_name = btp->name(); 01011 btp->set_name(""); 01012 btp->print_xml_writer(xml, constrained); 01013 btp->set_name(tmp_name); 01014 01015 for_each(dim_begin(), dim_end(), PrintArrayDimXMLWriter(xml, constrained)); 01016 01017 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01018 throw InternalErr(__FILE__, __LINE__, "Could not end " + tag + " element"); 01019 } 01020 01032 unsigned int 01033 Array::print_array(FILE *out, unsigned int index, unsigned int dims, 01034 unsigned int shape[]) 01035 { 01036 ostringstream oss; 01037 unsigned int i = print_array(oss, index, dims, shape); 01038 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 01039 01040 return i; 01041 } 01042 01054 unsigned int Array::print_array(ostream &out, unsigned int index, unsigned int dims, unsigned int shape[]) 01055 { 01056 if (dims == 1) { 01057 out << "{"; 01058 01059 // Added test in case this method is passed an array with no elements. jhrg 1/27/16 01060 if (shape[0] >= 1) { 01061 for (unsigned i = 0; i < shape[0] - 1; ++i) { 01062 var(index++)->print_val(out, "", false); 01063 out << ", "; 01064 } 01065 var(index++)->print_val(out, "", false); 01066 } 01067 01068 out << "}"; 01069 01070 return index; 01071 } 01072 else { 01073 out << "{"; 01074 // Fixed an off-by-one error in the following loop. Since the array 01075 // length is shape[dims-1]-1 *and* since we want one less dimension 01076 // than that, the correct limit on this loop is shape[dims-2]-1. From 01077 // Todd Karakasian. 01078 // 01079 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg 01080 // 9/12/96. 01081 // 01082 // For arrays that hold zero values but have rank > 1, the print out 01083 // may look a little odd (e.g., x[4][0] will print as { {}, {}, {}, {} }) 01084 // but it's not wrong and this is really for debugging mostly. jhrg 1/28/16 01085 if (shape[0] > 0) { 01086 for (unsigned i = 0; i < shape[0] - 1; ++i) { 01087 index = print_array(out, index, dims - 1, shape + 1); 01088 out << ","; 01089 } 01090 01091 index = print_array(out, index, dims - 1, shape + 1); 01092 } 01093 01094 out << "}"; 01095 01096 return index; 01097 } 01098 } 01099 01100 void 01101 Array::print_val(FILE *out, string space, bool print_decl_p) 01102 { 01103 ostringstream oss; 01104 print_val(oss, space, print_decl_p); 01105 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 01106 } 01107 01108 void 01109 Array::print_val(ostream &out, string space, bool print_decl_p) 01110 { 01111 // print the declaration if print decl is true. 01112 // for each dimension, 01113 // for each element, 01114 // print the array given its shape, number of dimensions. 01115 // Add the `;' 01116 01117 if (print_decl_p) { 01118 print_decl(out, space, false, false, false); 01119 out << " = " ; 01120 } 01121 01122 unsigned int *shape = new unsigned int[dimensions(true)]; 01123 unsigned int index = 0; 01124 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i) 01125 shape[index++] = dimension_size(i, true); 01126 01127 print_array(out, 0, dimensions(true), shape); 01128 01129 delete [] shape; shape = 0; 01130 01131 if (print_decl_p) { 01132 out << ";\n" ; 01133 } 01134 } 01135 01145 bool 01146 Array::check_semantics(string &msg, bool) 01147 { 01148 bool sem = BaseType::check_semantics(msg) && !_shape.empty(); 01149 01150 if (!sem) 01151 msg = "An array variable must have dimensions"; 01152 01153 return sem; 01154 } 01155 01164 void 01165 Array::dump(ostream &strm) const 01166 { 01167 strm << DapIndent::LMarg << "Array::dump - (" 01168 << (void *)this << ")" << endl ; 01169 DapIndent::Indent() ; 01170 Vector::dump(strm) ; 01171 strm << DapIndent::LMarg << "shape:" << endl ; 01172 DapIndent::Indent() ; 01173 Dim_citer i = _shape.begin() ; 01174 Dim_citer ie = _shape.end() ; 01175 unsigned int dim_num = 0 ; 01176 for (; i != ie; i++) { 01177 strm << DapIndent::LMarg << "dimension " << dim_num++ << ":" 01178 << endl ; 01179 DapIndent::Indent() ; 01180 strm << DapIndent::LMarg << "name: " << (*i).name << endl ; 01181 strm << DapIndent::LMarg << "size: " << (*i).size << endl ; 01182 strm << DapIndent::LMarg << "start: " << (*i).start << endl ; 01183 strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ; 01184 strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ; 01185 strm << DapIndent::LMarg << "constrained size: " << (*i).c_size 01186 << endl ; 01187 DapIndent::UnIndent() ; 01188 } 01189 DapIndent::UnIndent() ; 01190 DapIndent::UnIndent() ; 01191 } 01192 01193 } // namespace libdap 01194