converting base 4 code to letters - c

im working on an assmebler project that i have and i need to translate binary machine code that i have to a "weird" 4 base code for example
if i get binary code like this "0000-10-01-00" i should translate it to "aacba"
00=a
01=b
10=c
11=d
i have managed to translate the code to 4 base code but i dont know how to continue from there or if this is the right way to do it,...
adding my code below
void intToBase4 (unsigned int *num)
{
int d[7];
int j,i=0;
double x=0;
while((*num)>0)
{
d[i]=(*num)%4;
i++;
(*num)=(*num)/4;
}
for(x=0,j=i-1; j>=0; j--)
{
x += d[j]*pow(10,j);
}
(*num)=(unsigned int)x;
}

I've included a little 32-bit to num to letter converter for you to grasp the basics. It works a single "32-bit number" at a time. You could use this as a basis for an array based solution like you have half way done in your example, or change the type to be bigger, or whatever. It should show you roughly what you need to do:
void intToBase4 (uint32_t num, char *outString)
{
// There are 16 digits per num in this example
for(int i=0; i<16; i++)
{
// Grab the lowest 2 bits and convert to a letter.
*outString++ = (num & 0x03) + 'a';
// Shift next 2 bits low
num >>= 2;
}
// NUL terminate string.
*outString = '\0';
}

A bit more universal one:
Usage:
value - value to decode, buff - buff where result string will be stored, numofwrds - number of fields to be decoded, ... fields sizes in bits
example "xxxxyyvvzz": - 4 bits, two bits, two bits, two bits
decode(v, buff, 4, 4, 2, 2, 2);
char dictionary[] = "abcdefghijklmnopqrstuwxyz";
char *decode(unsigned int value, char *buff, int numofwrds, ...)
{
va_list vl;
int *fieldsizes = malloc(sizeof(int) * numofwrds);
int bitsize = 0;
char *result = NULL;
if (fieldsizes != NULL)
{
va_start(vl, numofwrds);
for (int i = 0; i < numofwrds; i++)
{
fieldsizes[i] = va_arg(vl, int);
bitsize += fieldsizes[i];
}
va_end(vl);
for (int i = 0; i < numofwrds; i++)
{
unsigned int mask, offset;
mask = (1 << fieldsizes[i]) - 1;
offset = bitsize - fieldsizes[i];
mask <<= offset;
buff[i] = dictionary[(value & mask) >> offset];
bitsize -= fieldsizes[i];
}
free(fieldsizes);
result = buff;
}
buff[numofwrds] = '\0';
return result;
}

Related

Memcpy in C causes STM to freeze after turning power off and on

