I m not able to truncate the buffer from the size what I want. I'm bit perplexed why I get wrong results? Even though my usage of memcpy() is right. I read the man page also. I'm doing something wrong here?
What I want to achieve:
Buff: 00 83 00 00 16 0a 44 00 00 00 00 bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
Copy the bytes which start from bd, that means 12th bytes till the end-
Desired Output should be:
bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
This is my code:
I'm receiving the response from serial device and I need chop some bytes.
void rx_dev(transport, int addr, const void *buf, unsigned count) {
uint8_t s[1024];
uint8_t *p;
memset (s, 0, sizeof(s));
// This below function does only the hex parsing.
hex_parse(s, sizeof(s), buf, count);
printf("* %02x %s\n", addr, s);
printf("Count: %zu\n", count);
p = s;
printf("p* %s\n", p);
// I'm doing this check to avoid something greater than 14.
if (count > 14) {
memcpy(p, s+11, count-11);
printf("*Trim:%s\n", p);
}
}
EDIT: Added the more details
int hex_parse(char *out, unsigned size, const void *buf, unsigned count)
{
const uint8_t *p = buf;
unsigned i;
int n = 0;
if (count)
{
if (n + 2 < size)
{
out[n+0] = hexchars[(p[0] >> 4) & 15];
out[n+1] = hexchars[p[0] & 15];
}
n += 2;
}
for (i = 1; i < count; i++) {
if (n + 3 < size)
{
out[n+0] = ' ';
out[n+1] = hexchars[(p[i] >> 4) & 15];
out[n+2] = hexchars[p[i] & 15];
}
n += 3;
}
if (n < size)
out[n] = '\0';
else if (size)
out[size-1] = '\0';
return n;
}
My ouutput:
* 01 00 83 00 00 16 0a 44 00 00 00 00 bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
p* 00 83 00 00 16 0a 44 00 00 00 00 bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
Here I don't get the correct output, why is it prinitng 28bytes, this is not my desired result I wanted?
Trim: 16 0a 44 00 00 0 44 00 00 00 00 bd 0e 8a 0c 61 01 13 51 24 ad 9a 0b 1c 0e ff ff 00
You can use memmove , as in memcpy the target and the source must not overlap each other, while in memmove it does not matter. So you can do
int offset = 11,size = 28;
memmove(buf, buf+off, size - off);
The source and destination in your memcpy call overlap. From the standard:
If copying takes place between objects that overlap, the behavior
is undefined.
The standard function memmove is like memcpy but defined for overlapping objects, use that instead.
When you're calling memcpy, you're not copying the bytes from the buffer. You're copying the "hex_parsed" string. As that format uses 3 characters per byte (2 digits and a space), chopping 11 characters is chopping about 4 bytes.
Related
I'm having an issue with (I think) memory reallocation in C. The program is meant to run such that when fopen(array, &num); is called, it will first retrieve the number of elements in the array from file and place that in num, reallocate memory for the array pointer given to give it enough room to store the contents of the file proper, then copy the values over into that array. This seems to work while still in the fopen function (shown by 'mark 1'), but does not work outside of this (shown by 'mark 2') instead seeming to spew out random memory garbage. Any help appreciated (both with code and formatting my poorly laid out question).
//main.c
void Rtest(){
char num;
struct individual *array;
array = (struct individual *) malloc(sizeof(struct individual));
openf(array, &num);
printf("%d\n", num);
for (int i = 0; i < num; i++) {printf("%s\n", array[i].name);} //mark 2
free(array);
}
//fil.h
struct individual {
char name[32];
char stats[7];
char role;
char roles[13];
};
void openf(struct individual *array, char *num){
FILE *fp;
fp = fopen("save.bin", "rb");
fread(num, 1, sizeof(char), fp);
array = (struct individual *)realloc(array, *num * sizeof(struct individual));
printf("%d\n", sizeof(*array));
fread(array, *num, sizeof(struct individual), fp);
for (int i = 0; i < *num; i++) {printf("%s\n", array[i].name);} //mark 1
fclose(fp);
}
File contents:
03 43 61 72 6C 73 6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04 05 06 08 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 43 61 72 6C 73 6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04 05 06 08 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 43 61 72 6C 73 6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04 05 06 08 00 01 02 03 04 05 06 07 08 09 0A 0B 0C
When you want to change the argument inside a function, you pass a pointer to it.
For example, inside Rtest you declared a char called num. It has no value, and you sent it to openf, But you actually sent the pointer to num since you wanted to change its value, you did it correctly and indeed openf changed num value successfully.
But how about array? Well, you declared it on Rtest and allocated space in memory for it, which is all correct. Then, you wanted to send it to Rtest as a pointer so the function could change it.
array is a variable of the type "pointer to struct individual". This is okay, but if you wanted to change it inside Rtest, well you need to send a pointer for that variables.. hence, you needed a "POINTER TO pointer to struct individual". Note that the variable name was copied from before and I just added "POINTER TO"
I'm sure you know what pointer to pointer is, and what you needed to do is use:
openf(&array, &num);
And of course modift openf as well so it will use the new "pointer to pointer", something like that:
void openf(struct individual **array, char *num){
FILE *fp;
fp = fopen("save.bin", "rb");
fread(num, 1, sizeof(char), fp);
*array = (struct individual **)realloc(*array, *num * sizeof(struct individual));
printf("%d\n", sizeof(**array));
fread(*array, *num, sizeof(struct individual), fp);
for (int i = 0; i < *num; i++) {printf("%s\n", (*array)[i].name);} //mark 1
fclose(fp);
}
When I run this code on my machine, along with Rtest and provided save.bin I get the following output:
53
Carlson
Carlson
Carlson
3
Carlson
Carlson
Carlson
EDIT:
As #WhozCraig mentioned in the comments, You could use the unused return value for the function and return the pointer for the "new" array, which might be a slightly better way of doing things here instead of the "pointer to pointer" stuff, but its up to you.
Unexpected MAC-address value obtained using snprintf function
Why do I get "Unexpected mac-address value. I have big string (unsigned char data[DATA_LEN ]) to parse and copy mac address to the structure member. I am getting completely different string. Please help on this, Thank you.
Input data string:
unsigned char data[512] = "its-STRING: 18 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AC 12 00 20 00 00 00 C8 8C DF 9D 57 12 20 00 00 00 29 \n";
Output of the program
Parsed Mac from string = 8C DF 9D 57 12 20
copied MacAddress == 32:30:3a:33:38:00
From the above mentioned string i have to extract the mac-address "8C DF 9D 57 12 20"and then i have to copy this mac-address into the following structure
typedef struct my_stuct_s{
uint8_t mac_addr[18];
}my_stuct_t;
Below is how I have the coded.
#define PARSE_OFFSET 89
#define END_OFFESET 19
#define DATA_LEN 512
#define ADDR_LEN 6
typedef struct my_stuct_s{
uint8_t mac_addr[ADDR_LEN];
uint8_t item;
}my_stuct_t;
int main()
{
unsigned char data[DATA_LEN] = "its-STRING: 18 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AC 12 00 20 00 00 00 C8 8C DF 9D 57 12 20 00 00 00 29 \n";
unsigned char strv6[ADDR_LEN];
unsigned char *data1 = NULL;
my_stuct_t shm_memory;
memset(strv6, 0,sizeof(strv6));
memset(&shm_memory, 0,sizeof(my_stuct_t));
if ((strcmp(data, "") ) != 0)
{
data1 = &data[0];
data1 = data1 + PARSE_OFFSET;
snprintf(strv6, END_OFFESET,"%s\n", data1);
printf("Parsed Mac from string = %s\n", strv6);
snprintf((char *)&shm_memory.mac_addr, ADDR_LEN,
"%02x:%02x:%02x:%02x:%02x:%02x\n",
strv6[0], strv6[1],
strv6[2], strv6[3],
strv6[4], strv6[5]);
printf("copied MacAddress == %02x:%02x:%02x:%02x:%02x:%02x\n ",
shm_memory.mac_addr[0],
shm_memory.mac_addr[1],
shm_memory.mac_addr[2],
shm_memory.mac_addr[3],
shm_memory.mac_addr[4],
shm_memory.mac_addr[5]);
}
else
printf("\n empty string");
return 0;
}
Your parse offset starts at 89 and number of chars to be copied are 18.
#define PARSE_OFFSET 89
#define END_OFFESET 19
should be
#define PARSE_OFFSET 90
#define END_OFFESET 18
Length of the char array which stores the address should be 19.
unsigned char strv6[19];
You need to use sscanf not sprintf as below.
sscanf(strv6, "%02x %02x %02X %02x %02x %02x\n",
&shm_memory.mac_addr[0],
&shm_memory.mac_addr[1],
&shm_memory.mac_addr[2],
&shm_memory.mac_addr[3],
&shm_memory.mac_addr[4],
&shm_memory.mac_addr[5]);
I'm trying to read UTF file and decided to read it in binary mode and skip non-ASCII as file consists of valid english text basically. I'm stuck at fread returning 1 instead of number of bytes requested. First output of print_hex IMHO shows it has read more than 1 char. I've read some examples of reading binary files in C e.g Read and write to binary files in C?, read about fread e.g. here https://en.cppreference.com/w/c/io/fread and here How does fread really work?, still puzzled why it returns 1. File hexdump, and complete C code and output below.
ADD: compiled by gcc, run on Linux.
File:
00000000 ff fe 41 00 41 00 42 00 61 00 0d 00 0a 00 41 00 |..A.A.B.a.....A.|
00000010 41 00 45 00 72 00 0d 00 0a 00 66 00 73 00 61 00 |A.E.r.....f.s.a.|
00000020 6a 00 0d 00 0a 00 64 00 73 00 61 00 66 00 64 00 |j.....d.s.a.f.d.|
00000030 73 00 61 00 66 00 64 00 73 00 61 00 0d 00 0a 00 |s.a.f.d.s.a.....|
00000040 64 00 66 00 73 00 61 00 0d 00 0a 00 66 00 64 00 |d.f.s.a.....f.d.|
00000050 73 00 61 00 66 00 73 00 64 00 61 00 66 00 0d 00 |s.a.f.s.d.a.f...|
00000060 0a 00 0d 00 0a 00 0d 00 0a 00 |..........|
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_hex(const char *s)
{
while(*s)
printf("%02x ", (unsigned char) *s++);
printf("\n");
}
int main(){
#define files_qty 5
const char* files_array[][2]={{"xx","a"},{"zz","b"},{"xxx","d"},{"d","sd"},{"as","sd"}};
const char* file_postfix = ".txt";
char* file_out_name = "XXX_AD.txt";
FILE* file_out = fopen (file_out_name, "w");
printf ("This app reads txt files with hardcoded names and writes to file %s\n",file_out_name);
/* ssize_t bytes_read = 1; //signed size_t */
size_t n_bytes = 10;
unsigned char* string_in;
char* string_out;
char* file_name;
string_in = (char*) malloc (n_bytes+1);
string_out = (char*) malloc (n_bytes+50);
file_name = (char*) malloc (n_bytes+1); /* more error prone would be to loop through array for max file name length */
int i;
size_t n;
for (i=0;i<files_qty;i++)
{
strcpy (file_name,files_array[i][0]);
FILE* file = fopen (strcat(file_name,file_postfix), "rb");
if (file!= NULL)
{
int k=0;
while (n=fread (string_in, sizeof(char), n_bytes, file)>0)
{
printf("bytes read:%lu\n",(unsigned long) n);
print_hex(string_in);
int j;
for (j=0;j<n;j++)
{
switch (string_in[j])
{
case 0x00:
case 0xff:
case 0xfe:
case 0x0a:
break;
case 0x0d:
string_out[k]=0x00;
fprintf (file_out, "%s;%s;%s\n", files_array[i][0], files_array[i][1], string_out);
k=0;
printf("out:\n");
print_hex(string_out);
break;
default:
string_out[k++]=string_in[j];
}
}
}
fclose (file);
}
else
{
perror (file_name); /* why didn't the file open? */
}
}
free (string_in);
free (string_out);
free (file_name);
return 0;
}
Output:
bytes read:1
ff fe 41
bytes read:1
0d
out:
bytes read:1
72
bytes read:1
61
bytes read:1
73
bytes read:1
61
bytes read:1
0d
out:
72 61 73 61
bytes read:1
61
bytes read:1
73
bytes read:1
61
bytes read:1
0a
You have a precedence problem. Simple assignment has lower precedence than comparison. So the following line:
while(n=fread (string_in, sizeof(char), n_bytes, file)>0)
is evaluated as (extra parenthesis)
while (n=(fread (string_in, sizeof(char), n_bytes, file)>0))
Therefore n is being assigned as 1 because fread is returning a value > 0
Instead, explicitly add parenthesis as:
while((n=fread (string_in, sizeof(char), n_bytes, file))>0)
/*HASHING*/
unsigned char *do_hashing(unsigned char *buffer){
unsigned char outbuffer[20];
unsigned char output[20];
SHA1(buffer, strlen(buffer), outbuffer);
for (int i=0; i<20; i++) {
output[i]=outbuffer[i];
}
printf("The hash: ");
for (int i = 0; i < 20; i++) {
printf("%02x ", outbuffer[i]);
}
printf("\n");
return output;
}
/*HASHING*/
Why does this function produce different output (wrong one) if I remove printf-function. For example:
./ftest
The hash: a1 2a 9c 6e 60 85 75 6c d8 cb c9 98 c9 42 76 a7 f4 8d be 73
The hash: a1 2a 9c 6e 60 85 75 6c d8 cb c9 98 c9 42 76 a7 f4 8d be 73
=with for-loop print
./ftest
The hash: 6c 08 40 00 00 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 00
=without for-loop print
I have not included the main-function or #includes in this case because error occurs inside this function.
You are returning a pointer to a local variable unsigned char output[20];,
The variable does not exist after the function ends causing undefined behavor.
At the moment, you are returning local pointer (that is placed on stack). This causes an undefined behavior.
If you want to do it, please use malloc() function to allocate memory in heap.
unsigned char* output = malloc(20*sizeof(unsigned char));
But don't forget to call free() to free the allocated memory, otherwise you'll get a memory leak.
i am studying C now, and I am parsing a raw registry file and read it.
i have some problem now,
000011E0 00 00 00 00 60 01 00 00 B9 01 00 00 00 00 00 00
000011F0 20 C0 26 00 FF FF FF FF 00 00 00 00 FF FF FF FF
00001200 10 FC 00 00 FF FF FF FF 4C 00 01 00 00 00 00 00
this is hex value of REGISTRY file.
fseek(fp,0x11F0,SEEK_SET);
char tmp[4];
int now = ftell(fp);
for(int i = 0 ; i < 4 ; i++){
tmp[i] = fgetc(fp);
}
I made this tmp array, but I need 0x0026c020.
how can I change this array to that value? or please suggest me better algorithm.
Thanks.
If you know for a fact that the value is stored with the same endianness as the host OS architecture, you can just do:
int value = *(int *)tmp;
However, you should not read the bytes in backwards order, as you do here -- that alters the endianness and will result in an incorrect value. Try this:
int value;
if (fread(&value, sizeof(value), 1, fp) != 1) {
/* Could not read, handle error. */
}
/* value is set, inspect it */
To convert a string into integer there are already available functions one such function is
strtoul().
you can use standard strtoul() function to convert string into integer values.