Panda3D
|
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 ©) : 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 }