I have a problem with STM32F401CCU. After executing a code disconnecting and connecting power the STM freezes and to unfreeze it I need to reload the build.
I have a complex set of functions that are used to turn an array of int values into a single very long char array. The char array is then written to the long term Flash memory. In order to execute that I do many operations with char arrays and they appear to be executed properly, as saving to Flash is done correctly - I tested Flash content with ST LINK and they are what they should be. But after turning power off/on to actually test if long term Flash memory works I encounter a fatal bug - upon powering STM back on it freezes and the only way to unfreeze it is to reload the build.
After many hours of tests I figured that the problem is with memcpy usage in StringCreateStrForFlashOneProduct. Presumably I created a sort of memory leak, but I don't get what's wrong.
A piece of example operation that causes STM to freeze:
static char send_save_string_final[2048];
char sssssend_char[2048] = "000000NewProduct";
char *StringCreateStrForFlashOneProduct(const int someint)
{
memcpy(sssssend_char, "000000008888008000000000888800800000000088880080", 48);
memcpy(send_save_string_final, sssssend_char, 48);
return send_save_string_final;
}
The code I actually use:
FUNCTION ONE - Creates a single array of chars and then saves it to flash memory
static char output_all_sorts[6001] = "";
char all_save_string[6001] = "";
char sssssend_char_all_sorts[2048] = "00000AllProducts";
char append_char_numz_all_sorts[17] = "0000000000000000";
void FlashSaveAllSorts(void)
{
strcpy(sssssend_char_all_sorts, "00000AllProducts");
sssssend_char_all_sorts[2047] = 0;
strcpy(output_all_sorts, "0");
output_all_sorts[6000] = 0;
strcpy(all_save_string, "00000AllProducts");
all_save_string[6000] = 0;
strcpy(append_char_numz_all_sorts, "0000000000000000");
append_char_numz_all_sorts[16] = 0;
for (int doin_int = 0; doin_int <= 6; doin_int++)
{
strcpy(sssssend_char_all_sorts, StringCreateStrForFlashOneProduct(doin_int));
strcat(all_save_string, sssssend_char_all_sorts);
strcpy(output_all_sorts, all_save_string);
}
strcpy(output_all_sorts, all_save_string);
output_all_sorts[strlen(output_all_sorts)] = 0;
Flash_Write_Data(0x08020000, output_all_sorts, 3000);
}
FUNCTION TWO - Creates a single line with all data for one product
static char send_save_string_final[2048] = "0";
char sssssend_char[2048] = "000000NewProduct";
char append_char_numz[17] = "0000000000000000";
char *StringCreateStrForFlashOneProduct(const int someint)
{
strcpy(send_save_string_final, "0");
send_save_string_final[2047] = 0;
strcpy(sssssend_char, "000000NewProduct");
sssssend_char[2047] = 0;
strcpy(append_char_numz, "0000000000000000");
append_char_numz[16] = 0;
strncpy(append_char_numz, StringCreateStringFromIntTwo(someint), 17);
append_char_numz[16] = 0;
strcat(sssssend_char, append_char_numz);
for (int kk = 0; kk < 3; kk = kk + 1)
{
char append_char_one[17] = "0000000000000000";
for (int jj = 0; jj < 12; jj = jj + 1)
{
char append_char[17] = "0000000000000000";
memcpy(append_char, StringCreateStringFromIntTwo(tunable_vars_machine_for_flash[someint][kk][jj]), 17);
strcat(sssssend_char, append_char);
}
memcpy(append_char_one, "000000000MenuEnd", 17);
strcat(sssssend_char, append_char_one);
}
char append_char_end_zeros[17] = "0000000000000000";
memcpy(append_char_end_zeros, StringCreateStringFromIntTwo(0), 17);
strcat(sssssend_char, append_char_numz);
memcpy(send_save_string_final, sssssend_char, 2047);
return send_save_string_final;
}
FUNCTION THREE - Creates a 16-chars array with a following format 000000000000001333, zeros are required to have consistent length of saved string, 1333 is example data value:
char *StringCreateStringFromIntTwo(int base_int_base)
{
//clearprint("StringCreateStri");
int base_int = base_int_base;
if (base_int == 0)
{
base_int = 999999; /// avoid saving zero to flash memory
}
static char send_char_final[17] = "0000000000000000";
char send_char[16] = "00000000";
static char send_char_sixteen_zeros[17] = "0000000000000000";
int legnewpigwphjh = strlen(send_char);
char str_zero[2] = "0";
char str_two_zeros[3] = "00";
char str_three_zeros[4] = "000";
char str_four_zeros[5] = "0000";
char str_five_zeros[6] = "00000";
char str_six_zeros[7] = "000000";
char str_seven_zeros[8] = "0000000";
char str_eight_zeros[9] = "00000000";
char str_sixteen_zeros[17] = "0000000000000000";
int int_mem_length = countDigits(base_int);
char str_mem_write_int[9];
sprintf(str_mem_write_int, "%d", base_int);
if (int_mem_length == 7)
{
strcat(send_char, str_zero);
}
if (int_mem_length == 6)
{
strcat(send_char, str_two_zeros);
}
if (int_mem_length == 5)
{
strcat(send_char, str_three_zeros);
}
if (int_mem_length == 4)
{
strcat(send_char, str_four_zeros);
}
if (int_mem_length == 3)
{
strcat(send_char, str_five_zeros);
}
if (int_mem_length == 2)
{
strcat(send_char, str_six_zeros);
}
if (int_mem_length == 1)
{
strcat(send_char, str_seven_zeros);
}
strcat(send_char, str_mem_write_int);
strcpy(send_char_final, str_sixteen_zeros);
strcpy(send_char_final, send_char);
return send_char_final;
}
Your code is way too complicated. There are too many string copies and concatenations, and countless useless operations. You do not seem to master pointers, nor basic memory layout concepts. Above all, given your skill level, you should absolutely avoid strncpy and memcpy.
Here is a simpler approach with functions that construct the appropriate string format at the end of the buffer and return the number of characters written. With this method, composing a long string is much simpler and much less error prone:
// function to construct a fixed length string of digits with leading 0s
// buffer must point to an array at least 17 bytes long
// returns the number of characters, ie: 16
int FormatNumber16(char *buffer, int someint) {
if (someint == 0) {
// This test seems bogus: the product number 0 will be written as 999999
// and so will the MenuEnd number
someint = 999999; // avoid writing 0 ???
}
return snprintf(buffer, 17, "%016d", someint);
}
// function to construct the product string to store to flash
// buffer must point to an array at least 641 bytes long
// returns the number of characters, ie: 640
int FormatOneProduct(char *buffer, int product_nb) {
int pos = 0;
pos += snprintf(buffer + pos, 17, "%016s", "NewProduct");
pos += FormatNumber16(buffer + pos, product_nb);
for (int kk = 0; kk < 3; kk++) {
for (int jj = 0; jj < 12; jj++) {
pos += FormatNumber16(buffer + pos,
tunable_vars_machine_for_flash[product_nb][kk][jj]);
}
}
pos += snprintf(buffer + pos, 17, "%016s", "MenuEnd");
// vvv this will actually append 0000000000999999 ?
pos += FormatNumber16(buffer + pos, 0);
// pos should be 640 = 16 + 16 + 12*3*16 + 16 + 16
return pos;
}
// function to write all product data to flash (7 products)
void FlashSaveAllSorts(void) {
char buffer[6001] = ""; // no need for global data
int pos = 0;
pos += snprintf(buffer + pos, 17, "%016s", "AllProducts");
// append the description of all 7 products (0 to 6 included)
for (int product_nb = 0; product_nb <= 6; product_nb++) {
pos += FormatOneProduct(buffer + pos, product_nb);
}
// buffer contains 4496 = 16 + 640*7 characters, why write 3000 bytes?
Flash_Write_Data(0x08020000, buffer, 3000);
}
Some example functions:
char *StringCreateStrForFlashOneProduct(char *buff, size_t len, int someint)
{
int mask = 1000000000;
char *wrk = buff;
if(!someint) someint = 999999;
memset(buff, '0', len - 10);
wrk += len - 10;
while(mask)
{
*wrk++ = '0' + abs(someint / mask);
someint %= mask;
mask /= 10;
}
*wrk = 0;
return buff;
}
example usage:
int main(void)
{
char str[17];
printf("`%s`\n", StringCreateStrForFlashOneProduct(str, 16, 1234));
}

