I have a flash memory dump file that spits out addresses and data.
I want to parse the data so that it will tell me the valid tags
The '002F0900' column are the starting addresses.
An example of a valid tag is "DC 08 00 06 00 00 07 26 01 25 05 09" where "DC 08" = tag number, "00 06" = tag data length, "00 00" = tag version. Tag data starts after the version and in this case would be "07 26 01 25 05 09" and the next tag would start "DC 33".
I'm able to print out the first tag up to the data length but I'm not sure how to print the data because I have to consider if the data will go onto the next line so I'd have to skip the address somehow. Each line contains 58 columns. Each address is 8 characters long plus a colon and 2 spaces until the next hex value starts.
I also will eventually have to consider when "DC" shows up in the address column.
If anyone could give some advice because I know how I'm doing this isn't the best way to do this. I'm just trying to get it to work first.
The text file is thousands of lines that look like this:
002F0900: 09 FF DC 08 00 06 00 00 07 26 01 25 05 09 DC 33
002F0910: 00 07 00 00 1F A0 26 01 25 05 09 FF 9C 3E 00 08
002F0920: 00 01 07 DD 0A 0D 00 29 35 AD 9C 41 00 0A 00 01
002F0930: 07 DD 0A 0D 00 29 36 1C 1D 01 9C 40 00 02 00 01
002F0940: 01 00 9C 42 00 0A 00 01 07 DD 0A 0D 00 29 36 21
002F0950: 1D AD 9C 15 00 20 00 00 01 00 00 00 00 04 AD AE
002F0960: C8 0B C0 8A 5B 52 01 00 00 00 00 00 FF 84 36 BA
002F0970: 4E 92 E4 16 28 86 75 C0 DC 10 00 05 00 00 00 00
002F0980: 00 00 01 FF DC 30 00 04 00 01 00 00 00 01 9C 41
Example output would be:
Tag Number: DC 08
Address: 002E0000
Data Length: 06
Tag Data: 07 26 01 25 05 09
Source Code:
#include<stdio.h>
FILE *fp;
main()
{
int i=0;
char ch;
char address[1024];
char tag_number[5];
char tag_length[4];
int number_of_addresses = 0;
long int length;
fp = fopen(FILE_NAME,"rb");
if(fp == NULL) {
printf("error opening file");
}
else {
printf("File opened\n");
while(1){
if((address[i]=fgetc(fp)) ==':')
break;
number_of_addresses++;
i++;
}
printf("\nAddress:");
for (i = 0; i < number_of_addresses;i++)
printf("%c",address[i]);
while((ch = fgetc(fp)) != 'D'){ //Search for valid tag
}
tag_number[0] = ch;
if((ch = fgetc(fp)) == 'C') //We have a valid TAG
{
tag_number[1] = ch;
tag_number[2] = fgetc(fp);
tag_number[3] = fgetc(fp);
tag_number[4] = fgetc(fp);
}
printf("\nNumber:");
for(i=0;i<5;i++)
printf("%c",tag_number[i]);
fgetc(fp); //For space
tag_length[0] = fgetc(fp);
tag_length[1] = fgetc(fp);
fgetc(fp); //For space
tag_length[2] = fgetc(fp);
tag_length[3] = fgetc(fp);
printf("\nLength:");
for(i=0;i<4;i++)
printf("%c",tag_length[i]);
length = strtol(tag_length,&tag_length[4], 16);
printf("\nThe decimal equilvant is: %ld",length);
for (i = 0;i<165;i++)
printf("\n%d:%c",i,fgetc(fp));
}
fclose(fp);
}
Update #ooga:The tags are written arbitrarily. If we also consider invalid tag in the logic then I should be able to figure out the rest if I spend some time. Thanks
This is just an idea to get you started since I'm not entirely sure what you need. The basic idea is that read_byte returns the next two-digit hex value as a byte and also returns its address.
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "UA201_dump.txt"
void err(char *msg) {
fprintf(stderr, "Error: %s\n", msg);
exit(EXIT_FAILURE);
}
// read_byte
// Reads a single two-digit "byte" from the hex dump, also
// reads the address (if necessary).
// Returns the byte and current address through pointers.
// Returns 1 if it was able to read a byte, 0 otherwise.
int read_byte(FILE *fp, unsigned *byte, unsigned *addr_ret) {
// Save current column and address between calls.
static int column = 0;
static unsigned addr;
// If it's the beginning of a line...
if (column == 0)
// ... read the address.
if (fscanf(fp, "%x:", &addr) != 1)
// Return 0 if no address could be read.
return 0;
// Read the next two-digit hex value into *byte.
if (fscanf(fp, "%x", byte) != 1)
// Return 0 if no byte could be read.
return 0;
// Set return address to current address.
*addr_ret = addr;
// Increment current address for next time.
++addr;
// Increment column, wrapping back to 0 when it reaches 16.
column = (column + 1) % 16;
// Return 1 on success.
return 1;
}
int main() {
unsigned byte, addr, afterdc, length, version, i;
FILE *fp = fopen(FILE_NAME,"r");
if (!fp) {
fprintf(stderr, "Can't open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
while (read_byte(fp, &byte, &addr)) {
if (byte == 0xDC) {
// Read additional bytes like this:
if (!read_byte(fp, &afterdc, &addr)) err("EOF 1");
if (!read_byte(fp, &length, &addr)) err("EOF 2");
if (!read_byte(fp, &byte, &addr)) err("EOF 3");
length = (length << 8) | byte;
if (!read_byte(fp, &version, &addr)) err("EOF 4");
if (!read_byte(fp, &byte, &addr)) err("EOF 5");
version = (version << 8) | byte;
printf("DC: %02X, %u, %u\n ", afterdc, length, version);
for (i = 0; i < length; ++i) {
if (!read_byte(fp, &byte, &addr)) err("EOF 6");
printf("%02X ", byte);
}
putchar('\n');
}
}
fclose(fp);
return 0;
}
Some explanation:
Every time read_byte is called, it reads the next printed byte (the two-digit hex values) from the hex dump. It returns that byte and also the address of that byte.
There are 16 two-digit hex values on each line. The column number (0 to 15) is retained in a static variable between calls. The column is incremented after reading each byte and reset to 0 every time the column reaches 16.
Any time the column number is 0, it reads the printed address, retaining it between calls in a static variable. It also increments the static addr variable so it can tell you the address of a byte anywhere in the line (when the column number is not zero).
As an example, you could use read_bye like this, which prints each byte value and it's address on a separate line:
// after opening file as fp
while (read_byte(fp, &byte, &addr))
printf("%08X- %02X\n", addr, byte);
(Not that it would be useful to do that, but to test it you could run it with the snippet you provided in your question.)
Related
I'm trying to open a bin file an get its data into a buffer and copy the data from that buffer to a section that I made called .my_data.
When I do hexdump binfile.bin I see
00000000 4455 e589 00bf 0000 e800 0000 00b8
00000010 5d00 00c3
00000015
and when I printf the buffer and buffer2 I see
55 48 89 e5 bf 00 00 00 00 e8 00 00 00 00 b8 00 00 00 00 5d c3
55 48 89 e5 bf 00 00 00 00 e8 00 00 00 00 b8 00 00 00 00 5d c3
which matches the output from hexdump. However when load buffer2 into my new section (I didn't include that part of the code), I used objdump -s -j .my_data foo and I see some other data not similar to the output above.
I apologize for the dumb question but I just want to confirm if the memcpy I used it's actually copying the data from buffer to buffer2 so I can discard this part and look for the error in the rest of my program. From the output of the second for loop I would think it is. I'm also using gcc, thanks.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
int main (){
uint8_t buffer[21];
uint8_t buffer2[21];
FILE *ptr;
ptr = fopen("binfile.bin", "rb");
size_t file_size = 0;
if(!ptr)
{
printf("unable to open file");
return 1;
}
fseek(ptr, 0, SEEK_END);
file_size = ftell(ptr);
rewind(ptr);
int i = 0;
fread(buffer, sizeof(buffer), 1, ptr);
memcpy(buffer2, buffer, sizeof(buffer));
for(i = 0; i < 21; i++)
{
printf("%02x ", buffer[i]);
}
printf("\n\n");
for(i = 0; i < 21; i++)
{
printf("%02x ", buffer2[i]);
}
fclose(ptr);
return 0;
}
You are thinking right as far as how you are approaching copying buffer to buffer2, but you are failing to ensure you only attempt to access the elements of buffer that are validly initialized. Since your file contains only 20 bytes, when you attempt to access buffer[20] you are attempting to access a variable with automatic storage duration while the value is indeterminate invoking Undefined Behavior. All bets are off.
You can handle this by fully initializing buffer, e.g.
uint8_t buffer[21] = {0);
which if you fill less than all elements with fread is still okay because all elements are validly initialized.
The other way is simply to read with the size parameter to fread set at 1 so fread returns the number of bytes read. Then you can use that value to output your results, e.g.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 1024 /* max number of characters (bytes) */
int main (int argc, char **argv) {
size_t nbytes = 0;
unsigned char buf1[MAXC] = {0}, buf2[MAXC] = {0};
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "rb") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
nbytes = fread (buf1, 1, MAXC, fp); /* with size=1, no. of bytes returned */
if (fp != stdin) /* close file if not stdin */
fclose (fp);
memcpy (buf2, buf1, nbytes); /* copy nbytes buf1, buf2 */
for (size_t i = 0; i < nbytes; i++) /* outuput buf1 contents */
printf (" %02x", buf1[i]);
putchar ('\n');
for (size_t i = 0; i < nbytes; i++) /* output buf2 contents */
printf (" %02x", buf2[i]);
putchar ('\n');
}
Example Use/Output
With your data in the file dat/bytes20.bin, you would receive:
$ ./bin/fread_bytes dat/bytes20.bin
44 55 e5 89 00 bf 00 00 e8 00 00 00 00 b8 5d 00 00 c3
44 55 e5 89 00 bf 00 00 e8 00 00 00 00 b8 5d 00 00 c3
Let me know if you have further questions.
here is the corrected code: note the & 0xFF when printing
uint8_t buffer[21];
uint8_t buffer2[21];
FILE *ptr;
ptr = fopen("binfile.bin", "rb");
size_t file_size = 0;
if (!ptr)
{
printf("unable to open file");
return 1;
}
fseek(ptr, 0, SEEK_END);
file_size = ftell(ptr);
rewind(ptr);
int i = 0;
fread(buffer, sizeof(buffer), 1, ptr);
memcpy(buffer2, buffer, sizeof(buffer));
for (i = 0; i < sizeof buffer; i++)
{
printf("%02x ", buffer[i] & 0xFF);
}
printf("\n\n");
for (i = 0; i < sizeof buffer2; i++)
{
printf("%02x ", buffer2[i] & 0xFF);
}
fclose(ptr);
return 0;
here is the output
55 48 89 e5 bf 00 00 00 00 e8 00 00 00 00 b8 00 00 00 00 5d c3
55 48 89 e5 bf 00 00 00 00 e8 00 00 00 00 b8 00 00 00 00 5d c3
I'm having a problem.
I'm trying to create a file and then reading it again, saving the values in a new structure. But when I try to print the values I just get garbaje after 7 values.
What am I doing wrong?
Or maybe there is a fwrite limit
#include<stdio.h>
#include<stdlib.h>
struct estructura_salida
{
int num_art;
int exist;
};
int main (void)
{
fflush(stdin);
int i,j;
long reg;
struct estructura_salida listado[100];
struct estructura_salida ventas[100];
struct estructura_salida listadol[100];
struct estructura_salida ventasl[100];
for(i=0;i<100;i++)
{
listado[i].num_art = i+1;
listado[i].exist = i+20;
ventas[i].num_art = i+1;
ventas[i].exist = i+10;
}
printf("\ncargados\n");
for(i=0;i<100;i++)
{
printf("\n%i\t%i\t%i",listado[i].num_art,listado[i].exist,ventas[i].exist);
}
FILE *fp1;
FILE *fp2;
fp1 = fopen("C://stock.dbf","wt");
fp2 = fopen("C://ventas.dbf","wt");
fwrite(listado,sizeof(struct estructura_salida),200,fp1);
fwrite(ventas,sizeof(struct estructura_salida),200,fp2);
fclose(fp1);
fclose(fp2);
printf("\nleyendo el archivo");
fp1 = fopen("C://stock.dbf","rt");
fp2 = fopen("C://ventas.dbf","rt");
while(!feof(fp1))
{
fread(listadol,sizeof(listadol),1,fp1);
}
while(!feof(fp2))
{
fread(ventasl,sizeof(ventasl),1,fp2);
}
fclose(fp1);
fclose(fp2);
printf("\narchivo leido\n");
for(i=0;i<100;i++)
{
printf("\n%i\t%i\t%i",listadol[i].num_art,listadol[i].exist,ventasl[i].exist);
}
return 0;
}
this is how the console looks, I just get garbaje.
console
Thank you!!
Diagnosis
I believe you are almost certainly working on a Windows system because you used "wt" in the fopen() mode. The t is not recognized by the C standard or most Unix systems. And also because you used fflush(stdin) which is essentially meaningless on non-Windows systems but is defined to do a more or less useful task on Windows systems.
Your primary problem is that you use "wt" to open a text file for writing, but when you use fwrite(), you are writing binary data to a text file. That means that entries containing 10 or 13 are likely to cause chaos.
Use "wb" (and "rb" when reading). This is supported by the C standard and indicates that you are doing binary I/O, not text I/O, and prevents the I/O system from wreaking havoc on your data.
You are also writing 200 records when you only have arrays containing 100 records (as pointed out by R Sahu in their answer) — this is not a recipe for happiness, either.
Your loops using while (!feof(fp1)) are wrong; using while (!feof(file)) is always wrong. You keep reading over the same elements — listadol[0] and ventasl[0], because you simply pass the array name to fread(). You could read all the records back in one fread() operation per file, or you need to index the array correctly (passing &listadol[i] for example).
Strictly, you should verify that the fopen() calls (in particular) are successful. Arguably, you should do the same for the fread() and fwrite() calls. The ultra-fanatic would check the fclose() calls. If the data file is crucial, you should do that, just in case there wasn't enough space on disk, or something else goes radically wrong.
Prescription
Putting the changes together, and using NUM_ENTRIES to identify the number of entries (and changing it from 100 to 10 for compactness of output), I get:
#include <stdio.h>
#include <stdlib.h>
struct estructura_salida
{
int num_art;
int exist;
};
enum { NUM_ENTRIES = 10 };
int main(void)
{
struct estructura_salida listado[NUM_ENTRIES];
struct estructura_salida ventas[NUM_ENTRIES];
struct estructura_salida listadol[NUM_ENTRIES];
struct estructura_salida ventasl[NUM_ENTRIES];
for (int i = 0; i < NUM_ENTRIES; i++)
{
listado[i].num_art = i + 1;
listado[i].exist = i + 20;
ventas[i].num_art = i + 1;
ventas[i].exist = i + 10;
}
printf("\ncargados\n");
for (int i = 0; i < NUM_ENTRIES; i++)
{
printf("%i\t%i\t%i\n", listado[i].num_art, listado[i].exist, ventas[i].exist);
}
const char name1[] = "stock.dbf";
const char name2[] = "ventas.dbf";
FILE *fp1 = fopen(name1, "wb");
FILE *fp2 = fopen(name2, "wb");
if (fp1 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", name1);
exit(EXIT_FAILURE);
}
if (fp2 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", name2);
exit(EXIT_FAILURE);
}
fwrite(listado, sizeof(struct estructura_salida), NUM_ENTRIES, fp1);
fwrite(ventas, sizeof(struct estructura_salida), NUM_ENTRIES, fp2);
fclose(fp1);
fclose(fp2);
printf("\nleyendo el archivo");
fp1 = fopen(name1, "rb");
fp2 = fopen(name2, "rb");
if (fp1 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", name1);
exit(EXIT_FAILURE);
}
if (fp2 == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", name2);
exit(EXIT_FAILURE);
}
int n;
for (n = 0; fread(&listadol[n], sizeof(listadol[n]), 1, fp1) == 1; n++)
;
int m;
for (m = 0; fread(&ventasl[m], sizeof(ventasl[m]), 1, fp2) == 1; m++)
;
fclose(fp1);
fclose(fp2);
printf("\narchivo leido\n");
if (n != m)
{
fprintf(stderr, "Read different numbers of records (%d from %s, %d from %s)\n",
n, name1, m, name2);
exit(EXIT_FAILURE);
}
for (int i = 0; i < n; i++)
{
printf("%i\t%i\t%i\n", listadol[i].num_art, listadol[i].exist, ventasl[i].exist);
}
return 0;
}
It would be better to use a function to open the files which checks for failure and reports the error and exits — an exercise for the reader.
The output from that is:
cargados
1 20 10
2 21 11
3 22 12
4 23 13
5 24 14
6 25 15
7 26 16
8 27 17
9 28 18
10 29 19
leyendo el archivo
archivo leido
1 20 10
2 21 11
3 22 12
4 23 13
5 24 14
6 25 15
7 26 16
8 27 17
9 28 18
10 29 19
A hex dump program shows that the two data files contain what you'd expect:
stock.dbf:
0x0000: 01 00 00 00 14 00 00 00 02 00 00 00 15 00 00 00 ................
0x0010: 03 00 00 00 16 00 00 00 04 00 00 00 17 00 00 00 ................
0x0020: 05 00 00 00 18 00 00 00 06 00 00 00 19 00 00 00 ................
0x0030: 07 00 00 00 1A 00 00 00 08 00 00 00 1B 00 00 00 ................
0x0040: 09 00 00 00 1C 00 00 00 0A 00 00 00 1D 00 00 00 ................
0x0050:
ventas.dbf:
0x0000: 01 00 00 00 0A 00 00 00 02 00 00 00 0B 00 00 00 ................
0x0010: 03 00 00 00 0C 00 00 00 04 00 00 00 0D 00 00 00 ................
0x0020: 05 00 00 00 0E 00 00 00 06 00 00 00 0F 00 00 00 ................
0x0030: 07 00 00 00 10 00 00 00 08 00 00 00 11 00 00 00 ................
0x0040: 09 00 00 00 12 00 00 00 0A 00 00 00 13 00 00 00 ................
0x0050:
There aren't any printable characters except the odd CR or LF in that, so the information on the right isn't all that informative. (Tested on a Mac running macOS 10.13.6 High Sierra, using GCC 8.2.0.)
Problem 1
fwrite(listado,sizeof(struct estructura_salida),200,fp1);
fwrite(ventas,sizeof(struct estructura_salida),200,fp2);
You are trying to write 200 objects while you have only 100. That causes undefined behavior.
Problem 2
Use of while(!feof(fp1)) is not right. See Why is “while ( !feof (file) )” always wrong?.
Change the code to read the data to:
int n = fread(listadol, sizeof(listadol[0]), 100, fp1);
// Now you can be sure that n objects were successfully read.
Problem 3
When using fread/fwrite, open the files in binary mode, not text mode.
fp1 = fopen("C://stock.dbf", "wb");
fp2 = fopen("C://ventas.dbf", "wb");
and
fp1 = fopen("C://stock.dbf", "rb");
fp2 = fopen("C://ventas.dbf", "rb");
sturct ptr info
struct ptr { // packet struct
unsigned long srcip;
unsigned long dstip;
unsigned short srcport;
unsigned short dstport;
unsigned char *str; // payload data of packet
unsigned short len; // payload length
unsigned long ts;
};
find file path and save module code
char *msg = NULL; // to save file path
int j = 0;
/* find file path and save */
for (i=84; i < ptr->len; i++) {
if (ptr->str[i] > 0x00 && ptr->str[i] < 0x7f) {
msg[j] = ptr->str[i];
j++;
}
if (ptr->str[i] > 0x7f) {
msg[j] = 0x23;
j++;
}
}
This is file path in SMB packet, i captured on Wireshark.
0000 5c 00 e0 ac c8 b2 5c 00 73 00 65 00 63 00 72 00 \.....\.s.e.c.r.
0010 65 00 74 00 5c 00 78 c7 ac c0 2e 00 74 00 78 00 e.t.\.x.....t.x.
0020 74 00 00 00 t...
current result =
msg : \####\secret\x###.txt
I just put '#' (0x23) temporarily..
and this is what i want =
msg : \고니\secret\인사.txt
I just found "e0 ac" are part of letter '고' , "c8 b2" are part of letter '니'
But i don't know how to convert..
In sum, i want convert hex code (in packet) to UTF-8.
I've written in a file (using 'fwrite()') the following:
TUS�ABQ���������������(A����������(A��B������(A��B���A��(A��B���A������B���A������0����A������0�ABQ�������0�ABQ�����LAS����������������A�����������A��&B�������A��&B��B���A��&B��B������&B��
B����153���B����153�LAS�����153�LAS�����LAX���������������:A����������:AUUB������:AUUB��B��:
AUUB��B����UUB��B����������B��������LAX���������LAX�����MDW���������������A����������A��(�������A��(����A��A��(����A������(����A����A�89���A����A�89MDW�����A�89MDW�����OAK���������
����������������������#�����������#�����������#�����������#�������������������������OAK���������OAK�����SAN���������������LA����������LA��P#������LA��P#��#A��LA��P#��#A������P#��#A����������#A��������SAN���������SAN�����TPA�ABQ����������������B�����������B��#�����...(continues)
which is translated to this:
TUSLWD2.103.47.775.1904.06.40.03AMBRFD4.63.228.935.0043.09.113.0ASDGHU5.226.47.78.3.26...(The same structure)
and the hexdump of that would be:
00000000 54 55 53 00 41 42 51 00 00 00 00 00 00 00 00 00 |TUS.ABQ.........|
00000010 00 00 00 00 00 00 28 41 00 00 0e 42 00 00 f8 41 |......(A...B...A|
00000020 00 00 00 00 4c 41 53 00 00 00 00 00 00 00 00 00 |....LAS.........|
00000030 00 00 00 00 00 00 88 41 00 00 26 42 9a 99 11 42 |.......A..&B...B|
(Continues...)
the structure is, always 2 words of 3 characters each one (i.e. TUS and LWD) followed by 7 floats, and then it repeats again on a on until end of file.
The key thing is: I just want to read every field separated like 'TUS', 'LWD', '2.10', '3.4', '7.77'...
And I can only use 'fread()' to achieve that! For now, I'm trying this:
aux2 = 0;
fseek(fp, SEEK_SET, 0);
fileSize = 0;
while (!feof(fp) && aux<=2) {
fread(buffer, sizeof(char)*4, 1, fp);
printf("%s", buffer);
fread(buffer, sizeof(char)*4, 1, fp);
printf("%s", buffer);
for(i=0; i<7; i++){
fread(&delay, sizeof(float), 1, fp);
printf("%f", delay);
}
printf("\n");
aux++;
fseek(fp,sizeof(char)*7+sizeof(float)*7,SEEK_SET);
aux2+=36;
}
And I get this result:
TUSABQ0.0000000.0000000.00000010.5000000.0000000.00000010.500000
AB0.0000000.000000-10384675421112248092159136000638976.0000000.0000000.000000-10384675421112248092159136000638976.0000000.000000
AB0.0000000.000000-10384675421112248092159136000638976.0000000.0000000.000000-10384675421112248092159136000638976.0000000.000000
But it does not works correctly...
*Note: forget the arguments of the last 'fseek()', cos I've been trying too many meaningless things!
To write the words (i.e. TUS) into the file, I use this:
fwrite(x->data->key, 4, sizeof(char), fp);
and to write the floats, this:
for (i = 0; i < 7; i++) {
fwrite(¤t->data->retrasos[i], sizeof(float), sizeof(float), fp);
}
I'd recommend using a structure to hold each data unit:
typedef struct {
float value[7];
char word1[5]; /* 4 + '\0' */
char word2[5]; /* 4 + '\0' */
} unit;
To make the file format portable, you need a function that packs and unpacks the above structure to/from a 36-byte array. On Intel and AMD architectures, float corresponds to IEEE-754-2008 binary32 format in little-endian byte order. For example,
#define STORAGE_UNIT (4+4+7*4)
#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
size_t unit_pack(char *target, const size_t target_len, const unit *source)
{
size_t i;
if (!target || target_len < STORAGE_UNIT || !source) {
errno = EINVAL;
return 0;
}
memcpy(target + 0, source->word1, 4);
memcpy(target + 4, source->word2, 4);
for (i = 0; i < 7; i++)
memcpy(target + 8 + 4*i, &(source->value[i]), 4);
return STORAGE_UNIT;
}
size_t unit_unpack(unit *target, const char *source, const size_t source_len)
{
size_t i;
if (!target || !source || source_len < STORAGE_UNIT) {
errno = EINVAL;
return 0;
}
memcpy(target->word1, source, 4);
target->word1[4] = '\0';
memcpy(target->word2, source + 4, 4);
target->word2[4] = '\0';
for (i = 0; i < 7; i++)
memcpy(&(target->value[i]), source + 8 + i*4, 4);
return STORAGE_UNIT;
}
#else
#error Unsupported architecture!
#endif
The above only works on Intel and AMD machines, but it is certainly easy to extend to other architectures if necessary. (Almost all machines currently use IEEE 754-2008 binary32 for float, only the byte order varies. Those that do not, typically have C extensions that do the conversion to/from their internal formats.)
Using the above, you can -- should! must! -- document your file format, for example as follows:
Words are 4 bytes encoded in UTF-8
Floats are IEEE 754-2008 binary32 values in little-endian byte order
A file contains one or more units. Each unit comprises of
Name Description
word1 First word
word2 Second word
value0 First float
value1 Second float
value2 Third float
value3 Fourth float
value4 Fifth float
value5 Sixth float
value6 Second float
There is no padding.
To write an unit, use a char array of size STORAGE_UNIT as a cache, and write that. So, if you have unit *one, you can write it to FILE *out using
char buffer[STORAGE_UNIT];
if (unit_pack(buffer, sizeof buffer, one)) {
/* Error! Abort program! */
}
if (fwrite(buffer, STORAGE_UNIT, 1, out) != 1) {
/* Write error! Abort program! */
}
Correspondingly, reading from FILE *in would be
char buffer[STORAGE_UNIT];
if (fread(buffer, STORAGE_UNIT, 1, in) != 1) {
/* End of file, or read error.
Check feof(in) or/and ferror(in). */
}
if (unit_unpack(one, buffer, STORAGE_UNIT)) {
/* Error! Abort program! */
}
If one is an array of units, and you are writing or reading one[k], use &(one[k]) (or equivalently one + k) instead of one.
I have a question on filling an array with values in C. I have a string that I want to split into an array of new strings each 14 'sections' long.
int main(int argc , char *argv[])
{
char string[]="50 09 00 00 98 30 e0 b1 0d 01 00 00 00 00 4f 09 00 00 98 30 c6 b1 0d 01 01 01 01 50 09 00 00 98 30 e0 b1 0d 01 00 00 00 00 4f 09 00 00 98 30 c6 b1 0d 01 01 01 01";
char delim[] = " ";
char *result = NULL;
char *strArray[1440] = {0};
int i = 0;
result = strtok(string, " ");
while (result)
{
strArray[i] = result;
result = strtok( NULL, delim );
i++;
}
// Now I have each 'section' of the original string in strArray[xx]
int z = 1022;
int c;
char arr[5000];
char *finalarr[100] = {0};
char buff[100];
int l = 0;
for(c=0;c<z;++c)
{
strcat(arr,strArray[c]);
if (c % 14 == 13)
{
// print the value so far for check, this gives an output of 28 chars
puts(arr);
// copy value of arr to buff
ret = sprintf(buff,"%s", arr);
// copy value of buff to instance of finalarr
finalarr[l] = buff;
// empty arr
strcpy(arr," ");
l++;
}
}
// both have the same value (last value of arr)
printf("finalarr1 = %s\n",finalarr[1]);
printf("finalarr20 = %s\n",finalarr[20]);
}
Perhaps I'm trying to solve it in a too complex way (I hope). Anyway some directions to help would be highly appreciated.
#include <stdio.h>
#include <string.h>
int main(int argc , char *argv[])
{
int i;
int fcount=0;
int acount=0;
char string[]="50 09 00 00 98 30 e0 b1 0d 01 00 00 00 00 4f 09 00 00 98 30 c6 b1 0d 01 01 01 01 50 09 00 00 98 30 e0 b1 0d 01 00 00 00 00 4f 09 00 00 98 30 c6 b1 0d 01 01 01 01";
char *finalarr[100];
char arr[29]="\0";
for (i=0;i<(strlen(string));i++)
{
if ((i+1)%3!=0)
{
strncpy(&arr[acount],&string[i],1);
acount++;
if (acount==28)
{
acount=0;
arr[29]="\0";
finalarr[fcount]=strdup(arr);
fcount++;
}
}
}
printf("finalarr1 = %s\n",finalarr[0]);
printf("finalarr1 = %s\n",finalarr[1]);
printf("finalarr1 = %s\n",finalarr[2]);
return 0;
}
result:
finalarr1 = 500900009830e0b10d0100000000
finalarr1 = 4f0900009830c6b10d0101010150
finalarr1 = 0900009830e0b10d01000000004f
You should replace the lines:
// copy value of arr to buff
ret = sprintf(buff,"%s", arr);
// copy value of buff to instance of finalarr
finalarr[l] = buff;
with:
finalarr[l] = strdup(arr);
because you only need to duplicate the string stored in arr. The variable buff should not be needed.
And the line:
// empty arr
strcpy(arr," ");
with:
*arr = '\0';
Because you only need to "reset" the string arr. With your original line, you only "replaced " former text with a 'lonely' space.