Vince schrieb:
I am reading files(BYTE array) on a smart card and I need to associate
to each chunk some data and some type.
The card can't be that smart when it only allows for 10-character names
(or less than that if the name requires a multibyte encoding) - SCNR ;)
But seriously, what would you think if you had a long name and someone
decided it's okay to truncate it for the sake of saving a few bytes? I
think it's insulting.
[rationale snipped]
So finally I have an array like this
------------------------------
|0|1|2|3|4|5|6|7|8|9|10|11|12|
------------------------------
< name >< age >
So I associate the name tag to offset 0 to 8 and the type is a string
and age to offset 9 to 12 as a numeric.
I need after to be able to do
strname = myarray.GetString("name");
or nAge = myarray.GetNumeric("age");
Okay, somehow I feel like giving a complete example :-)
#include <cassert>
#include <iostream>
#include <limits>
#include <string>
#include <vector>
typedef std::vector< unsigned char > card_data;
unsigned char extract( const card_data& data, size_t offset,
size_t bits )
{
assert( data.size() >= ( offset + bits + 7 ) / 8 );
// grab a byte (or less) from an arbitrary bit offset into data
unsigned char result =
( data[ offset / 8 ] << offset % 8 ) & ( 0xff << offset % 8 );
if ( bits > 8 - offset % 8 )
result |= ( ( data[ offset / 8 + 1 ] >> ( 8 - offset % 8 ) )
& ( 0xff >> ( 8 - offset % 8 ) ) );
return result >> ( 8 - bits % 8 ) % 8;
}
std::string get_string( const card_data& data, size_t offset,
size_t length )
{
std::string result;
for ( card_data::size_type i = 0; i < ( length + 7 ) / 8; ++i )
{
if ( char c = extract( data, 8 * i + offset,
std::min( length - 8 * i, 8u ) ) )
result += c;
else break;
}
return result;
}
template< typename T >
T get_numeric( const card_data& data, size_t offset, size_t length )
{
assert( ( length + 7 ) / 8 <= sizeof( T ) );
T result = 0;
// Assuming big-endian bit order.
// Take care to handle other formats properly
for ( size_t i = 0; i < ( length + 7 ) / 8; ++i )
result |= extract( data, 8 * i + offset,
std::min( length - 8 * i, 8u ) )
<< ( length - std::min( 8 * ( i + 1 ), length ) );
// sign-extend if needed
if ( std::numeric_limits< T >::is_signed &&
result & ( 1 << ( length - 1 ) ) )
result |= T( -1 ) << length;
return result;
}
int main()
{
card_data test;
// This was of course was read from the card
test.push_back( 0x25 );
test.push_back( 0x37 );
test.push_back( 0xb4 );
test.push_back( 0x37 );
test.push_back( 0x00 );
test.push_back( 0x7f ); // all-1 padding for no particular reason
test.push_back( 0xff );
test.push_back( 0xff );
test.push_back( 0xff );
test.push_back( 0xff );
test.push_back( 0x9e );
// Look up the offset/length in your card description database
// according to the card type and field name
// For the fun of it, let's not start on a byte boundary
std::cout << get_string( test, 1, 80 ) << " is "
<< get_numeric< unsigned >( test, 81, 7 )
<< " years old" << std::endl;
std::string s;
std::getline( std::cin, s );
}
Cheers,
Malte