![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include "parse.hpp"
00002
00003 #include
00004 #include
00005 #include
00006 #include
00007
00008 using namespace moab;
00009
00010 void tag_syntax( std::ostream& s )
00011 {
00012 s << "Tags are specified as =[value], where the tag value " << std::endl
00013 << "is optional." << std::endl
00014 << std::endl
00015 << "Values of integral types (INTEGER, BIT, and HANDLE) are " << std::endl
00016 << "specified using standard C integer notation (a 0x prefix " << std::endl
00017 << "for hexidecimal, 0 prefix for octal, and no prefix for " << std::endl
00018 << "decimal.) The value of an opaque tag is interpreted as " << std::endl
00019 << "either a integral value or a character string. If the tag " << std::endl
00020 << "value begins with the prefix 0x it will be interpreted as a " << std::endl
00021 << "hexidecimal (base-16) number. If the value does not begin " << std::endl
00022 << "with the 0x prefix, it is interpreted as a character string." << std::endl
00023 << "Characater strings will be padded with null characters as" << std::endl
00024 << "necessary to fill the tag." << std::endl
00025 << "Floating-point (real) values must be specified in base-10." << std::endl
00026 << "C exponential notation (e.g. 1e-10) is accepted." << std::endl
00027 << std::endl
00028 << "If the tag is an array of integral or floating-point values " << std::endl
00029 << "then the tag value must be specified as a comma-separated " << std::endl
00030 << "list, with NO spaces." << std::endl
00031 << std::endl
00032 << "Tags are created with the syntax name=type:size[=default_value]." << std::endl
00033 << "where type is one of {int,double,opaque,handle,bit} and size is " << std::endl
00034 << "the number of values of the specified type, or the number of " << std::endl
00035 << "bytes if the type is 'opaque', A default value for the tag may " << std::endl
00036 << "be specified." << std::endl;
00037 }
00038
00039 // Check endian-ness of platform. Used when parsing numerical
00040 // value for opaque tags.
00041 inline static bool is_platform_little_endian();
00042
00043 // Parse tag value from a string (vals). The passed size
00044 // is the number of values returned by MOAB from tag_get_length.
00045 static void* parse_values( const char* vals, DataType type, int size );
00046
00047 // Parse opque tag data as either a hexidecimal number or
00048 // an ASCII string.
00049 static unsigned char* parse_opaque_value( const char* vals, int size );
00050
00051 // Parse one or more non-opaque tag values in a comma-separated list.
00052 // The passed size is the size returned by MOAB (num values * sizeof(type)).
00053 template < typename T >
00054 T* parse_values_typed( const char* vals, int size );
00055
00056 // Template function to parse a single non-opaque tag value.
00057 // Parses the value in the string pointed to by "iter" and updates
00058 // iter to point passed the parsed value. Returns zero on success.
00059 template < typename T >
00060 int parse_value( const char*& iter, T& value );
00061
00062 // Convert an ASCII hexidecimal digit to its numerical value.
00063 static int hexdigit( char c );
00064
00065 inline static bool is_platform_little_endian()
00066 {
00067 static const unsigned int one = 1;
00068 static const bool little = !*( (char*)&one );
00069 return little;
00070 }
00071
00072 template < typename T >
00073 int parse_value( const char*& iter, T& value )
00074 {
00075 char* endptr;
00076 long parsed_val = strtol( iter, &endptr, 0 );
00077 if( endptr == iter ) return 1;
00078 iter = endptr;
00079
00080 value = (T)parsed_val;
00081 if( (long)value != parsed_val )
00082 {
00083 std::cerr << "Value too large: " << iter << std::endl;
00084 return 2;
00085 }
00086
00087 return 0;
00088 }
00089
00090 template <>
00091 int parse_value< double >( const char*& iter, double& value )
00092 {
00093 char* endptr;
00094 value = strtod( iter, &endptr );
00095 if( endptr == iter ) return 1;
00096 iter = endptr;
00097 return 0;
00098 }
00099
00100 int hexdigit( char c )
00101 {
00102 if( c >= '0' && c <= '9' )
00103 return c - '0';
00104 else if( c >= 'a' && c <= 'f' )
00105 return 10 + c - 'a';
00106 else if( c >= 'A' && c <= 'F' )
00107 return 10 + c - 'A';
00108 else
00109 return -1;
00110 }
00111
00112 unsigned char* parse_opaque_value( const char* vals, int size )
00113 {
00114 unsigned char* data = (unsigned char*)malloc( size );
00115 if( vals[0] && vals[0] == '0' && vals[1] && toupper( vals[1] ) == 'X' )
00116 {
00117 unsigned char *iter, *end;
00118 int step;
00119 if( is_platform_little_endian() )
00120 {
00121 iter = data;
00122 end = data + size;
00123 step = 1;
00124 }
00125 else
00126 {
00127 iter = data + size - 1;
00128 end = data - 1;
00129 step = -1;
00130 }
00131
00132 const char* vals_end = vals + 1;
00133 const char* vals_iter = vals + strlen( vals ) - 1;
00134 for( ; iter != end; iter += step )
00135 {
00136 int less = 0;
00137 int most = 0;
00138 if( vals_iter != vals_end )
00139 {
00140 less = hexdigit( *vals_iter );
00141 --vals_iter;
00142 }
00143 if( vals_iter != vals_end )
00144 {
00145 most = hexdigit( *vals_iter );
00146 --vals_iter;
00147 }
00148 if( less < 0 || most < 0 )
00149 {
00150 std::cerr << "Error parsing hex value: " << vals << std::endl;
00151 free( data );
00152 return 0;
00153 }
00154
00155 *iter = 16 * most + less;
00156 }
00157 }
00158 else
00159 {
00160 memset( data, 0, size );
00161 strcpy( (char*)data, vals + 2 );
00162 }
00163
00164 return data;
00165 }
00166
00167 template < typename T >
00168 T* parse_values_typed( const char* vals, int count )
00169 {
00170 if( !count ) return 0;
00171
00172 T* data = (T*)malloc( count * sizeof( T ) );
00173 T* end = data + count;
00174 if( parse_value< T >( vals, *data ) )
00175 {
00176 free( data );
00177 return 0;
00178 }
00179 for( T* ptr = data + 1; ptr != end; ++ptr )
00180 {
00181 if( *vals != ',' )
00182 {
00183 std::cerr << "Expected ',' separating tag values: " << vals << std::endl;
00184 free( data );
00185 return 0;
00186 }
00187 ++vals;
00188 if( parse_value< T >( vals, *ptr ) )
00189 {
00190 free( data );
00191 return 0;
00192 }
00193 }
00194
00195 return data;
00196 }
00197
00198 void* parse_values( const char* vals, DataType type, int size )
00199 {
00200 switch( type )
00201 {
00202 case MB_TYPE_OPAQUE:
00203 return parse_opaque_value( vals, size );
00204 case MB_TYPE_INTEGER:
00205 return parse_values_typed< int >( vals, size );
00206 case MB_TYPE_DOUBLE:
00207 return parse_values_typed< double >( vals, size );
00208 case MB_TYPE_BIT:
00209 return parse_values_typed< bittype >( vals, size );
00210 case MB_TYPE_HANDLE:
00211 return parse_values_typed< EntityHandle >( vals, size );
00212 default:
00213 std::cerr << "Unknown tag data type: " << (int)type << std::endl;
00214 return 0;
00215 }
00216 }
00217
00218 int parse_tag_spec( char* name, TagSpec& result, Interface* iface )
00219 {
00220 // Separate optional tag value from tag name
00221 char* val = strrchr( name, '=' );
00222 if( val )
00223 {
00224 // zero-length tag name>
00225 if( val == name )
00226 {
00227 std::cerr << "Cannot create tag w/out name: " << name << std::endl;
00228 return 1;
00229 }
00230 *val = '\0';
00231 if( !*++val ) // if name ends with an '=', set val to NULL.
00232 val = 0;
00233 }
00234
00235 // Get tag
00236 ErrorCode rval = iface->tag_get_handle( name, 0, MB_TYPE_OPAQUE, result.handle, MB_TAG_ANY );
00237 if( MB_TAG_NOT_FOUND == rval )
00238 {
00239 std::cerr << "Tag not found: " << name << std::endl;
00240 return 2;
00241 }
00242 else if( MB_SUCCESS != rval )
00243 {
00244 std::cerr << "Error retrieving tag handle: " << name << std::endl;
00245 return 3;
00246 }
00247
00248 // Parse tag value
00249 result.value = 0;
00250 if( val )
00251 {
00252 DataType type;
00253 rval = iface->tag_get_data_type( result.handle, type );
00254 if( MB_SUCCESS != rval )
00255 {
00256 std::cerr << "Error retrieving type for tag: " << name << std::endl;
00257 return 3;
00258 }
00259
00260 int size;
00261 rval = iface->tag_get_length( result.handle, size );
00262 if( MB_SUCCESS != rval )
00263 {
00264 std::cerr << "Error retrieving size for tag: " << name << std::endl;
00265 return 3;
00266 }
00267
00268 result.value = parse_values( val, type, size );
00269 if( !result.value ) return 1;
00270 }
00271
00272 return 0;
00273 }
00274
00275 int parse_tag_create( char* name, TagSpec& result, Interface* iface )
00276 {
00277 // split at '=' signs
00278
00279 char* eq1 = strrchr( name, '=' );
00280 if( !eq1 )
00281 {
00282 std::cerr << "Invalid tag specification: " << name << std::endl;
00283 return 1;
00284 }
00285 *eq1 = '\0';
00286 ++eq1;
00287 char *type_str = eq1, *val = 0;
00288
00289 char* eq2 = strrchr( name, '=' );
00290 if( eq2 )
00291 {
00292 *eq2 = '\0';
00293 ++eq2;
00294 val = ( '\0' == eq1[0] ) ? 0 : eq1;
00295 type_str = eq2;
00296 }
00297
00298 // parse type data
00299 char* size_str = strchr( type_str, ':' );
00300 if( !size_str )
00301 {
00302 std::cerr << "Invalid tag type specification: " << type_str << std::endl;
00303 return 1;
00304 }
00305 *size_str = '\0';
00306 ++size_str;
00307 DataType type;
00308 if( !strcmp( type_str, "int" ) )
00309 {
00310 type = MB_TYPE_INTEGER;
00311 }
00312 else if( !strcmp( type_str, "double" ) )
00313 {
00314 type = MB_TYPE_DOUBLE;
00315 }
00316 else if( !strcmp( type_str, "bit" ) )
00317 {
00318 type = MB_TYPE_BIT;
00319 }
00320 else if( !strcmp( type_str, "handle" ) )
00321 {
00322 type = MB_TYPE_HANDLE;
00323 }
00324 else if( !strcmp( type_str, "opaque" ) )
00325 {
00326 type = MB_TYPE_OPAQUE;
00327 }
00328 else
00329 {
00330 std::cerr << "Invalid tag type specification: " << type_str << std::endl;
00331 return 1;
00332 }
00333 char* end_ptr;
00334 int count = (int)strtol( size_str, &end_ptr, 0 );
00335 if( !*size_str || *end_ptr || count < 1 )
00336 {
00337 std::cerr << "Invalid tag size specification: " << size_str << std::endl;
00338 return 1;
00339 }
00340
00341 // parse default value
00342 result.value = 0;
00343 if( val )
00344 {
00345 result.value = parse_values( val, type, count );
00346 if( !result.value ) return 1;
00347 }
00348
00349 // check if tag exists
00350 if( MB_SUCCESS == iface->tag_get_handle( name, 0, MB_TYPE_OPAQUE, result.handle, MB_TAG_ANY ) )
00351 {
00352 // make sure it matches
00353 DataType etype;
00354 int esize;
00355 if( MB_SUCCESS != iface->tag_get_data_type( result.handle, etype ) ||
00356 MB_SUCCESS != iface->tag_get_length( result.handle, esize ) )
00357 {
00358 std::cerr << "Error accessing properties of tag: " << name << std::endl;
00359 return 3;
00360 }
00361
00362 if( etype != type || esize != count )
00363 {
00364 std::cerr << "Tag already exists with different type: " << name << std::endl;
00365 return 1;
00366 }
00367
00368 std::vector< unsigned char > value( esize );
00369 if( result.value )
00370 {
00371 ErrorCode rval = iface->tag_get_default_value( result.handle, &value[0] );
00372 if( rval != MB_ENTITY_NOT_FOUND && rval != MB_SUCCESS )
00373 {
00374 std::cerr << "Error checking default value of tag: " << name << std::endl;
00375 return 3;
00376 }
00377 else if( rval == MB_ENTITY_NOT_FOUND || memcmp( &value[0], result.value, esize ) )
00378 {
00379 std::cerr << "Tag already exists and default value doesn't match: " << name << std::endl;
00380 return 1;
00381 }
00382 }
00383 }
00384 else
00385 {
00386 ErrorCode rval =
00387 iface->tag_get_handle( name, count, type, result.handle, MB_TAG_SPARSE | MB_TAG_CREAT, result.value );
00388 if( MB_SUCCESS != rval )
00389 {
00390 std::cerr << "Failed to create tag: " << name << std::endl;
00391 return 3;
00392 }
00393 }
00394
00395 return 0;
00396 }