123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- // C source file with the function definitions to handle bits
- // clear_bit_holder() function
- // function to make the contents of the bit holder array to be 0
- void clear_bit_holder(void)
- {
- for (umax i = 0; i < BIT_HOLDER_LENGTH; i++)
- BIT_HOLDER[i] = 0;
- }
- // clear_byte_holder() function
- // function to make the contents of the byte holder array to be 0
- void clear_byte_holder(void)
- {
- for (umax i = 0; i < BYTE_HOLDER_LENGTH; i++)
- BYTE_HOLDER[i] = 0;
- }
- // print_bit_holder() function
- // function print the contents of the bit holder array
- void print_bit_holder(void)
- {
- for (umax i = 0; i < BIT_HOLDER_LENGTH; i++)
- printf("%u ", BIT_HOLDER[i]);
- printf("\n");
- }
- // print_byte_holder() function
- // function print the contents of the byte holder array
- void print_byte_holder(void)
- {
- for (umax i = 0; i < BYTE_HOLDER_LENGTH; i++)
- printf("%02X ", BYTE_HOLDER[i]);
- printf("\n");
- }
- // arr_bitshift() function
- // bitshift the bits of an array by 1 either at the
- // right (BITSHIFT_RIGHT) or at the left (BITSHIFT_LEFT)
- // bits are moved from a variable to the other when it is needed
- byte arr_bitshift(void * array, umax arr_size, umax var_size, BITSHIFT_T bitshift_type)
- {
- // initialize variables
- umax byte_cnt = arr_size * var_size; // number of bytes on the array
- byte * cur_byte = array; // casting the array pointer
- // containers for bits that are meant to be passed to another byte variable
- byte new_bit = 0, old_bit = 0;
- // check which type of shift to perform (right/left)
- // this process depends on endianness as well (fucking hell)
-
- // left bitshift
- // go throught the array from right to left
- if (bitshift_type == BITSHIFT_LEFT)
- {
- if (SYS_ENDIAN == LITTLE)
- {
- // get to the end of the first variable
- cur_byte += byte_cnt - var_size;
- for (umax i = 0; i < arr_size; i++)
- {
- for (umax j = 0; j < var_size; j++)
- {
- new_bit = (* cur_byte) >> (CHAR_BIT - 1);
- (* cur_byte) = (* cur_byte) << 1;
- (* cur_byte) += old_bit;
- old_bit = new_bit;
- cur_byte++;
- }
- // go to the end of the next variable
- cur_byte -= 2 * var_size;
- }
- }
- // for big endian system (ez)
- else if (SYS_ENDIAN == BIG)
- {
- // get to the end of the first variable
- cur_byte += byte_cnt - 1;
- for (umax i = 0; i < byte_cnt; i++)
- {
- new_bit = (* cur_byte) >> (CHAR_BIT - 1);
- (* cur_byte) = (* cur_byte) << 1;
- (* cur_byte) += old_bit;
- old_bit = new_bit;
- cur_byte--;
- }
- }
- }
- // right bitshift
- // go throught the array from left to right
- else if (bitshift_type == BITSHIFT_RIGHT)
- {
- // for big endian system (sucks)
- if (SYS_ENDIAN == LITTLE)
- {
- // get to the start of the first variable
- cur_byte += var_size - 1;
- for (umax i = 0; i < arr_size; i++)
- {
- for (umax j = 0; j < var_size; j++)
- {
- new_bit = (* cur_byte) << (CHAR_BIT - 1);
- (* cur_byte) = (* cur_byte) >> 1;
- (* cur_byte) += old_bit;
- old_bit = new_bit;
- cur_byte--;
- }
- // advance to the start of the next variable (at the right)
- cur_byte += 2 * var_size;
- }
- }
- // for big endian system (ez)
- else if (SYS_ENDIAN == BIG)
- {
- // get to the start of the first variable
- // already there (cur_byte = array)
- for (umax i = 0; i < byte_cnt; i++)
- {
- new_bit = (* cur_byte) << (CHAR_BIT - 1);
- (* cur_byte) = (* cur_byte) >> 1;
- (* cur_byte) += old_bit;
- old_bit = new_bit;
- cur_byte++;
- }
- }
- }
-
- // bitshift done
- // return last bit moved
- return old_bit;
- }
- // arr_n_bitshift() function
- // bitshift the bits of an array by shift_count
- // this function just calls shift_count times the arr_bitshift() function
- void arr_n_bitshift(void * array, umax arr_size, umax var_size, BITSHIFT_T bitshift_type, umax shift_count)
- {
- while (shift_count-- > 0)
- arr_bitshift(array, arr_size, var_size, bitshift_type);
- return;
- }
- // arr_circ_bitshift() function
- // bitshift the bits of an array keeping the bits that are going to
- // get discarded. These bits are put (depending on the bitshift direction)
- // on the end or at the start of the bitfield being bitshifted
- byte arr_circ_bitshift(void * array, umax arr_size, umax var_size, BITSHIFT_T bitshift_type)
- {
- // save the bit that will get lost on the bitshift
- // it will depend as well on the endian mode
- umax byte_cnt = arr_size * var_size; // number of bytes on the array
- byte * arr = array;
- byte princess_bit = arr_bitshift(array, arr_size, var_size, bitshift_type);
-
- // left bitshift
- if (bitshift_type == BITSHIFT_LEFT) {
- // go to the end of the last element of the array
- if (SYS_ENDIAN == LITTLE)
- arr[byte_cnt - var_size] += princess_bit;
- else if (SYS_ENDIAN == BIG)
- arr[byte_cnt - 1] += princess_bit;
- }
- // right bitshift
- else if (bitshift_type == BITSHIFT_RIGHT) {
- // go to the start of the first element of the array
- if (SYS_ENDIAN == LITTLE)
- arr[var_size - 1] += princess_bit;
- else if (SYS_ENDIAN == BIG)
- arr[0] += princess_bit;
- }
-
- // circular bitshift done
- // return bit saved
- return princess_bit;
- }
- // arr_n_circ_bitshift() function
- // shifts the bits of an array in a circular way by shift_count
- // this function just calls shift_count times the arr_circ_bitshift() function
- void arr_n_circ_bitshift(void * array, umax arr_size, umax var_size, BITSHIFT_T bitshift_type, umax shift_count)
- {
- while (shift_count-- > 0)
- arr_circ_bitshift(array, arr_size, var_size, bitshift_type);
- return;
- }
- // get_bits() function
- // funtion to read bits from bytes in memory and send them to BIT_HOLDER for further processing
- // It will return the numeric position of the first bit of the binary number in BIT_HOLDER.
- // Example:
- // lpad_cnt = 4, bit_cnt = 5,
- // v v v
- // 00010100 |1010|1100 1|0101001 01010111
- // 0x14 0xAC 0xA9 0x57
- // ^ src
- smax get_bits(umax bit_cnt, umax lpad_cnt, void * src)
- {
- // check params
- if ((bit_cnt + lpad_cnt) > BIT_HOLDER_LENGTH || src == NULL)
- return -1;
-
- // clear bit and byte arrays
- clear_bit_holder();
- clear_byte_holder();
-
- // number of bytes the bits (bit_cnt + lshifts + lpad_cnt) will take in memory
- umax byte_cnt = bit_cnt + lpad_cnt;
- while ((byte_cnt % CHAR_BIT) != 0) byte_cnt++;
- byte_cnt /= CHAR_BIT;
-
- // copy the bytes that contain the bits into BYTE_HOLDER
- cp_mem_bytes(src, byte_cnt, BYTE_HOLDER + (BYTE_HOLDER_LENGTH - byte_cnt));
-
- // remove the left padding bits (array bitshift - non-circular)
- arr_n_bitshift(BYTE_HOLDER + (BYTE_HOLDER_LENGTH - byte_cnt),
- byte_cnt, 1, BITSHIFT_LEFT, lpad_cnt);
- arr_n_bitshift(BYTE_HOLDER + (BYTE_HOLDER_LENGTH - byte_cnt),
- byte_cnt, 1, BITSHIFT_RIGHT, (byte_cnt * CHAR_BIT) - bit_cnt);
-
- // number of bytes the bits (without left padding bits 1 and 2) will take
- byte_cnt = bit_cnt;
- while ((byte_cnt % CHAR_BIT) != 0) byte_cnt++;
- byte_cnt = byte_cnt / CHAR_BIT;
-
- // get the bits into BIT_HOLDER
- // start from the rightmost byte in BYTE_HOLDER
- // read each bit from right to left and write it to BIT_HOLDER
- for (umax i = 0; i < byte_cnt; i++)
- for (umax j = 0, byte = 1; j < CHAR_BIT; j++, byte <<= 1)
- BIT_HOLDER[BIT_HOLDER_LENGTH - (CHAR_BIT * i) - j - 1] = (byte & BYTE_HOLDER[BYTE_HOLDER_LENGTH - i - 1]) >> j;
-
- // return the starting position of the binary digits
- return BIT_HOLDER_LENGTH - bit_cnt;
- }
- // get_byte_bits() function
- // function to get bits from memory but it operates with the byte bits first before
- // getting the bits. This function exists because of little endian basically.
- //
- // The most crazy overcomplicated example of why this function exists:
- //
- // imagine number -pi (minus pi) stored in a 32 bits float in little endian and I want to get the bits
- // of the exponent part of the float (8 bits), unfortunately, said float isn't byte aligned, it starts
- // 3 bits left from were it is supposed to start
- // so if the byte aligned float is like this:
- // DB 0F 49 C0 (hex, in memory)
- // 11011011 00001111 01001001 11000000 (binary, in memory)
- // the 3 left bit aligned float is like this:
- // whatever 61 E9 38 idk (hex, in memory)
- // |...|11011 01100001 11101001 00111000 000|.....| (binary, in memory)
- // src src + 1 src + 2 src + 3 src + 4
- // to get the exponent bits I would have first to bitshift the bytes in which the float is in (5 bytes)
- // to the left by 3 (to align it) then reverse the 5 bytes to get them in big endian order and then use
- // the get_bits() function to get the desired bits from the process above.
- // the get_byte_bits() works in 2 stages, the alignment and the bit extraction
- //
- // Alignment:
- // a call of get_byte_bits() to align and get all the bits would be like
- // get_byte_bits(5, 3, ..., ..., src, LITTLE);
- // - 5 bytes
- // - apply 3 left bitshifts to those 5 bytes
- // - resulting variable is on little endian so reverse the order of the bytes after the bitshift
- // In the reversal the 5 bytes in memory would look like:
- // 00 C0 49 0F DB
- // 00000000 11000000 01001001 00001111 11011011
- // ptr + 0 ptr + 1 ptr + 2 ptr + 3 ptr + 4
- //
- // Bit Extraction:
- // If I want to apply the get_bits() function to get the exponent bits at this point I would do
- // get_bits(8, 8 + 1, ptr) which the finalized call of get_byte_bits() would be at the end
- // get_byte_bits(5, 3, 8, 9, src, LITTLE);
- //
- // I think I was high when doing this. The downside of this function is that to be able to
- // define the parameters you have to be extremely sure of what you are requesting. You literally
- // have to be able to see the bytes in memory like if they were in front of you. Also, you need
- // to be aware of the bits per byte on your system (I try to build these functions to be able to
- // be used on other bits per byte systems but as I cannot do tests on those I am not sure if the
- // logic is complete)
- //
- // NOTE: a call with byte_cnt, equal to 0 will make the function to set
- // byte_cnt to be the ceil((bit_cnt + lpad_cnt) / CHAR_BIT)
- // usually I will use byte_cnt = 0 unless I am losing data on the
- // bitshifts that I want
- smax get_byte_bits(umax byte_cnt, umax lshifts, umax bit_cnt, umax lpad_cnt, void * src, ENDIAN_T endian)
- {
- // check params
- if (bit_cnt == 0 || src == NULL || endian == NO_ENDIAN)
- return -1;
-
- // check byte_cnt
- // and define it if it is 0
- if (byte_cnt == 0) {
- byte_cnt = lshifts + bit_cnt + lpad_cnt;
- while (byte_cnt % CHAR_BIT != 0) byte_cnt++;
- byte_cnt = byte_cnt / CHAR_BIT;
- }
-
- // first, copy the bytes requested into a temporal container
- byte * ptr = allocate_memory(byte_cnt, sizeof(byte));
- cp_mem_bytes(src, byte_cnt, ptr);
- // align the bits
- arr_n_bitshift(ptr, byte_cnt, sizeof(byte), BITSHIFT_LEFT, lshifts);
-
- // then, check the endian (if little then reverse the array)
- if (endian == LITTLE)
- reverse_array(ptr, byte_cnt, sizeof(byte));
- // now, on the operated bytes, apply the get_bits() function
- smax rtn = get_bits(bit_cnt, lpad_cnt, ptr);
- // free memory
- free_memory(ptr);
- return rtn;
- }
|