BITS.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // C source file with the function definitions to handle bits
  2. // clear_bit_holder() function
  3. // function to make the contents of the bit holder array to be 0
  4. void clear_bit_holder(void)
  5. {
  6. for (umax i = 0; i < BIT_HOLDER_LENGTH; i++)
  7. BIT_HOLDER[i] = 0;
  8. }
  9. // clear_byte_holder() function
  10. // function to make the contents of the byte holder array to be 0
  11. void clear_byte_holder(void)
  12. {
  13. for (umax i = 0; i < BYTE_HOLDER_LENGTH; i++)
  14. BYTE_HOLDER[i] = 0;
  15. }
  16. // print_bit_holder() function
  17. // function print the contents of the bit holder array
  18. void print_bit_holder(void)
  19. {
  20. for (umax i = 0; i < BIT_HOLDER_LENGTH; i++)
  21. printf("%u ", BIT_HOLDER[i]);
  22. printf("\n");
  23. }
  24. // print_byte_holder() function
  25. // function print the contents of the byte holder array
  26. void print_byte_holder(void)
  27. {
  28. for (umax i = 0; i < BYTE_HOLDER_LENGTH; i++)
  29. printf("%02X ", BYTE_HOLDER[i]);
  30. printf("\n");
  31. }
  32. // arr_bitshift() function
  33. // bitshift the bits of an array by 1 either at the
  34. // right (BITSHIFT_RIGHT) or at the left (BITSHIFT_LEFT)
  35. // bits are moved from a variable to the other when it is needed
  36. byte arr_bitshift(void * array, umax arr_size, umax var_size, BITSHIFT_T bitshift_type)
  37. {
  38. // initialize variables
  39. umax byte_cnt = arr_size * var_size; // number of bytes on the array
  40. byte * cur_byte = array; // casting the array pointer
  41. // containers for bits that are meant to be passed to another byte variable
  42. byte new_bit = 0, old_bit = 0;
  43. // check which type of shift to perform (right/left)
  44. // this process depends on endianness as well (fucking hell)
  45. // left bitshift
  46. // go throught the array from right to left
  47. if (bitshift_type == BITSHIFT_LEFT)
  48. {
  49. if (SYS_ENDIAN == LITTLE)
  50. {
  51. // get to the end of the first variable
  52. cur_byte += byte_cnt - var_size;
  53. for (umax i = 0; i < arr_size; i++)
  54. {
  55. for (umax j = 0; j < var_size; j++)
  56. {
  57. new_bit = (* cur_byte) >> (CHAR_BIT - 1);
  58. (* cur_byte) = (* cur_byte) << 1;
  59. (* cur_byte) += old_bit;
  60. old_bit = new_bit;
  61. cur_byte++;
  62. }
  63. // go to the end of the next variable
  64. cur_byte -= 2 * var_size;
  65. }
  66. }
  67. // for big endian system (ez)
  68. else if (SYS_ENDIAN == BIG)
  69. {
  70. // get to the end of the first variable
  71. cur_byte += byte_cnt - 1;
  72. for (umax i = 0; i < byte_cnt; i++)
  73. {
  74. new_bit = (* cur_byte) >> (CHAR_BIT - 1);
  75. (* cur_byte) = (* cur_byte) << 1;
  76. (* cur_byte) += old_bit;
  77. old_bit = new_bit;
  78. cur_byte--;
  79. }
  80. }
  81. }
  82. // right bitshift
  83. // go throught the array from left to right
  84. else if (bitshift_type == BITSHIFT_RIGHT)
  85. {
  86. // for big endian system (sucks)
  87. if (SYS_ENDIAN == LITTLE)
  88. {
  89. // get to the start of the first variable
  90. cur_byte += var_size - 1;
  91. for (umax i = 0; i < arr_size; i++)
  92. {
  93. for (umax j = 0; j < var_size; j++)
  94. {
  95. new_bit = (* cur_byte) << (CHAR_BIT - 1);
  96. (* cur_byte) = (* cur_byte) >> 1;
  97. (* cur_byte) += old_bit;
  98. old_bit = new_bit;
  99. cur_byte--;
  100. }
  101. // advance to the start of the next variable (at the right)
  102. cur_byte += 2 * var_size;
  103. }
  104. }
  105. // for big endian system (ez)
  106. else if (SYS_ENDIAN == BIG)
  107. {
  108. // get to the start of the first variable
  109. // already there (cur_byte = array)
  110. for (umax i = 0; i < byte_cnt; i++)
  111. {
  112. new_bit = (* cur_byte) << (CHAR_BIT - 1);
  113. (* cur_byte) = (* cur_byte) >> 1;
  114. (* cur_byte) += old_bit;
  115. old_bit = new_bit;
  116. cur_byte++;
  117. }
  118. }
  119. }
  120. // bitshift done
  121. // return last bit moved
  122. return old_bit;
  123. }
  124. // arr_n_bitshift() function
  125. // bitshift the bits of an array by shift_count
  126. // this function just calls shift_count times the arr_bitshift() function
  127. void arr_n_bitshift(void * array, umax arr_size, umax var_size, BITSHIFT_T bitshift_type, umax shift_count)
  128. {
  129. while (shift_count-- > 0)
  130. arr_bitshift(array, arr_size, var_size, bitshift_type);
  131. return;
  132. }
  133. // arr_circ_bitshift() function
  134. // bitshift the bits of an array keeping the bits that are going to
  135. // get discarded. These bits are put (depending on the bitshift direction)
  136. // on the end or at the start of the bitfield being bitshifted
  137. byte arr_circ_bitshift(void * array, umax arr_size, umax var_size, BITSHIFT_T bitshift_type)
  138. {
  139. // save the bit that will get lost on the bitshift
  140. // it will depend as well on the endian mode
  141. umax byte_cnt = arr_size * var_size; // number of bytes on the array
  142. byte * arr = array;
  143. byte princess_bit = arr_bitshift(array, arr_size, var_size, bitshift_type);
  144. // left bitshift
  145. if (bitshift_type == BITSHIFT_LEFT) {
  146. // go to the end of the last element of the array
  147. if (SYS_ENDIAN == LITTLE)
  148. arr[byte_cnt - var_size] += princess_bit;
  149. else if (SYS_ENDIAN == BIG)
  150. arr[byte_cnt - 1] += princess_bit;
  151. }
  152. // right bitshift
  153. else if (bitshift_type == BITSHIFT_RIGHT) {
  154. // go to the start of the first element of the array
  155. if (SYS_ENDIAN == LITTLE)
  156. arr[var_size - 1] += princess_bit;
  157. else if (SYS_ENDIAN == BIG)
  158. arr[0] += princess_bit;
  159. }
  160. // circular bitshift done
  161. // return bit saved
  162. return princess_bit;
  163. }
  164. // arr_n_circ_bitshift() function
  165. // shifts the bits of an array in a circular way by shift_count
  166. // this function just calls shift_count times the arr_circ_bitshift() function
  167. void arr_n_circ_bitshift(void * array, umax arr_size, umax var_size, BITSHIFT_T bitshift_type, umax shift_count)
  168. {
  169. while (shift_count-- > 0)
  170. arr_circ_bitshift(array, arr_size, var_size, bitshift_type);
  171. return;
  172. }
  173. // get_bits() function
  174. // funtion to read bits from bytes in memory and send them to BIT_HOLDER for further processing
  175. // It will return the numeric position of the first bit of the binary number in BIT_HOLDER.
  176. // Example:
  177. // lpad_cnt = 4, bit_cnt = 5,
  178. // v v v
  179. // 00010100 |1010|1100 1|0101001 01010111
  180. // 0x14 0xAC 0xA9 0x57
  181. // ^ src
  182. smax get_bits(umax bit_cnt, umax lpad_cnt, void * src)
  183. {
  184. // check params
  185. if ((bit_cnt + lpad_cnt) > BIT_HOLDER_LENGTH || src == NULL)
  186. return -1;
  187. // clear bit and byte arrays
  188. clear_bit_holder();
  189. clear_byte_holder();
  190. // number of bytes the bits (bit_cnt + lshifts + lpad_cnt) will take in memory
  191. umax byte_cnt = bit_cnt + lpad_cnt;
  192. while ((byte_cnt % CHAR_BIT) != 0) byte_cnt++;
  193. byte_cnt /= CHAR_BIT;
  194. // copy the bytes that contain the bits into BYTE_HOLDER
  195. cp_mem_bytes(src, byte_cnt, BYTE_HOLDER + (BYTE_HOLDER_LENGTH - byte_cnt));
  196. // remove the left padding bits (array bitshift - non-circular)
  197. arr_n_bitshift(BYTE_HOLDER + (BYTE_HOLDER_LENGTH - byte_cnt),
  198. byte_cnt, 1, BITSHIFT_LEFT, lpad_cnt);
  199. arr_n_bitshift(BYTE_HOLDER + (BYTE_HOLDER_LENGTH - byte_cnt),
  200. byte_cnt, 1, BITSHIFT_RIGHT, (byte_cnt * CHAR_BIT) - bit_cnt);
  201. // number of bytes the bits (without left padding bits 1 and 2) will take
  202. byte_cnt = bit_cnt;
  203. while ((byte_cnt % CHAR_BIT) != 0) byte_cnt++;
  204. byte_cnt = byte_cnt / CHAR_BIT;
  205. // get the bits into BIT_HOLDER
  206. // start from the rightmost byte in BYTE_HOLDER
  207. // read each bit from right to left and write it to BIT_HOLDER
  208. for (umax i = 0; i < byte_cnt; i++)
  209. for (umax j = 0, byte = 1; j < CHAR_BIT; j++, byte <<= 1)
  210. BIT_HOLDER[BIT_HOLDER_LENGTH - (CHAR_BIT * i) - j - 1] = (byte & BYTE_HOLDER[BYTE_HOLDER_LENGTH - i - 1]) >> j;
  211. // return the starting position of the binary digits
  212. return BIT_HOLDER_LENGTH - bit_cnt;
  213. }
  214. // get_byte_bits() function
  215. // function to get bits from memory but it operates with the byte bits first before
  216. // getting the bits. This function exists because of little endian basically.
  217. //
  218. // The most crazy overcomplicated example of why this function exists:
  219. //
  220. // imagine number -pi (minus pi) stored in a 32 bits float in little endian and I want to get the bits
  221. // of the exponent part of the float (8 bits), unfortunately, said float isn't byte aligned, it starts
  222. // 3 bits left from were it is supposed to start
  223. // so if the byte aligned float is like this:
  224. // DB 0F 49 C0 (hex, in memory)
  225. // 11011011 00001111 01001001 11000000 (binary, in memory)
  226. // the 3 left bit aligned float is like this:
  227. // whatever 61 E9 38 idk (hex, in memory)
  228. // |...|11011 01100001 11101001 00111000 000|.....| (binary, in memory)
  229. // src src + 1 src + 2 src + 3 src + 4
  230. // to get the exponent bits I would have first to bitshift the bytes in which the float is in (5 bytes)
  231. // to the left by 3 (to align it) then reverse the 5 bytes to get them in big endian order and then use
  232. // the get_bits() function to get the desired bits from the process above.
  233. // the get_byte_bits() works in 2 stages, the alignment and the bit extraction
  234. //
  235. // Alignment:
  236. // a call of get_byte_bits() to align and get all the bits would be like
  237. // get_byte_bits(5, 3, ..., ..., src, LITTLE);
  238. // - 5 bytes
  239. // - apply 3 left bitshifts to those 5 bytes
  240. // - resulting variable is on little endian so reverse the order of the bytes after the bitshift
  241. // In the reversal the 5 bytes in memory would look like:
  242. // 00 C0 49 0F DB
  243. // 00000000 11000000 01001001 00001111 11011011
  244. // ptr + 0 ptr + 1 ptr + 2 ptr + 3 ptr + 4
  245. //
  246. // Bit Extraction:
  247. // If I want to apply the get_bits() function to get the exponent bits at this point I would do
  248. // get_bits(8, 8 + 1, ptr) which the finalized call of get_byte_bits() would be at the end
  249. // get_byte_bits(5, 3, 8, 9, src, LITTLE);
  250. //
  251. // I think I was high when doing this. The downside of this function is that to be able to
  252. // define the parameters you have to be extremely sure of what you are requesting. You literally
  253. // have to be able to see the bytes in memory like if they were in front of you. Also, you need
  254. // to be aware of the bits per byte on your system (I try to build these functions to be able to
  255. // be used on other bits per byte systems but as I cannot do tests on those I am not sure if the
  256. // logic is complete)
  257. //
  258. // NOTE: a call with byte_cnt, equal to 0 will make the function to set
  259. // byte_cnt to be the ceil((bit_cnt + lpad_cnt) / CHAR_BIT)
  260. // usually I will use byte_cnt = 0 unless I am losing data on the
  261. // bitshifts that I want
  262. smax get_byte_bits(umax byte_cnt, umax lshifts, umax bit_cnt, umax lpad_cnt, void * src, ENDIAN_T endian)
  263. {
  264. // check params
  265. if (bit_cnt == 0 || src == NULL || endian == NO_ENDIAN)
  266. return -1;
  267. // check byte_cnt
  268. // and define it if it is 0
  269. if (byte_cnt == 0) {
  270. byte_cnt = lshifts + bit_cnt + lpad_cnt;
  271. while (byte_cnt % CHAR_BIT != 0) byte_cnt++;
  272. byte_cnt = byte_cnt / CHAR_BIT;
  273. }
  274. // first, copy the bytes requested into a temporal container
  275. byte * ptr = allocate_memory(byte_cnt, sizeof(byte));
  276. cp_mem_bytes(src, byte_cnt, ptr);
  277. // align the bits
  278. arr_n_bitshift(ptr, byte_cnt, sizeof(byte), BITSHIFT_LEFT, lshifts);
  279. // then, check the endian (if little then reverse the array)
  280. if (endian == LITTLE)
  281. reverse_array(ptr, byte_cnt, sizeof(byte));
  282. // now, on the operated bytes, apply the get_bits() function
  283. smax rtn = get_bits(bit_cnt, lpad_cnt, ptr);
  284. // free memory
  285. free_memory(ptr);
  286. return rtn;
  287. }