Convert blob of data to align with structure - c

char buf[512] = { 0 };
int ret = recv(gSock, buf, 512, 0);
typedef struct _STRUCT {
int package;
int version;
char string[512];
} STRUCT, *PSTRUCT;
PSTRUCT ok;
ok = (PSTRUCT)buf;
I am trying to accept a buffer from a socket (Code not here, but it is working). It accepts it and places it into buf. I then want to cast this buf as a structure STRUCT. I want the first 4 bytes to go into the first member, second 4 bytes into the second member, and then the remaining data to go into the last member. However this is not working like I expected. I am getting weird large numbers that are not what I am receiving.
I entered 1111111111 (10) and the results I got back were;
package = 825307441
version = 825307441
string = 11\n
I did a decimal to hex conversion on the package number and it comes back as '31313131', which is my first 4 1's. So I am not to sure why it is going from integer, to hex back to a integer. I want just exactly what sends to go into the structure.

You have to review the following functions:
htonl, htons, ntohl, ntohs - convert values between host and network byte order.

Related

Processing binary data containing different length

So I have some binary data that I read, process and need to "split" into different variables, like this:
int *buffer;
buffer = malloc(size);
fread(buffer,size,1,file);
buffer = foo(buffer);
The result looks something like this in my debugger:
01326A18 5F4E8E19 5F0A0000
I want the first byte ( 01 ) to be int a.
The following 4 bytes are the first timestamp b (should be 5F186A32)
The following 4 bytes are the second timestamp c (should be 5F198E4E)
The 0A is supposed to be int d.
My Problem is that I can put the 1 into a, with (*buffer) & 0xff;, but I'm not able to read the first timestamp correctly since its from second to 5th byte and not align with the int declaration of the buffer.
If I print *(buffer +1) it gives me the second int and prints "198E4E5F"
It would be better if I were able to target n byte from every position in my data.
thx in advance.
Something like this will work on most little-endian platforms. Just fread the same way.
struct {
uint8_t a;
uint32_t timeStamp1;
uint32_t timeStamp2;
uint8_t d;
} buffer __attribute__((packed));
assert(sizeof buffer == 10); /* check packing */
If you set your buffer type as char* this will make it point to the 1 byte of chunks. Then if try to get buffer+2, it will return the second byte of the buffer, unlike int pointer which will return the 8th byte of the buffer. Do not forget to update your size in malloc call, since you get your memory with 1 byte chunks in this case. Also this link may be helpful.

How do I fix this method for reading structs and putting them in the linked list?

