Understanding Hex logic

-1

Finding very hard to understand below hex code logic. Could anyone please explain ampersand in switch condition and how is that previousTagSize calculated.

- (void)parse:(NSInputStream*)inputStream {

  NSInteger MASK = 0x1f;
  NSInteger Type1 = 8;
  NSInteger Type2 = 9;
  NSInteger Type3 = 18;

    uint8_t header[11];
    long len = [inputStream read:header maxLength:11];

    //How does it work?
    switch (header[0] & MASK) {
        case  Type1:
            self.type = Type_1;
            break;
        case Type2:
            self.type = Type_2;
            break;
    }

    self.dataSize = ((header[1] & 0x000000FF) << 16) | ((header[2] & 0x000000FF) << 8) | (header[3] & 0x000000FF);

        // read previous tag size
    uint8_t tagSize[4];
    [inputStream read:tagSize maxLength:4];
    int previousTagSize = ((tagSize[0] & 0x000000FF) << 24) |
                          ((tagSize[1] & 0x000000FF) << 16) |
                          ((tagSize[2] & 0x000000FF) << 8) |
                          (tagSize[3] & 0x000000FF);

    if (previousTagSize != 11 + self.dataSize) {
        NSLog(@"Invalid .");
    }
}
objective-c
hex
asked on Stack Overflow Sep 23, 2018 by (unknown user) • edited Sep 23, 2018 by Mat

1 Answer

1

Finding very hard to understand below hex code logic.

The "logic" isn't hex, it is a combination of integer and bitwise logic.

The "hex" is just one way of representing an integer value in Objective-C program text. What the computer your compiled Objective-C executes on will, as an ordered sequence of bits, is the same regardless of the textual representation of the integer in your program text.

For example, 104 (decimal), 0x68 (hex) and 0150 (octal) if stored in a byte are all represented using the same ordered sequence of bits 01101000. The computer also sees the UTF-8 character "h" as those same ordered sequence of bits.

(Note: I'm using bytes or 8 bits in this answer to save typing lots of zeros, an NSInteger on a 64-bit machine is 64 bits but for the values used in the examples here the first 56 of those bits are all zero.)

Whether bits are treated as integers, floating point numbers, characters et al depends on context - and that is where the integer and bitwise logic comes in...

Could anyone please explain ampersand in switch condition

The & operator in Objective-C is bitwise and, that is the ordered sequences of bits in the two operands are combined pairwise using the logical (aka Boolean) and function (0 and 0 = 0, 0 and 1 = 0, 1 and 0 = 0 and 1 and 1 = 1). The fragment of code:

header[0] & MASK

is using & to do a masking operation - if you look at the and function if one operand is a 1 the result is the other operand, if it is 0 the result is 0, so and can be used to "mask" off part of a sequence.

For example consider if header[0] held the representation of our 104 from above, that representation as 8 bits is 01101000. The representation of MASK, which has the value 0x1F, as 8 bits is 00011111. Combine these two representations using bitwise and gives you the sequence 00001000 where the first 3 zeros are due to zeros in the second operand (the "mask") and the 5-bit sequence 01000 is the same as the last five bits of the first operand due to the second operand being all ones.

After this bitwise and if the resultant sequence of bits is interpreted as an integer the value is 8, which just happens to by the same value as Type1 in the program.

The effect therefore of the switch is to select based on the integer interpretation of the last 5 bits of header[0]. This type of code, for example, occurs when multiple data values have been packed into larger storage units – in this case 5 bits out of 64 (the storage size of an NSInteger on a 64-bit computer).

and how is that previousTagSize calculated.

Again this is just bitwise operations, the operator | is bitwise or and the operator << is shift left, a single bit left shift discards the leftmost bit of the ordered sequence of bits and appends a 0 bit to the rightmost end (so the sequence stays the same length). The complete fragment:

int previousTagSize = ((tagSize[0] & 0x000000FF) << 24) |
                      ((tagSize[1] & 0x000000FF) << 16) |
                      ((tagSize[2] & 0x000000FF) << 8) |
                      (tagSize[3] & 0x000000FF);

combines 4 values, each of which is masked to 8 bits[*], into a single 32 bit (the size of an int in Objective-C) sequence.

HTH

[*] Masking is required if the value is a signed type even if the value fits into the destination number of bits to remove the extra ones (in 4-bit two's complement representation 0101 represents 5, 1101 represents -3; in 8 bits these would be 00000101 and 11111101 respectively, the masking removes those extra 1's in the second case or they would effect the correctness of the packing. The removed 1's are restored on unpacking. Read up on 2's complement for more details.

answered on Stack Overflow Sep 23, 2018 by CRD • edited Sep 24, 2018 by CRD

User contributions licensed under CC BY-SA 3.0