views:

358

answers:

4

I have written a function to take in the data from a Sirit IDentity MaX AVI reader and parse out the facility code and keycard number. How I am currently doing it works, but is there a better way? Seems little hackish... buff & buf are size 264

buf and buff are char

Data received from reader:

2009/12/30 14:56:18 epc0 LN:001 C80507A0008A19FA 0000232F Xlat'd

char TAccessReader::HexCharToInt(char n)
{
    if (n >= '0' && n <= '9')
        return (n-'0');
    else

    if (n >= 'A' && n <= 'F')
        return (n-'A'+10);
    else
        return 0;
}

bool TAccessReader::CheckSirit(char *buf, long *key_num, unsigned char *fac) {

   unsigned short i, j, k;

   *key_num = 0; // Default is zero
   memset(buff, 0, sizeof(buff));

   i = sscanf(buf, "%s %s %s %s %s %s %s", &buff[0], &buff[20], &buff[40],
              &buff[60], &buff[80], &buff[140], &buff[160]);
   if (i == 7 && buff[147] && !buff[148]) {
       // UUGGNNNN UU=spare, GG=Facility Code, NNNN=Keycard Number (all HEX)

       // get facility code

       *fac = HexCharToInt(buff[142]) * 16 + HexCharToInt(buff[143]);
       *key_num = (unsigned short)HexCharToInt(buff[144]) * 4096 +
                  (unsigned short)HexCharToInt(buff[145]) * 256 +
                  (unsigned short)HexCharToInt(buff[146]) * 16 +
                  HexCharToInt(buff[147]);
   }
   // do some basic checks.. return true or false
}
+1  A: 

You could use strtoul() from the C standard library.

GregS
`strtol` and `strtoul` re my favorite functions for this because they're so flexible. They can do hex, decimal, octal, and binary (any base from 2 to 36, really), and if you say base 0, they'll use C-style prefixes (`0` for octal, `0x` for hex, no prefix for decimal) to figure out the base. Great for parsing parameters. The only thing they don't do is base 64.
Mike D.
+6  A: 

Just use std::stringstream:

#include <sstream>
#include <iostream>

using namespace std;

int main() {
    unsigned int x;   
    stringstream ss;
    ss << hex << "ff";
    ss >> x;
    // output it as a signed type
    cout << static_cast<int>(x) << endl;
}

You can also use strtol from straight-up C:

#include <cstdlib>
#include <iostream>

using namespace std;

int main() {
    string s = "ff";
    char *p;
    long n = strtol(s.c_str(), &p, 16);
    if (*p != 0) {
        cout << "fail" << endl;
    }
    else {
        cout << n << endl;
    }
}
Jason
If it's problem that is likely to be common (parsing input strings to numbers) almost surely there is a library function to handle it for you already.
Jason
`char *p; *key_num = strtol(` worked - thanks!
0A0D
@Roboto: Great, glad I could help.
Jason
+1  A: 

Since you are already using sscanf, why not have it parse the hex numbers for you:

sscanf(buff, "%x %x", &val1, &val2);
R Samuel Klatchko
0A0D
+1  A: 

Here's an easy way to get at the data you want. I do work in the access control business so this was something that interested me...

template<typename TRet, typename Iterator>
TRet ConvertHex(Iterator begin) {
    unsigned long result;

    Iterator end = begin + (sizeof(TRet) * 2);
    std::stringstream ss(std::string(begin, end));
    ss >> std::hex >> result;

    return result;
}

bool TAccessReader::CheckSirit(char *buf, long *key_num, unsigned char *fac) {
   *key_num = 0; // Default is zero

   std::istringstream sbuf(std::string(buf, buf+264));

   // Stuff all of the string elements into a vector
   std::vector<std::string> elements;
   std::copy (std::istream_iterator<std::string>(sbuf), std::istream_iterator<std::string>(), std::back_inserter (elements));

   // We're interested in the 6th element
   std::string read = elements[5];

   if (read.length() == 8) {
       // UUGGNNNN UU=spare, GG=Facility Code, NNNN=Keycard Number (all HEX)

       // get facility and card code
       std::string::const_iterator iter = read.begin();
       *fac = ConvertHex<unsigned char>(iter + 2);
       *key_num = ConvertHex<unsigned short>(iter + 4);
   }
   // do some basic checks.. return true or false
}
joshperry
getting this error: 'operator<<' not implemented in type 'string' for arguments of type 'istringstream'
0A0D
Yeah, sorry about that, it should have been >> not <<. I've changed the code anyway, so try the new goods.
joshperry
I think its missing something because it is not compiling properly.. undefined symbol `is` and `read`
0A0D
Yes, well that's what I get for not actually trying it. I've compiled it and the code should work now. I'm not sure what you are wanting to check in the `if` statement so I just put a check on the length.
joshperry
when `return result;` is called, it kills my thread.. i'm guessing this is not threadsafe?
0A0D
It kills your thread? There is no shared data so there shouldn't be any issue with thread safety... What compiler are you using? Here is the code compiling and running on GCC: http://codepad.org/ITyjBrtq
joshperry
C++ Builder 5 by Borland... I put in breakpoints to see what was happening and it gets all the way to `return result;` and after I hit 'continue' it just stops. Program is still running but thread is not
0A0D
more info.. I see it entering/leaving the critical section and locking the mutex so it should be fine there.. i am going to see if it has to do with the assignment.
0A0D
ok, it has to do with the `*fac =` assignment
0A0D
got it to work - my stupid fault! fac was null in my code - this works excellent!
0A0D
That was my guess, not enough information to tell though... Glad it works for you. The C++ standard library is quite powerful, learn it, love it, use it!
joshperry
thanks josh.. i'm a little rusty so this really helped!
0A0D