I need to read a file and place it inside a struct in a double linked list.
But my method doesn't work int insert_File(List* pointer_to_pointer) . Someone can help? How can I fix it? How to read this file and place it correctly in each variable in the struct? Thanks guys.
/* ListStudent.h */
struct student
{
char name[30];
int cod_student;
float test_1, test_2, activity, test_optional; /* if test_optional not exist in list_students.txt complete with 0 in struct */
};
typedef struct element* List;
int insert_File(List* pointer_to_pointer);
/* ListStudent.cpp */
struct element
{
struct element *previous;
struct student database;
struct element *next;
};
int insert_File(List* pointer_to_pointer)
{
if(pointer_to_pointer == NULL)
return 0;
element *node = *pointer_to_pointer;
FILE *pointer_to_file;
struct student s;
pointer_to_file = fopen("list_students", "r");
if(NULL == pointer_to_file)
{
cout << "ERROR";
return 1;
}
while(fread(&s, sizeof(struct student), 1, pointer_to_file))
{
int a = insert_list_sorted_ascending_by_name(pointer_to_pointer, s);
}
fclose(pointer_to_file);
return 0;
}
/* ListStudent_main.cpp */
#include "ListStudent.cpp"
int main(){
List *pointer_to_pointer;
pointer_to_pointer = create_list();
int f = insert_File(pointer_to_pointer);
return 0;
}
File txt
Marcos David 885487 9.4 5.4 8.5 0
Victor Corleone 445587 9.8 5.7 9.5 9
Alban Sernen 115400 8.4 8.4 5.5
Alban Aline 775487 1.4 2.4 1.5 1.1
Alban Victor 905487 2.4 2.6 4.5 1.5
Data representation in file is not the same as in memory.
While, for instance, the int value in memory consists of an exact, fix number of bytes (typically four on modern hardware), numbers in text consist of a variable series of bytes. Additionally, the values of the bytes are not the same.
885487 in a text file consists of the bytes 0x38 0x38 0x35 0x34 0x38 0x37, whereas the same number in memory (32-bit int provided) looks like 0xEF 0x82 0x0D 0x00 (little endian representation!).
Sizes of other members do not match either, additionally, there will be no space character (0x20) in between the binary data members.
For illustration: Data inside s after first call to
fread(&s, sizeof(struct student), 1, pointer_to_file):
name == "Marcos David 885487 9.4 5.4 8." // you read EXACTLY 30 chars
cod_student == 170 926 133 // "5 0\n" interpreted as 32-bit int (little endian)
test_1 == <some value> // "Vict" interpreted as 32-bit float
test_2 == <some value> // "or C" interpreted as 32-bit float
activity == <some value> // "orle" interpreted as 32-bit float
test_optional == <some value> // "one " interpreted as 32-bit float
I didn't make the effort to convert the characters to actual floating point values, suppose it's pretty obvious that the values won't be those you actually wanted to have... I assumed unix line endings – if you use windows ones, then there will be an additional \r character in front of the \n, shifting the characters used for filling the floats by 1, but that won't change anything in reading unwanted data.
You now have two options:
Either you store the students already as binary (while writing, open file with "wb" option, for reading use "rb", to make sure that there won't be special handling for line breaks). Be aware that the file won't be human readable any more then!
Or you need to convert the textual data into binary one.
For the latter option I personally would read the file line by line (C: fgets; C++: std::getline) and parse these lines on their own.
You are in the unlucky situation that you have chosen a separator character for the data items that can occur in one of the data fields as well: the space character. If you change the field separator to something different (e. g. | – there are special separator characters as well, ASCII 0x1C – 0x1F, ideal for our purpose on reading, but hard to enter in a text editor...), then you will make your life much easier: Just tokenise the string with this separator character and convert the substrings.
For now, you'd look up in the string the first digit (assuming that digits won't occur in a name) and copy the characters in front of (apart from the last space) into the name field. Don't forget to null-terminate the string.
From now on, you can just tokenise, beginning at the digit just found before. In C, have a look at strtok function for tokenising and at strtol and strtof for conversion.
In C++ (as you tagged that initially), there are quite a number of different ways how you can process the remaining string (maybe simplest using a std::istringstream).

How do you read to a struct via fread given specific byte format?

I'm having trouble reading from a binary file into a struct given a specific format. As in, given a byte-by-byte definition (Offset: 0 Length: 2 Value: 0xFF 0xD8, Offset: 2 Length: 2 Value: 0xFF 0xE1, etc), I'm not sure how to define my structure nor utilize file operations like fread(); to correctly take in the information I'm looking for.
Currently, my struct(s) are as follows:
struct header{
char start; //0xFF 0xD8 required.
char app1_marker; //0xFF 0xE1 required. Make sure app0 marker (0xFF 0xE0) isn't before.
char size_of_app1_block; //big endian
char exif_string; //"EXIF" required
char NULL_bytes; //0x00 0x00 required
char endianness; //II or MM (if not II break file)
char version_number; //42 constant
char offset; //4 blank bytes
};
and
struct tag{
char tag_identifier;
char data_type;
char size_of_data;
char data;
};
What data types should I be using if each attribute of the structure has a different (odd) byte length? Some require 2 bytes of space, others 4, and even others are variable/dynamic length. I was thinking of using char arrays, since a char is always one byte in C. Is this a good idea?
Also, what would be the proper way to use fread if I'm trying to read the whole structure in at once? Would I leave it at:
fread(&struct_type, sizeof(char), num_of_bytes, FILE*);
Any guidance to help me move past this wall would be greatly appreciate. I already understand basic structural declerations and constructions, the two key issues I'm having is the variance and odd byte sizes for the information and the proper way to read variable byte sizes into the struct in one fread statement.
Here is the project link:
http://people.cs.pitt.edu/~jmisurda/teaching/cs449/2141/cs0449-2141-project1.htm
I usually see fread() on structures specify the size as the structure size, and the number of elements as 1, and the expectation that fread() returns 1:
size_t result = fread(&record, num_of_bytes, 1, infile);
I am uncertain how you figure out if your endianess field is II or MM, but I guess the idea is that you could decide whether or not to fix up the field values based on whether the file endianess matches the host endianess.
The actual data seems to be the tag structures, and the last field data is actually just a place holder for variable length data that is specified in the size_of_data field. So I guess you would first read sizeof(struct tag) - 1 bytes, and then read size_of_data more bytes.
struct tag taghdr;
size_t result = fread(&taghdr, sizeof(taghdr) - 1, 1, infile);
if (result != 1) { /* ...handle error */ }
struct tag *tagdata = malloc(sizeof(taghdr) + taghdr.size_of_data - 1);
if (tagdata == 0) { /*...no more memory */ }
memcpy(tagdata, &taghdr, sizeof(taghdr) - 1);
if (taghdr.size_of_data > 0) {
result = fread(&tagdata->data, taghdr.size_of_data, 1, infile);
if (result != 1) { /*...handle error */ }
}

