Panda3D
 All Classes Functions Variables Enumerations
dcArrayParameter.cxx
00001 // Filename: dcArrayParameter.cxx
00002 // Created by:  drose (17Jun04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "dcArrayParameter.h"
00016 #include "dcSimpleParameter.h"
00017 #include "dcClassParameter.h"
00018 #include "hashGenerator.h"
00019 
00020 ////////////////////////////////////////////////////////////////////
00021 //     Function: DCArrayParameter::Constructor
00022 //       Access: Public
00023 //  Description: 
00024 ////////////////////////////////////////////////////////////////////
00025 DCArrayParameter::
00026 DCArrayParameter(DCParameter *element_type, const DCUnsignedIntRange &size) :
00027   _element_type(element_type),
00028   _array_size_range(size)
00029 {
00030   set_name(_element_type->get_name());
00031   _element_type->set_name(string());
00032 
00033   _array_size = -1;
00034   if (_array_size_range.has_one_value()) {
00035     _array_size = _array_size_range.get_one_value();
00036   } else {
00037     _has_range_limits = true;
00038   }
00039 
00040   if (_array_size >= 0 && _element_type->has_fixed_byte_size()) {
00041     _has_fixed_byte_size = true;
00042     _fixed_byte_size = _array_size * _element_type->get_fixed_byte_size();
00043     _has_fixed_structure = true;
00044     
00045   } else {
00046     // We only need to store the length bytes if the array has a
00047     // variable size.
00048     _num_length_bytes = 2;
00049   }
00050 
00051   if (_element_type->has_range_limits()) {
00052     _has_range_limits = true;
00053   }
00054 
00055   if (_element_type->has_default_value()) {
00056     _has_default_value = true;
00057   }
00058 
00059   _has_nested_fields = true;
00060   _num_nested_fields = _array_size;
00061   _pack_type = PT_array;
00062 
00063   DCSimpleParameter *simple_type = _element_type->as_simple_parameter();
00064   if (simple_type != (DCSimpleParameter *)NULL) {
00065     if (simple_type->get_type() == ST_char) {
00066       // We make a special case for char[] arrays: these we format as
00067       // a string.  (It will still accept an array of ints packed into
00068       // it.)  We don't make this special case for uint8[] or int8[]
00069       // arrays, although we will accept a string packed in for them.
00070       _pack_type = PT_string;
00071     }
00072   }
00073 }
00074 
00075 ////////////////////////////////////////////////////////////////////
00076 //     Function: DCArrayParameter::Copy Constructor
00077 //       Access: Public
00078 //  Description: 
00079 ////////////////////////////////////////////////////////////////////
00080 DCArrayParameter::
00081 DCArrayParameter(const DCArrayParameter &copy) :
00082   DCParameter(copy),
00083   _element_type(copy._element_type->make_copy()),
00084   _array_size(copy._array_size),
00085   _array_size_range(copy._array_size_range)
00086 {
00087 }
00088 
00089 ////////////////////////////////////////////////////////////////////
00090 //     Function: DCArrayParameter::Destructor
00091 //       Access: Public, Virtual
00092 //  Description: 
00093 ////////////////////////////////////////////////////////////////////
00094 DCArrayParameter::
00095 ~DCArrayParameter() {
00096   delete _element_type;
00097 }
00098 
00099 ////////////////////////////////////////////////////////////////////
00100 //     Function: DCArrayParameter::as_array_parameter
00101 //       Access: Published, Virtual
00102 //  Description: 
00103 ////////////////////////////////////////////////////////////////////
00104 DCArrayParameter *DCArrayParameter::
00105 as_array_parameter() {
00106   return this;
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: DCArrayParameter::as_array_parameter
00111 //       Access: Published, Virtual
00112 //  Description: 
00113 ////////////////////////////////////////////////////////////////////
00114 const DCArrayParameter *DCArrayParameter::
00115 as_array_parameter() const {
00116   return this;
00117 }
00118 
00119 ////////////////////////////////////////////////////////////////////
00120 //     Function: DCArrayParameter::make_copy
00121 //       Access: Published, Virtual
00122 //  Description: 
00123 ////////////////////////////////////////////////////////////////////
00124 DCParameter *DCArrayParameter::
00125 make_copy() const {
00126   return new DCArrayParameter(*this);
00127 }
00128 
00129 ////////////////////////////////////////////////////////////////////
00130 //     Function: DCArrayParameter::is_valid
00131 //       Access: Published, Virtual
00132 //  Description: Returns false if the type is an invalid type
00133 //               (e.g. declared from an undefined typedef), true if
00134 //               it is valid.
00135 ////////////////////////////////////////////////////////////////////
00136 bool DCArrayParameter::
00137 is_valid() const {
00138   return _element_type->is_valid();
00139 }
00140 
00141 ////////////////////////////////////////////////////////////////////
00142 //     Function: DCArrayParameter::get_element_type
00143 //       Access: Published
00144 //  Description: Returns the type of the individual elements of this
00145 //               array.
00146 ////////////////////////////////////////////////////////////////////
00147 DCParameter *DCArrayParameter::
00148 get_element_type() const {
00149   return _element_type;
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: DCArrayParameter::get_array_size
00154 //       Access: Published
00155 //  Description: Returns the fixed number of elements in this array,
00156 //               or -1 if the array may contain a variable number of
00157 //               elements.
00158 ////////////////////////////////////////////////////////////////////
00159 int DCArrayParameter::
00160 get_array_size() const {
00161   return _array_size;
00162 }
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: DCArrayParameter::append_array_specification
00166 //       Access: Public, Virtual
00167 //  Description: Returns the type represented by this_type[size].  
00168 //
00169 //               In the case of a DCArrayParameter, this means it
00170 //               modifies the current type to append the array
00171 //               specification on the innermost type, and returns this
00172 //               same pointer again.
00173 ////////////////////////////////////////////////////////////////////
00174 DCParameter *DCArrayParameter::
00175 append_array_specification(const DCUnsignedIntRange &size) {
00176   if (get_typedef() != (DCTypedef *)NULL) {
00177     // If this was a typedef, wrap it directly.
00178     return new DCArrayParameter(this, size);
00179   }
00180 
00181   // Otherwise, the brackets get applied to the inner type.
00182   _element_type = _element_type->append_array_specification(size);
00183   return this;
00184 }
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: DCArrayParameter::calc_num_nested_fields
00188 //       Access: Public, Virtual
00189 //  Description: This flavor of get_num_nested_fields is used during
00190 //               unpacking.  It returns the number of nested fields to
00191 //               expect, given a certain length in bytes (as read from
00192 //               the get_num_length_bytes() stored in the stream on the
00193 //               pack).  This will only be called if
00194 //               get_num_length_bytes() returns nonzero.
00195 ////////////////////////////////////////////////////////////////////
00196 int DCArrayParameter::
00197 calc_num_nested_fields(size_t length_bytes) const {
00198   if (_element_type->has_fixed_byte_size()) {
00199     return length_bytes / _element_type->get_fixed_byte_size();
00200   }
00201   return -1;
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: DCArrayParameter::get_nested_field
00206 //       Access: Public, Virtual
00207 //  Description: Returns the DCPackerInterface object that represents
00208 //               the nth nested field.  This may return NULL if there
00209 //               is no such field (but it shouldn't do this if n is in
00210 //               the range 0 <= n < get_num_nested_fields()).
00211 ////////////////////////////////////////////////////////////////////
00212 DCPackerInterface *DCArrayParameter::
00213 get_nested_field(int) const {
00214   return _element_type;
00215 }
00216 
00217 ////////////////////////////////////////////////////////////////////
00218 //     Function: DCArrayParameter::validate_num_nested_fields
00219 //       Access: Public, Virtual
00220 //  Description: After a number of fields have been packed via push()
00221 //               .. pack_*() .. pop(), this is called to confirm that
00222 //               the number of nested fields that were added is valid
00223 //               for this type.  This is primarily useful for array
00224 //               types with dynamic ranges that can't validate the
00225 //               number of fields any other way.
00226 ////////////////////////////////////////////////////////////////////
00227 bool DCArrayParameter::
00228 validate_num_nested_fields(int num_nested_fields) const {
00229   bool range_error = false;
00230   _array_size_range.validate(num_nested_fields, range_error);
00231        
00232   return !range_error;
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 //     Function: DCArrayParameter::output_instance
00237 //       Access: Public, Virtual
00238 //  Description: Formats the parameter in the C++-like dc syntax as a
00239 //               typename and identifier.
00240 ////////////////////////////////////////////////////////////////////
00241 void DCArrayParameter::
00242 output_instance(ostream &out, bool brief, const string &prename,
00243                 const string &name, const string &postname) const {
00244   if (get_typedef() != (DCTypedef *)NULL) {
00245     output_typedef_name(out, brief, prename, name, postname);
00246 
00247   } else {
00248     ostringstream strm;
00249     
00250     strm << "[";
00251     _array_size_range.output(strm);
00252     strm << "]";
00253     
00254     _element_type->output_instance(out, brief, prename, name, 
00255                                    postname + strm.str());
00256   }
00257 }
00258 
00259 ////////////////////////////////////////////////////////////////////
00260 //     Function: DCArrayParameter::generate_hash
00261 //       Access: Public, Virtual
00262 //  Description: Accumulates the properties of this type into the
00263 //               hash.
00264 ////////////////////////////////////////////////////////////////////
00265 void DCArrayParameter::
00266 generate_hash(HashGenerator &hashgen) const {
00267   DCParameter::generate_hash(hashgen);
00268   _element_type->generate_hash(hashgen);
00269   _array_size_range.generate_hash(hashgen);
00270 }
00271 
00272 ////////////////////////////////////////////////////////////////////
00273 //     Function: DCArrayParameter::pack_string
00274 //       Access: Published, Virtual
00275 //  Description: Packs the indicated numeric or string value into the
00276 //               stream.
00277 ////////////////////////////////////////////////////////////////////
00278 void DCArrayParameter::
00279 pack_string(DCPackData &pack_data, const string &value,
00280             bool &pack_error, bool &range_error) const {
00281   // We can only pack a string if the array element type is char or
00282   // int8.
00283   DCSimpleParameter *simple_type = _element_type->as_simple_parameter();
00284   if (simple_type == (DCSimpleParameter *)NULL) {
00285     pack_error = true;
00286     return;
00287   }
00288 
00289   size_t string_length = value.length();
00290 
00291   switch (simple_type->get_type()) {
00292   case ST_char:
00293   case ST_uint8:
00294   case ST_int8:
00295     _array_size_range.validate(string_length, range_error);
00296     if (_num_length_bytes != 0) {
00297       nassertv(_num_length_bytes == 2);
00298       do_pack_uint16(pack_data.get_write_pointer(2), string_length);
00299     }
00300     pack_data.append_data(value.data(), string_length);
00301     break;
00302 
00303   default:
00304     pack_error = true;
00305   }
00306 }
00307 
00308 ////////////////////////////////////////////////////////////////////
00309 //     Function: DCArrayParameter::pack_default_value
00310 //       Access: Public, Virtual
00311 //  Description: Packs the arrayParameter's specified default value (or a
00312 //               sensible default if no value is specified) into the
00313 //               stream.  Returns true if the default value is packed,
00314 //               false if the arrayParameter doesn't know how to pack its
00315 //               default value.
00316 ////////////////////////////////////////////////////////////////////
00317 bool DCArrayParameter::
00318 pack_default_value(DCPackData &pack_data, bool &pack_error) const {
00319   // We only want to call up if the DCField can pack the value
00320   // immediately--we don't trust the DCField to generate the default
00321   // value (since it doesn't know how large the minimum length array
00322   // is).
00323   if (_has_default_value && !_default_value_stale) {
00324     return DCField::pack_default_value(pack_data, pack_error);
00325   }
00326 
00327   // If a default value is not specified for a variable-length array,
00328   // the default is the minimum array.
00329   unsigned int minimum_length = 0;
00330   if (!_array_size_range.is_empty()) {
00331     minimum_length = _array_size_range.get_min(0);
00332   }
00333 
00334   DCPacker packer;
00335   packer.begin_pack(this);
00336   packer.push();
00337   for (unsigned int i = 0; i < minimum_length; i++) {
00338     packer.pack_default_value();
00339   }
00340   packer.pop();
00341   if (!packer.end_pack()) {
00342     pack_error = true;
00343   } else {
00344     pack_data.append_data(packer.get_data(), packer.get_length());
00345   }
00346 
00347   return true;
00348 }
00349 
00350 ////////////////////////////////////////////////////////////////////
00351 //     Function: DCArrayParameter::unpack_string
00352 //       Access: Public, Virtual
00353 //  Description: Unpacks the current numeric or string value from the
00354 //               stream.
00355 ////////////////////////////////////////////////////////////////////
00356 void DCArrayParameter::
00357 unpack_string(const char *data, size_t length, size_t &p, string &value,
00358               bool &pack_error, bool &range_error) const {
00359   // We can only unpack a string if the array element type is char or
00360   // int8.
00361   DCSimpleParameter *simple_type = _element_type->as_simple_parameter();
00362   if (simple_type == (DCSimpleParameter *)NULL) {
00363     pack_error = true;
00364     return;
00365   }
00366 
00367   size_t string_length;
00368 
00369   switch (simple_type->get_type()) {
00370   case ST_char:
00371   case ST_uint8:
00372   case ST_int8:
00373     if (_num_length_bytes != 0) {
00374       string_length = do_unpack_uint16(data + p);
00375       p += 2;
00376     } else {
00377       nassertv(_array_size >= 0);
00378       string_length = _array_size;
00379     }
00380     if (p + string_length > length) {
00381       pack_error = true;
00382       return;
00383     }
00384     value.assign(data + p, string_length);
00385     p += string_length;
00386     break;
00387 
00388   default:
00389     pack_error = true;
00390   }
00391 }
00392 
00393 ////////////////////////////////////////////////////////////////////
00394 //     Function: DCArrayParameter::do_check_match
00395 //       Access: Protected, Virtual
00396 //  Description: Returns true if the other interface is bitwise the
00397 //               same as this one--that is, a uint32 only matches a
00398 //               uint32, etc. Names of components, and range limits,
00399 //               are not compared.
00400 ////////////////////////////////////////////////////////////////////
00401 bool DCArrayParameter::
00402 do_check_match(const DCPackerInterface *other) const {
00403   return other->do_check_match_array_parameter(this);
00404 }
00405 
00406 ////////////////////////////////////////////////////////////////////
00407 //     Function: DCArrayParameter::do_check_match_simple_parameter
00408 //       Access: Protected, Virtual
00409 //  Description: Returns true if this field matches the indicated
00410 //               simple parameter, false otherwise.
00411 ////////////////////////////////////////////////////////////////////
00412 bool DCArrayParameter::
00413 do_check_match_simple_parameter(const DCSimpleParameter *other) const {
00414   return ((const DCPackerInterface *)other)->do_check_match_array_parameter(this);
00415 }
00416 
00417 ////////////////////////////////////////////////////////////////////
00418 //     Function: DCArrayParameter::do_check_match_class_parameter
00419 //       Access: Protected, Virtual
00420 //  Description: Returns true if this field matches the indicated
00421 //               class parameter, false otherwise.
00422 ////////////////////////////////////////////////////////////////////
00423 bool DCArrayParameter::
00424 do_check_match_class_parameter(const DCClassParameter *other) const {
00425   return ((const DCPackerInterface *)other)->do_check_match_array_parameter(this);
00426 }
00427 
00428 ////////////////////////////////////////////////////////////////////
00429 //     Function: DCArrayParameter::do_check_match_array_parameter
00430 //       Access: Protected, Virtual
00431 //  Description: Returns true if this field matches the indicated
00432 //               array parameter, false otherwise.
00433 ////////////////////////////////////////////////////////////////////
00434 bool DCArrayParameter::
00435 do_check_match_array_parameter(const DCArrayParameter *other) const {
00436   if (_array_size != other->_array_size) {
00437     return false;
00438   }
00439   return _element_type->check_match(other->_element_type);
00440 }
 All Classes Functions Variables Enumerations