Write binary file C from unsigned char

I'm making a program that writes a binary file, the content of this binary file are in an unsigned char pointer. The next code is the way that I using to generate the binary
while (f > 0) {
oct = (unsigned char) *datosOct->informacion++;
for (int i = 2; i >= 0; --i)
{
char actual = ((oct & (1 << i)) ? '1' : '0');
temporal = appendCharToCharArray(temporal, actual);
}
f--;
}
datosBin->informacion = (unsigned char*)temporal;
I had used fopen in mode wb, but it literals write a file with 1s and 0s. this is the function that I use to write (I using the default compiler of Visual Studio). I use the next code to write the file
file = fopen(nombreArchivo, "wb");
fwrite(datosBin->informacion, sizeof(char), archivoEnOctal->tamanio, file);
My starting point is a char array that contains '1's and '0's, each byte of '1's and '0's represents an ASCII value. For example, '1010000' is the ASCII 80 representing the letter 'P', if I transforms the binary char array ('1010000') to an array of chars ('P') when it finds values whose ASCII is 00 takes them as the end of the text and does not write them to the final file. One of the possible outputs of my code is an image, so I need to write these values 00. I tried this to write the chars directly, but this doesn't work for the images for the reason I mentioned before
while (f > 0) {
oct = (unsigned char) *datosOct->informacion++;
for (int i = 2; i >= 0; --i)
{
if (size == 8) {
size = 0;
char nuevaLetra = strtol(temporal, 0, 2);
if (nuevaLetra == 00) {
nuevaLetra = '\0';
//nuevaLetra = (char) 0;
}
response = appendCharToCharArray(response, nuevaLetra);
temporal = (char*)"";
}
size++;
char actual = ((oct & (1 << i)) ? 1 : 0);
temporal = appendCharToCharArray(temporal, actual);
}
f--;
}
I'll leave it to you to build and run it, before looking inside output.txt
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
unsigned char data;
unsigned char numBitsValid;
} bitAccumalator_t;
int main()
{
FILE *fp = fopen("output.txt", "wb");
char *inputStream = "011001000110111101100101011100110010000001110100011010000110100101110011001000000110100001100101011011000111000000111111";
int numBits = strlen(inputStream);
bitAccumalator_t outBuffer = {0,0};
for (int i=0; i<numBits; i++)
{
outBuffer.data <<= 1;
if (inputStream[i] == '1')
{
outBuffer.data |= 1;
}
outBuffer.numBitsValid++;
if (outBuffer.numBitsValid == 8)
{
fwrite(&outBuffer.data, 1, 1, fp);
outBuffer.data = 0;
outBuffer.numBitsValid = 0;
}
}
fclose(fp);
return 0;
}

