1

I have following code in C which will generate keys based on input serial number.

unsigned int32 passkey(unsigned int32 snumber)
{
    char snstring[11];
    unsigned int32 pwd;
    int i = 0;
    itoa(snumber,10,snstring);
    do{
        snstring[i+1] -= '0';
        snstring[i] = ~snstring[i+1];
        snstring[i] &= 0x07;
        i++;
    }while(i < 9);
    snstring[9] <<= 1;
    snstring[9] &= 0x07;
    pwd = atoi32(snstring);
    return (pwd);
}

I need to convert this into C# code, I have tried following :

private uint ComputeKey(uint snumber)
        {
            char[] snstring = new char[11];
            UInt32 pwd;
            int i = 0;
            snstring = snumber.ToString().ToCharArray();

            do
            {
                snstring[i + 1] = Convert.ToChar(snstring[i + 1] - '0');
                snstring[i] = Convert.ToChar(~Convert.ToInt32(snstring[i + 1]));
                snstring[i] &= Convert.ToChar(Convert.ToInt32(0x07));
                i++;
            } while (i < 9);
            snstring[9] <<= 1;
            snstring[9] &= Convert.ToChar(0x07);
            pwd = Convert.ToUInt32(snstring);
            return (pwd);
        }

Programs throws exception at snstring[i] = Convert.ToChar(~Convert.ToInt32(snstring[i + 1])); this line.

Another noticeable behavior is that for example I have input as

151972634

Then, on this line snstring[i] = Convert.ToChar(~Convert.ToInt32(snstring[i + 1])); value of snstring[i+1] is '\u0005' And it throws OverflowException was Unhandled.

I am not sure what I should be doing, any help is appreciated.

PC Luddite
  • 5,883
  • 6
  • 23
  • 39

2 Answers2

1

When you flip bits of a 32-bit int representing a char, which always has one byte in C, you end up with the upper three bytes set to 0xFF. However, C happily chops off the upper bytes on assignment to char, while C#'s converter throws an exception.

You can fix this by using a cast in place of conversion to match what C does:

snstring[i+1] -= '0';
snstring[i] = (char)(~snstring[i+1] & 0x07);

Essentially, the cast tells C# explicitly to do the same thing that C does by default.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    You end up with the upper bytes set to 0xFF in C too, because of integer promotion. But C is lax and allows the assignment to do an implicit conversion back to the lvalue type straight after, without producing any diagnostics. Simply put, rugged C code should also do an implicit cast to the intended type directly after `~`, for example `(unsigned char)~snstring[i+1]`. (You don't want to use `char` for this in C, because it has poorly defined signedness.) – Lundin Aug 16 '16 at 14:22
1

I have done a similar task, i.e. to take a number as input and do exactly what your code is doing in C#. I am taking string as input and returning string though. Below is the code :

private string ComputeKey(string serialnumber)
        {
            if (string.IsNullOrEmpty(serialnumber))
            {
                throw new Exception("Cannot generate a key from a null or empty string");
            }

            serialnumber += '\0';
            var length = serialnumber.Length;
            byte[] snbytes = Encoding.UTF8.GetBytes(serialnumber);
            for (int i = 0; i < length - 1; i++)
            {
                snbytes[i + 1] -= 0x30;
                snbytes[i] = (byte)~snbytes[i + 1];
                snbytes[i] &= 0x07;
            }
            snbytes[length - 1] <<= 1;
            snbytes[length - 1] &= 0x07;

            var sb = new StringBuilder();
            for (int j = 0; j < length - 1; j++)
            {
                sb.Append(snbytes[j].ToString());
            }

            return sb.ToString();
        }
Su Sa
  • 40
  • 5