Having an issue with fread and fwrite function - c

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");

Related

correct way to copy binary file to buffer in c

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

Segfault in AES_cbc_encrypt

I'm trying to understand the OpenSSL library in more detail. So rather than using the set of higher-level EVP functions, I've been trying to use the AES_* functions. Following the general set of calls in this question (though I'm using CBC instead of counter mode), I've come up with this code:
void ctr(log_t* log)
{
unsigned char ivec[16];
/* Out buffer for ciphertext */
unsigned char outBuf[16];
blockReader_t* br = blockReaderInit(log, "./input.txt", 128);
int outFD;
if ((outFD = open("out.bin", O_WRONLY)) == -1)
{
logPrint(br->log, LOG_ARGS, LOG_ERR, "open: %s", strerror(errno));
logExit(br->log, LOG_ARGS, EXIT_FAILURE);
}
memset(ivec, 0, 16);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
{
logPrint(log, LOG_ARGS, LOG_ERR, "AES_set_encrypt_key: returned %d", res);
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
unsigned char* buf;
while ((buf = blockReaderGet(br)) != NULL)
{
logPrint(log, LOG_ARGS, LOG_INFO, "ivec =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) ivec, 16);
logPrint(log, LOG_ARGS, LOG_INFO, "buf =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) buf, 16);
AES_cbc_encrypt(buf, outBuf, 16, &aesKey, ivec, 1);
logPrint(log, LOG_ARGS, LOG_INFO, "outBuf =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) outBuf, 16);
int res = write(outFD, outBuf, 16);
if (res == -1)
{
logPrint(log, LOG_ARGS, LOG_ERR, "write: %s", strerror(errno));
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
else if (res < 16)
{
logPrint(log, LOG_ARGS, LOG_WARN, "Unexpectedly wrote < 16 bytes");
}
}
if ((close(outFD)) == -1)
{
logPrint(log, LOG_ARGS, LOG_ERR, "close: %s", strerror(errno));
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
}
The log_t struct and calls to log*() are my own logging framework which I am using to help debug this code. blockReader_t is another framework for reading files in sets of bytes. blockReaderGet() simply fills the destination buffer with the predetermined number of bytes of data (in this case 128 bits/16 bytes).
Contents of input.txt:
$ hexdump -C input.txt
00000000 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 |Midnight_Marlin.|
00000010 52 69 63 68 61 72 64 52 69 63 68 61 72 64 06 07 |RichardRichard..|
00000020
Output (ran in GDB):
(gdb) run
Starting program: /home/adam/crypto/openssl/aes/aes_128
[ 0.000020] <aes_128.c:83> "main" INFO: Log library started (v1.9.0)
...
[ 0.000054] <aes_128.c:50> "ctr" INFO: ivec =
[ 0.000057] <aes_128.c:51> "ctr" INFO: HEX (16 bytes)
---BEGIN_HEX---
00000000 00 00 00 00 00 00 00 00 d0 0f 00 00 00 00 00 00 |................|
00000010
---END_HEX---
[ 0.000069] <aes_128.c:53> "ctr" INFO: buf =
[ 0.000071] <aes_128.c:54> "ctr" INFO: HEX (16 bytes)
---BEGIN_HEX---
00000000 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 |Midnight_Marlin.|
00000010
---END_HEX---
Program received signal SIGSEGV, Segmentation fault.
_x86_64_AES_encrypt_compact () at aes-x86_64.s:170
170 xorl 0(%r15),%eax
I'm using an OpenSSL from GitHub that I've built myself and linked against locally; specifically the OpenSSL_1_0_2e tag, which I gather is the latest stable version.
The Perl file that generates this assembly file uses the $key variable to name what r15 represents. But given that AES_set_encrypt_key() returns success, I'm not sure what's wrong.
Could anyone please offer any pointers to what might be wrong here?
EDIT:
Despite compiling OpenSSL with -g3 instead of -O3, the backtrace isn't useful:
(gdb) bt
#0 _x86_64_AES_encrypt_compact () at aes-x86_64.s:170
#1 0x0000000000402b6b in AES_cbc_encrypt () at aes-x86_64.s:1614
#2 0x00007fffffffe0a0 in ?? ()
#3 0x000080007dfc19a0 in ?? ()
#4 0x00007fffffffe050 in ?? ()
#5 0x0000000000635080 in ?? ()
#6 0x00007fffffffe1a0 in ?? ()
#7 0x0000000000000010 in ?? ()
#8 0x00007ffff7bdf9a0 in ?? ()
#9 0x00007fffffffe1b0 in ?? ()
#10 0x00007fff00000001 in ?? ()
#11 0x00007ffff7bdf4c8 in ?? ()
#12 0x00007fffffffda40 in ?? ()
#13 0x0000000000000000 in ?? ()
EDIT 2:
CFLAG has been changed:
CFLAG= -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -m64 -DL_ENDIAN -O0 -ggdb -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
Note the -O0 -ggdb. Backtrace is the same:
(gdb) bt
#0 _x86_64_AES_encrypt_compact () at aes-x86_64.s:170
#1 0x0000000000402b6b in AES_cbc_encrypt () at aes-x86_64.s:1614
#2 0x00007fffffffe0a0 in ?? ()
#3 0x000080007dfc19a0 in ?? ()
#4 0x00007fffffffe050 in ?? ()
#5 0x0000000000635080 in ?? ()
#6 0x00007fffffffe1a0 in ?? ()
#7 0x0000000000000010 in ?? ()
#8 0x00007ffff7bdf9a0 in ?? ()
#9 0x00007fffffffe1b0 in ?? ()
#10 0x00007fff00000001 in ?? ()
#11 0x00007ffff7bdf4c8 in ?? ()
#12 0x00007fffffffda40 in ?? ()
#13 0x0000000000000000 in ?? ()
EDIT: MCVE example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/aes.h>
unsigned char input[] = {0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};
int main()
{
unsigned char ivec[16];
/* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
unsigned char outBuf[16];
int outFD;
if ((outFD = open("out.bin", O_WRONLY)) == -1)
{
perror("open");
return EXIT_FAILURE;
}
memset(ivec, 0, 16);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
{
fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
return EXIT_FAILURE;
}
for (int i = 0; i < 32; i += 16)
{
printf("ivec = ");
for (int j = 0; j < 16; j++)
printf("%.02hhx ", ivec[j]);
putchar('\n');
printf("input = ");
for (int j = i; j < (i + 16); j++)
printf("%.02hhx ", input[j]);
putchar('\n');
AES_cbc_encrypt(&input[i], outBuf, 16, &aesKey, ivec, 1);
printf("outBuf = ");
for (int j = 0; j < 16; j++)
printf("%.02hhx ", outBuf[j]);
putchar('\n');
int res = write(outFD, outBuf, 16);
if (res == -1)
{
perror("write");
return EXIT_FAILURE;
}
else if (res < 16)
{
printf("Warning: unexpectedly wrote < 16 bytes");
}
}
if ((close(outFD)) == -1)
{
perror("close");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
So there are several major bugs here. I'll go through all the ones I caught, but there may be more, as I didn't do a thorough code review.
You are using sentinel values everywhere (ie: the 16 integer literals. Swap these out with a preprocessor macro, or even better, a const int).
The output buffer needs to be at least as big as your input buffer, and should be rounded up the the nearest multiple of the block size, plus one more block.
You are looping through each element of the the input data and trying to encrypt one byte at a time. Unless you are implementing some obscure layer on top of AES, this is wrong. You iterate over blocks of data, not individual bytes. The loop is completely unnecessary.
Your input data buffer appears to be bigger than your output data buffer. With your current implementation, the last 16 bytes I think will be truncated/lost, since the input buffer has 32 bytes of data, but the output buffer is 16 bytes. In your specific example, input should be 32 bytes, output should be 32+1.
In addition to the loop being unnecessary, with some modifications it would run (incorrectly, corrupting data), and eventually access invalid memory (ie: pointing to near the end of the input buffer, and telling the encrypt function to ask for 16 bytes of data after that point).
I've provided an updated code listing and sample output that should get you on the right track. Here's a working example that should also guide you along.
Good luck!
Modified Code Listing
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/aes.h>
#define BLOCK_SIZE (128)
unsigned char input[BLOCK_SIZE] = {
0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};
int main()
{
unsigned char ivec[BLOCK_SIZE];
/* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
unsigned char outBuf[BLOCK_SIZE+1];
int outFD;
if ((outFD = open("out.bin", O_CREAT | O_RDWR)) == -1)
{
perror("open");
return EXIT_FAILURE;
}
memset(ivec, 0, BLOCK_SIZE);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if ((res = AES_set_encrypt_key((unsigned char*) myKey, BLOCK_SIZE, &aesKey)) < 0)
{
fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
return EXIT_FAILURE;
}
int i = 0;
//for (int i = 0; i < 32; i += BLOCK_SIZE)
{
printf("ivec = ");
for (int j = 0; j < BLOCK_SIZE; j++)
printf("%.02hhx ", ivec[j]);
putchar('\n');
printf("input = ");
for (int j = i; j < (i + BLOCK_SIZE); j++)
printf("%.02hhx ", input[j]);
putchar('\n');
putchar('\n');
putchar('\n');
putchar('\n');
AES_cbc_encrypt(input, outBuf, BLOCK_SIZE, &aesKey, ivec, AES_ENCRYPT);
printf("outBuf = ");
for (int j = 0; j < BLOCK_SIZE; j++)
printf("%.02hhx ", outBuf[j]);
putchar('\n');
int res = write(outFD, outBuf, BLOCK_SIZE);
if (res == -1)
{
perror("write");
return EXIT_FAILURE;
}
else if (res < BLOCK_SIZE)
{
printf("Warning: unexpectedly wrote < %d bytes.\n", BLOCK_SIZE);
}
}
if ((close(outFD)) == -1)
{
perror("close");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Build Command
gcc -O0 -ggdb test.c --std=c99 -lssl -lcrypto && ./a.out
Sample Output
ivec = 00 00 00 00 00 00 00 00 d0 0f 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 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 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 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 00 00 00 00 00 00 00 00 00 00 00 00 00 00
input = 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 52 69 63 68 61 72 64 52 69 63 68 61 72 64 06 07 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 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 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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
outBuf = 81 ee 91 c0 9f f6 40 db 3c 6d 32 dd 5e 86 6f f8 4e 7b aa 15 38 36 b8 20 bc 04 bd 4f 6c 53 0e 02 72 c2 b7 e8 79 35 f2 b2 e1 c1 6e 1e 3b 1e 75 81 6a 56 43 d8 9d 9c 4c 1e 04 bd 99 29 3a 55 c9 a4 90 48 20 13 5e 51 4a 0c 4b 35 bc db da 54 f1 2b 66 f6 1b 1a 42 25 33 30 0e 35 87 9d 4b 1f d5 3a 5d 3a 8e 8c c8 48 c0 52 72 c0 4e b3 b8 f5 37 03 1c 87 15 61 3b 64 2b 06 5e 12 8f c7 b5 21 98 06

Structures binary file into array C

I need to put structs from a binary file into an array of structs, one struct per key.
Here is my struct:
struct candidate{
char inscr[10];
char name[44];
int year;
int position;
char curse[30];
};
typedef struct candidate Candidate;
Here's what I tried to do:
void ordenafile(char fname[13]){
FILE *f = fopen (fname, "rb");
if(f==NULL){
printf("Error.");
return;
}
fseek(f, 0, SEEK_END);
int sz = ftell(f);
Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
arr[i]=p;
i++;
}
Having found the end of the file with fseek(), you need to rewind before reading from it.
This part of the code doesn't do what you want:
Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
arr[i]=p;
i++;
}
You have an array of structure pointers, and you allocate one structure, pointed at by p. Your loop then reads a value into the one structure, and copies the pointer into an element of the array of pointers. So, all the elements of the array point to the same structure. The variable aux is also unused.
You need one of two solutions:
Candidate arr[sz/sizeof(Candidate)];
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
;
This assumes you are going to be able to use the array in the current function and functions it calls, and don't need to return it to the calling code.
Alternatively:
Candidate *arr = malloc(sz);
if (arr == 0)
return 0;
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
;
return arr;
You can return this array from the function.
Working code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct candidate
{
char inscr[10];
char name[44];
int year;
int position;
char curse[30];
};
typedef struct candidate Candidate;
int write_sample_data(const char *filename);
Candidate *read_sample_data(const char *filename, int *number);
void print_sample_data(int num, Candidate *candidates);
int main(void)
{
const char filename[] = "practice.data";
if (write_sample_data(filename) != 0)
fprintf(stderr, "Failed to write sample data\n");
else
{
int number = 0;
Candidate *clist = read_sample_data(filename, &number);
if (number == 0)
fprintf(stderr, "Failed to read sample data\n");
else
{
print_sample_data(number, clist);
free(clist);
}
}
return 0;
}
int write_sample_data(const char *filename)
{
FILE *fp = fopen(filename, "wb");
if (fp == NULL)
{
fprintf(stderr, "Failed to open file %s for writing\n", filename);
return -1;
}
Candidate c;
for (int i = 0; i < 5; i++)
{
char inscr[10];
char name[40];
char curse[30];
sprintf(inscr, "I-%.4d", i);
sprintf(name, "Name %.4d Surname %.4d", rand() % 1000, rand() % 1000);
sprintf(curse, "Curse %.2d", rand() % 100);
// Using null-filling property of strncpy()
strncpy(c.inscr, inscr, sizeof(c.inscr));
strncpy(c.name, name, sizeof(c.name));
strncpy(c.curse, curse, sizeof(c.curse));
c.year = 2010 + i;
c.position = 1000 * i + (99 - i);
if (fwrite(&c, sizeof(Candidate), 1, fp) != 1)
{
fclose(fp);
fprintf(stderr, "Failed to write candidate %d\n", i);
return -1;
}
}
fclose(fp);
return 0;
}
Candidate *read_sample_data(const char *filename, int *number)
{
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
return 0;
}
fseek(fp, 0, SEEK_END);
size_t sz = ftell(fp);
rewind(fp);
Candidate *arr = malloc(sz);
if (arr == 0)
{
fprintf(stderr, "Failed to allocate %zu bytes memory\n", sz);
return 0;
}
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, fp) == 1; i++)
;
*number = i;
return arr;
}
void print_sample_data(int number, Candidate *clist)
{
for (int i = 0; i < number; i++)
{
printf("%-10s %-30s %.4d %.4d %s\n",
clist[i].inscr, clist[i].name, clist[i].year,
clist[i].position, clist[i].curse);
}
}
Note that this produces the same data each time it is run, despite using the pseudo-random numbers from rand(). Note too that the code deliberately exploits the behaviour of strncpy() that pads a field with null bytes to the full length so that the data in the file doesn't have any extraneous matter.
Sample output:
I-0000 Name 0249 Surname 0807 2010 0099 Curse 73
I-0001 Name 0930 Surname 0658 2011 1098 Curse 72
I-0002 Name 0878 Surname 0544 2012 2097 Curse 23
I-0003 Name 0440 Surname 0709 2013 3096 Curse 65
I-0004 Name 0042 Surname 0492 2014 4095 Curse 87
Hex dump of data file:
0x0000: 49 2D 30 30 30 30 00 00 00 00 4E 61 6D 65 20 30 I-0000....Name 0
0x0010: 32 34 39 20 53 75 72 6E 61 6D 65 20 30 38 30 37 249 Surname 0807
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030: 00 00 00 00 00 00 00 00 DA 07 00 00 63 00 00 00 ............c...
0x0040: 43 75 72 73 65 20 37 33 00 00 00 00 00 00 00 00 Curse 73........
0x0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0060: 49 2D 30 30 30 31 00 00 00 00 4E 61 6D 65 20 30 I-0001....Name 0
0x0070: 39 33 30 20 53 75 72 6E 61 6D 65 20 30 36 35 38 930 Surname 0658
0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0090: 00 00 00 00 00 00 00 00 DB 07 00 00 4A 04 00 00 ............J...
0x00A0: 43 75 72 73 65 20 37 32 00 00 00 00 00 00 00 00 Curse 72........
0x00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00C0: 49 2D 30 30 30 32 00 00 00 00 4E 61 6D 65 20 30 I-0002....Name 0
0x00D0: 38 37 38 20 53 75 72 6E 61 6D 65 20 30 35 34 34 878 Surname 0544
0x00E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00F0: 00 00 00 00 00 00 00 00 DC 07 00 00 31 08 00 00 ............1...
0x0100: 43 75 72 73 65 20 32 33 00 00 00 00 00 00 00 00 Curse 23........
0x0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0120: 49 2D 30 30 30 33 00 00 00 00 4E 61 6D 65 20 30 I-0003....Name 0
0x0130: 34 34 30 20 53 75 72 6E 61 6D 65 20 30 37 30 39 440 Surname 0709
0x0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0150: 00 00 00 00 00 00 00 00 DD 07 00 00 18 0C 00 00 ................
0x0160: 43 75 72 73 65 20 36 35 00 00 00 00 00 00 00 00 Curse 65........
0x0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0180: 49 2D 30 30 30 34 00 00 00 00 4E 61 6D 65 20 30 I-0004....Name 0
0x0190: 30 34 32 20 53 75 72 6E 61 6D 65 20 30 34 39 32 042 Surname 0492
0x01A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01B0: 00 00 00 00 00 00 00 00 DE 07 00 00 FF 0F 00 00 ................
0x01C0: 43 75 72 73 65 20 38 37 00 00 00 00 00 00 00 00 Curse 87........
0x01D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01E0:
There are 4 bytes of padding in the structures; 2 after the name and 2 at the end, so its length is a convenient 96 bytes, which just happens to be a multiple of 16, so the hex dump aligns nicely.

How to parse hex dump

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.)

Determine size of character array in C

I am trying to write a program that will talk to a XBee Pro S2B over serial from a PIC16 and I have some odd memory stuff going on...
I am a bit weak when it comes to pointers in C so I have been writing a test program using GCC to get it to work before I move it over to the PIC microcontroller. The biggest thing to note with the PIC is the memory constraints. So for this I would like to avoid adding any external libraries unless I absolutely have to (and avoid having to use malloc/free).
Here is my code:
#include <stdio.h>
#define FALSE 0
#define TRUE 1
void printPacketArray(unsigned char *packetArray, int packetSize){
printf("OUTPUT PACKET: ");
for(int i = 0; i < packetSize; i++){
printf("%02X ", packetArray[i]);
}
printf("\n");
}
/**
* This function builds all of the frames to be wrapped into a packet
*/
int buildFrame(
unsigned char frameType,
unsigned char requestResponse,
unsigned char *destinationAddress64Bit,
unsigned char *destinationAddress16Bit,
unsigned char *rfPacketData,
int destinationAddress64BitSize,
int destinationAddress16BitSize,
int rfDataSize,
unsigned char **frameArray,
int **frameArraySize){
// printf("Entering buildFrame\n");
// FT RESP (Optional Dest Addr x64) + (Optional Dest Addr x16) Packet
int outputPacketSize = (1 + 1 + destinationAddress64BitSize + destinationAddress16BitSize + rfDataSize);
// printf("Packet Size: %d\n", outputPacketSize);
unsigned char outputPacketArray[outputPacketSize];
// Add the frame type
outputPacketArray[0] = frameType;
// printf("Frame type: %02X\n", frameType);
// Request response
outputPacketArray[1] = requestResponse;
// printf("Response: %02X\n", requestResponse);
int arrayCount = 2;
// Add the destination address (64 bit)
if(destinationAddress64Bit != 0x00){
for(int i = 0; i < 8; i++){
outputPacketArray[arrayCount] = destinationAddress64Bit[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, destinationAddress64Bit[i]);
arrayCount++;
}
}
// Ad the destination address (16 bit)
if(destinationAddress16Bit != 0x00){
for(int i = 0; i < 2; i++){
outputPacketArray[arrayCount] = destinationAddress16Bit[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, destinationAddress16Bit[i]);
arrayCount++;
}
}
// Add the packet data
for(int i = 0; i < rfDataSize; i++){
outputPacketArray[arrayCount] = rfPacketData[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, rfPacketData[i]);
arrayCount++;
}
*frameArray = outputPacketArray;
// printf("*frameArray = %p\n", outputPacketArray);
*frameArraySize = &outputPacketSize;
// printf("*frameArraySize = %p\n", &outputPacketSize);
// printf("Packet: ");
// for(int i = 0; i < outputPacketSize; i++){
// printf("%02X ", outputPacketArray[i]);
// }
// printf("\n");
// printf("Exiting buildFrame\n");
return TRUE;
}
/**
* This function wraps the frame data into the packet.
*/
int buildPacket(
unsigned char *frameData,
int frameDataSize,
unsigned char **packetArrayPtr,
int **packetArraySizePtr){
// 7E MSB LSB Packet Checksum
int outputPacketSize = (1 + 1 + 1 + frameDataSize + 1);
int checksum = 0;
unsigned char outputPacketArray[outputPacketSize];
// Add the start delimiter
outputPacketArray[0] = 0x7E;
// Add the MSB (should always be 0x00)
outputPacketArray[1] = 0x00;
// Add the LSB (size of frameData)
outputPacketArray[2] = frameDataSize;
// Add the frame data
int arrayCount = 3;
for(int i = 0; i < frameDataSize; i++){
// printf("CNT: %d\n", arrayCount);
outputPacketArray[arrayCount] = frameData[i];
checksum += frameData[i];
arrayCount++;
}
// Add the checksum
outputPacketArray[arrayCount] = (0xFF - (checksum & 0xFF));
// printf("CNT: %d\n", arrayCount);
// printf("Packet: ");
// for(int i = 0; i < outputPacketSize; i++){
// printf("%02X ", outputPacketArray[i]);
// }
// printf("\n");
*packetArrayPtr = outputPacketArray;
*packetArraySizePtr = &outputPacketSize;
return TRUE;
}
int sendAPICommand(unsigned char* inputFrameData, int inputFrameDataLength){
unsigned char destinationAddress64Bit[] = {0x00, 0x13, 0xA2, 0x00, 0x40, 0x9C, 0x26, 0xE1};
unsigned char destinationAddress16Bit[] = {0xFF, 0xFE};
unsigned char *frameArrayPtr = 0x00;
int *frameArraySizePtr = 0x00;
// printf("COMPARE: 7E 00 13 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05 4A\n");
// We need to add in the radius and options before the data
unsigned char frameData[(inputFrameDataLength + 2)];
frameData[0] = 0x00; // Radius
frameData[1] = 0x00; // Options
for(int i = 0; i < inputFrameDataLength; i++){
frameData[(i + 2)] = inputFrameData[i];
}
if(buildFrame(0x10, 0x01, destinationAddress64Bit, destinationAddress16Bit, frameData, 8, 2, (inputFrameDataLength + 2), &frameArrayPtr, &frameArraySizePtr) == TRUE){
printf("COMPARE: 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05\n");
printPacketArray(frameArrayPtr, *frameArraySizePtr);
// The building of the frame was a success
if(buildPacket(frameArrayPtr, *frameArraySizePtr, &frameArrayPtr, &frameArraySizePtr) == TRUE){
printf("COMPARE: 7E 00 13 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05 4A\n");
printPacketArray(frameArrayPtr, *frameArraySizePtr);
return TRUE;
}
}
return FALSE;
}
int main(){
unsigned char packetData[] = {0x01, 0x02, 0x03, 0x04, 0x05};
sendAPICommand(packetData, 5);
return 0;
}
When I run it, I cannot seem to find out why the results are not consistent. Using the Eclipse debugger, I get the following error:
frameData.15 Error: Multiple errors reported.\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Failed to execute MI command: -data-evaluate-expression frameData.15 Error message from debugger back end: No symbol "frameData" in current context.\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Unable to create variable object
on this line of code:
if(buildFrame(0x10, 0x01, destinationAddress64Bit, destinationAddress16Bit, frameData, 8, 2, (inputFrameDataLength + 2), &frameArrayPtr, &frameArraySizePtr) == TRUE){
When I run the program completely (it silently fails) and this is my text output:
COMPARE: 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05
OUTPUT PACKET: 01 00 00 00 00 00 00 00 D8 8C 28 03 01 00 00 00 B0 8A 97 5C FF 7F 00 00 08 00 00 00 00 00 00 00 00 8A 97 5C 00 00 00 00 01 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 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 FF 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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 30 00 00 00 90 8A 97 5C FF 7F 00 00 90 89 97 5C FF 7F 00 00 00 00 00 00 00 00 00 00
I suspect the problem is I have a bad pointer (or pointers) in returning the size or the pointer to the character array but I don't know that for sure (or know how to get the program to fail in a way I can determine it).
In buildFrame:
unsigned char outputPacketArray[outputPacketSize];
outputPacketArray is a local variable. Its lifetime ends when you leave the function. However you assign a pointer to it to an output parameter of the function:
*frameArray = outputPacketArray;
(Same for outputPacketSize)
These pointers do not point to valid memory anymore when you leave the function. You need to dynamically allocate the array:
unsigned char* outputPacketArray = malloc(outputPacketSize);
and then free it later. Alternatively you could provide an appropriately sized array to the function, but then you would need to calculate the size already in main.
For the size you don't need a pointer to pointer at all, just return it from the function, or use a simple pointer (instead of double pointer) as output parameter.

Resources