breaking up a char array into a structure

In case someone gets this issue in the future I'll leave this up.
*Note This approach wasn't going to work when going from C client to C server. This would have only worked with the Java client to C server. So I had to abandoned this approach.
Ok, I've been fighting with C for too long now. I'm passing some info with UDP from a java client to a C server. I can get the info there, but I'm not sure how to break apart the message to store into a struct like so
struct __attribute__((__packed__)) clientMessage
{
short tml;
short rid;
char op;
char message[MAXBUFLEN-5];
};
I recieve the message like this
Where test is a char test[MAXBUFLEN-5];
if ((numbytes = recvfrom(sockfd, test, MAXBUFLEN-1, 0,
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);}
So, I need to take the message "7 2 1Yo" (two 2 byte shorts and a char followed by an unknown message length) and store it into it's appropriate parts in the struct. The message gets sent correctly, I just can't break it into the bits of info that I need. I'm currently attempting
memcpy(&cm.rid, &test, 2);
memcpy(&cm.tml, &test[1], 2);
memcpy(&cm.op, &test[4], 1);
memcpy(&cm.message, &test[5], MAXBUFLEN-5);
But my resutls end up being
Message: Yo
OP: 1Yo
RID: 7 1Yo
TML: 2 7 1Yo
it Should be
Message: Yo
OP: 1
RID: 2
TML: 7
I successfully get the message, but nothing else. I'm relatively new to C so forgive my ignorance. I'm guessing this is really easy but idk.
The first line should be memcpy(&cm.rid, &test[0], 2);, for the address is supposed to be the address of the first byte.
And the rest:
memcpy(&cm.tml, &test[2], 2); // you want to get the third and forth byte, begin with index 2.
memcpy(&cm.op, &test[4], 1); // the fifth byte, begin with index 4.
memcpy(&cm.message, &test[5], MAXBUFLEN-5); // the rest bytes.
If you are using a binary protocol, it would be better to use e.g. int16_t instead of short in the declaration of clientMessage because the size of short is not specified within the c standard.
To access the message stored in test you could do simply something like this:
struct clientMessage *cm = (struct clientMessage *) test;
You should also notice, that the endianness of network protocols is different from the endianness of a x86 and amd64 architecture, so instead of 42 you might recieve 10752.
To fix this you can use the ntohs() (Network TO Host Short) function to acces the tm and rid.
Use sscanf() for the first part and memcpy() for the text.
const char *message = "7 2 1Yo";
struct clientMessag cM;
int offset = 0;
int n;
n = sscanf(message, "%hd %hd %c%n", &cM.tml, &cM.rid, &cM.op, &offset);
size_t SuffixLength = strlen(&message[offset]);
if ((n != 3) || (SuffixLength >= sizeof(cM.message))) {
exit(1); // handle syntax error;
}
memcpy(cM.message, &message[offset], SuffixLength + 1);
// Additional field checks like IsOKOpCode(cM.op)
I avoided %s as it does not store whitespace into your message.
Error checking is always good to do. Recommend additional field checks.
BTW: its not clear if the cM.op field should be treat as text or a number. Does the OP want a 1 or '1' stored? The above assume text. Alternatively one could use "%hd%hd%hhd%n".
Since test contains the string "7 2 1Yo", you have to parse the string into the values you want. You can do this with sscanf():
char fmt[256];
snprintf(fmt, sizeof(fmt), "%%hd %%hd %%c%%%ds", MAXBUFLEN-5-1);
sscanf(test, fmt, &cm.rid, &cm.tml, &cm.op, cm.message);
In this code fragment above, we create a format string for the parsing. This is necessary to prevent sscanf() from scanning past the end of the message in the case that it is not \0 terminated. The result of the snprintf() call with a MAXBUFLEN of 128 is:
"%hd %hd %c%122s"
Which tells sscanf() to scan for two short decimal numbers, a char, and a string no longer than 122 characters.

sprintf is outputting some strange data

I am working an embedded project which involves reading/writing a struct into EEPROM. I am using sprintf to make it easy to display some debugging information.
There are two problems with this code for some reason. The first; sprintf is printing a very strange output. When I print 'addr++' it will follow a pattern '0, 1, 2, 3, 4, 32, ...' which doesn't make sense.
void ee_read(char * buf, unsigned int addr, unsigned int len) {
unsigned int i;
sprintf(bf1, "Starting EEPROM read of %u bytes.\r\n", len); // Debug output
debugr(bf1);
IdleI2C1();
StartI2C1();
WriteI2C1(EE_ADDR | EE_W);
IdleI2C1();
WriteI2C1((unsigned char)addr>>8); // Address to start reading data from
IdleI2C1();
WriteI2C1((unsigned char)addr&0xFF);
IdleI2C1();
RestartI2C1();
WriteI2C1(EE_ADDR | EE_R);
IdleI2C1();
for (i=0; i<len; i++) {
buf[i] = ReadI2C1(); // Read a byte from EEPROM
sprintf(bf1, "Addr: %u Byte: %c\r\n", addr, buf[i]); // Display the read byte and the address
debugr(bf1);
addr++; // Increment address
IdleI2C1();
if (i == len-1) { // This makes sure the last byte gets 'nAcked'
NotAckI2C1();
} else {
AckI2C1();
}
}
StopI2C1();
}
The output from the above is here: https://gist.github.com/3803316 Please note that the about output was taken with %x for the address value (so addr is hex)
The second problem, which you may have noticed with the output, is that it doesn't stop when i > len. It continues further than the output I have supplied, and doesn't stop until the microcontroller's watch dog restarts.
Edit:
Calling the function
Location loc;
ee_read(&loc, 0, sizeof(Location));
Declarations:
struct location_struct {
char lat[12]; // ddmm.mmmmmm
char latd[2]; // n/s
char lon[13]; // dddmm.mmmmmm
char lond[2]; // e/w
char utc[11]; // hhmmss.sss
char fix[2]; // a/v
};
typedef struct location_struct Location;
char bf1[BUFFER_SIZE];
I don't think it's a race condition. I disable the interrupts which use bf1. Even then, it would corrupt the whole debug string if that happened, and it certainly wouldn't be so repeatable.
Edit
The value of addr starts as zero, which can be seen here: https://gist.github.com/3803411
Edit
What this is supposed to do it copy the location structure byte by byte into the EEPROM, and then recall it when it is needed.
Closure
So I never did solve this problem. The project moved away from the EEPROM, and I have since changed OS, compiler and IDE. It's unlikely I will replicate this problem.
I'll tell you one thing wrong with your code, this line:
(unsigned char)addr>>8
doesn't do what you seem to need.
It converts the value in addr into an unsigned char which (assuming 8-bit char and either 16-bit int or only using the lower 16 bits of a wider int), will will always give you the lower eight bits.
If you then right shift that by eight bits, you'll always end up with zero.
If your intent is to get the upper eight bits of the address, you need to use:
(unsigned char)(addr>>8)
so that the shift is done first.

Resources