how to store the value of a variable to string array?

Here I have created a string and I am storing the binary value of a number in the string.. I want to store the value of the variable num to the string.
i contains the length of the binary number for the given decimal number..suppose the given number is A=6, i contains 3 and i need a string 'result' having '110' which is the binary value of 6.
char* result = (char *)malloc((i)* sizeof(char));
i--;
while(A>=1)
{
num=A%2;
result[i]=num; // here I need to store the value of num in the string
A=A/2;
i--;
}
It appears from the code you've posted is that what you are trying to do is to print a number in binary in a fixed precision. Assuming that's what you want to do, something like
unsigned int mask = 1 << (i - 1);
unsigned int pos = 0;
while (mask != 0) {
result[pos] = (A & mask) == 0 ? '0' : '1';
++pos;
mask >>= 1;
}
result[pos] = 0; //If you need a null terminated string
edge cases left as an exercise for the reader.
I'm not sure specifically what you are asking for. Do you mean the binary representation (i.e. 00001000) of a number written into a string or converting the variable to a string (i.e. 8)? I'll assume you mean the first.
The easiest way to do this is to repeatedly test the least significant bit and shift the value to the right (>>). We can do this in for loop. However you will need to know how many bits you need to read. We can do this with sizeof.
int i = 15;
for (int b = 0; b < sizeof(i); ++b) {
uint8_t bit_value = (i & 0x1);
i >>= 1;
}
So how do we turn this iteration into a string? We need to construct the string in reverse. We know how many bits are needed, so we can create a string buffer accordingly with an extra byte for NULL termination.
char *buffer = calloc(sizeof(i) + 1, sizeof(char));
What this does is allocates memory that is sizeof(i) + 1 elements long where each element is sizeof(char), and then zero's each element. Now lets put the bits into the string.
for (int b = 0; b < sizeof(i); ++b) {
uint8_t bit_value = (i & 0x1);
size_t offset = sizeof(i) - 1 - b;
buffer[offset] = '0' + bit_value;
i >>= 1;
}
So what's happening here? In each pass we're calculating the offset in the buffer that we should be writing a value to, and then we're adding the ASCII value of 0 to bit_value as we write it into the buffer.
This code is untested and may have some issues, but that is left as an exercise to the reader. If you have any questions, let me know!
here is the whole code. It is supposed to work fine.
int i=0;
int A;//supposed entered by user
//calculating the value of i
while(A!=0)
{
A=A/2;
i++;
}
char* result=(char *)malloc(sizeof(char)*i);
i--;
while(A!=0)
{
result[i]='0'+(A%2);
A=A/2;
i--;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
char *numToBinStr(int num){
static char bin[sizeof(int) * CHAR_BIT + 1];
char *p = &bin[sizeof(int) * CHAR_BIT];//p point to end
unsigned A = (unsigned)num;
do {
*--p = '0' + (A & 1);
A >>= 1;
}while(A > 0);//do-while for case value of A is 0
return p;
}
int main(void){
printf("%s\n", numToBinStr(6));
//To duplicate, if necessary
//char *bin = strdup(numToBinStr(6));
char *result = numToBinStr(6);
char *bin = malloc(strlen(result) + 1);
strcpy(bin, result);
printf("%s\n", bin);
free(bin);
return 0;
}
You could use these functions in <stdlib.h>:
itoa(); or sprintf()
The second link has some examples as well.

What changes do I make to this function to optimize the execution time?

unsigned int lookup_bloom(unsigned char (*id)[HEXXID], unsigned int len,
void *bf)
{
int i;
struct bloom_structure *filter = (struct bloom_structure *) bf;
unsigned int *nexthop = NULL;
// The returned values of counting_bloom_check() are 0 if found else 1
unsigned char matchvec[WDIST] = {1};
unsigned char tmp1[HEXXID + 1] = {0};
unsigned char tmp2[HEXXID] = {0};
memcpy(tmp1, id, HEXXID);
memcpy(tmp2, tmp2, HEXXID);
// Although the paper suggests to perform parallel membership queries
for (i = len; i >= MINLENGTH; i--) {
tmp1[i / BYTE] = tmp1[i / BYTE] >> (BYTE - i % BYTE) <<
(BYTE - i % BYTE);
if (!filter->flag[i - MINLENGTH])
continue;
matchvec[i - MINLENGTH] =
counting_bloom_check(filter->bloom[i - MINLENGTH], tmp1,
HEXXID);
}
// Parse the matchvec from longest to shortest to perform table search
for (i = len; i >= MINLENGTH; i--) {
tmp2[i / BYTE] = tmp2[i / BYTE] >> (BYTE - i % BYTE) <<
(BYTE - i % BYTE);
if (matchvec[i - MINLENGTH] || !filter->flag[i - MINLENGTH])
continue;
nexthop = hashit_lookup(filter->hashtable[i - MINLENGTH],
tmp2);
if (nexthop)
return *nexthop;
}
return 0;
}
Here are some definitions used in the code:
#define WDIST 140
#define MINLENGTH 20
struct bloom_structure {
bool flag[WDIST];
unsigned int length[WDIST];
int low[WDIST];
int high[WDIST];
counting_bloom_t *bloom[WDIST];
hash_t hashtable[WDIST];
};
I am measuring the time of execution of this function.
Could anybody help me in optimizing this routine?
It would be great if someone could suggest any changes to write the loops in order to reduce the execution time.
Thank You in advance!
Depending on how critical this function is you could try to minimize the number of divisions ( / and % ) performed as they are the most costly operations for the CPU.
You could possibly merge your two loops as they use the same range. This way you could use the same index calculations (those that imply divisions) in a variable.
If you really want to push this, you could precalculate all the indexes that imply division computation so that the values are accessed from an array or any container deemed fit.

Decoding a base64 encoded binary string in C

I am trying to get my decoder code to work. I am using the example 64-bit encoded string from wikipedia, trying to reproduce the text they encoded.
#include <stdio.h>
//Convert raw binary character to the cb64 index
unsigned char get_cb64(unsigned char c){
if(c>='A' && c<='Z'){return c-'A';}
if(c>='a' && c<='z'){return c-'G';}
if(c>='0' && c<='9'){return c+4;}
if(c=='+'){return '>';}
if(c=='/'){return '?';}
else{return 0;}
}
void main(int argc, char** argv)
{
unsigned char* str = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=";
//convert each binary character to its cb64 index
int size = 360;
int num_bytes = 8;
unsigned char str_cb64[size + 1];
int cb64_idx;
int i;
for(i=0; i < size; i++){
str_cb64[i]=get_cb64(str[i]);
}
str_cb64[size] = 0;
//convert blocks of 4 6 bit chars to 3 8 bit chars
int end_size = size*6/8;
unsigned char ascii_out[end_size];
int out_idx = 0;
int in_idx = 0;
while(in_idx < end_size/4){
ascii_out[out_idx] = str_cb64[in_idx+0] << 2 | str_cb64[in_idx+1] >> 4;
ascii_out[out_idx+1] = str_cb64[in_idx+1] << 4 | str_cb64[in_idx+2] >> 2;
ascii_out[out_idx+2] = str_cb64[in_idx+2] << 6 | str_cb64[in_idx+3];
out_idx += 3;
in_idx += 4;
}
for(i=0; i < end_size; i++){printf("%d\n",ascii_out[i]);}
}
To inspect, the code here prints the ascii value of each decoded character, which SHOULD be between 48 and 122, but there are values from (0, 255). I tested the conversion from the raw binary to the cb64 index, and that seems to work fine. The problem is in my shifting code. Any idea why it isn't working? I double checked the shifts and they look like they are coded correctly.
Thanks!
Your loop should be either while(in_idx < size) or while(out_idx < end_size). Right now you are comparing an input value to an output value, as well as dividing the output value even though you add one for each byte instead of each iteration. This will cause your loop to exit well before all of the data has been processed. Since ascii_out wasn't initialized, this could be the only problem if the beginning of the output is right, since the end will contain random data which happened to be in that space.

Resources