I need to read a single byte from a file. Normally when reading, I use a char array as the buffer. However, I need to be able to perform binary operations with byte, which can't be done with a char array. Here's what I've got:
read(file, buffer, 1);
I've tried making buffer both a char and an int, but both give me warnings that it expects a void * argument. But of course, that doesn't allow for binary operations like &.
How can I store buffer such that I can perform binary operations on it?
You could use the function int fgetc (FILE *fp).
The return value will be an int value from 0 to 255 or EOF.
You can read into a char array as you (supposedly) know how to do, and then perform your binary operations on the first element of that array.
Binary operation can be performed on char data type with unsigned. Even if its an array binary operation can be done to the single element of the array.
for your reference.
ssize_t read(int fd, void *buf, size_t count);
buffer has to be address of the character or character array, in your single char is sufficient. If you want to use array use the element array[0] and perform operation on that.
As mentioned in the comments above
unsigned char c;
read(file, &c, 1);
typedef unsigned char uint8_t; /* Not necessary if you are using C99, i.e. <stdint.h>. */
uint8_t buffer[BUF_SIZE] = {0};
.
.
.
if (fread(buffer, sizeof(buffer[0]), 1, file) == 1)
{
buffer[0] ^= 0xFFu; /* Or any other bit-wise operation. */
}
Refer -
1. https://linux.die.net/man/3/fread
2. http://en.cppreference.com/w/c/types/integer
Related
I'm making PE file format analyzer in C language.
When I used Visual Studio, I could make it much easier.
BUT, I have tired to make it without Visual Studio to improve my C programing.
It was made by GCC(My laptop is macbook).
To analyze PE file format, as you know I have to use file pointer and read file as 'rb' type.
I did it and it looks like worked well.... I wanted to print first and second words("MZ") but It printed unkown(to me) numbers.
P.S I write little different code refer to previous one to smaller than before. But It print NULL.
It means that I wrote code really wrong... PLZ tell me which parts are wrong
#include <stdio.h>
#include <stdlib.h>
// struct to save info of PE_File format
typedef struct _IMAGE_DOS_HEADER
{
unsigned short e_magic;
unsigned short e_cblp;
unsigned short e_cp;
unsigned short e_crlc;
unsigned short e_cparhdr;
unsigned short e_minalloc;
unsigned short e_maxalloc;
unsigned short e_ss;
unsigned short e_sp;
unsigned short e_csum;
unsigned short e_ip;
unsigned short e_cs;
unsigned short e_lfarlc;
unsigned short e_ovno;
unsigned short e_res[4];
unsigned short e_oemid;
unsigned short e_oeminfo;
unsigned short e_res2[10];
unsigned long e_lfanew;
} DOS_HEADER;
// I use two different functions.
// First one was made to import PE File format info from file that I used.
// Another was made to print some imformation. I use some comment because I didn't realize those.
DOS_HEADER get_dos_header(FILE *fp, char* fp_buffer);
void print_data_of_structures(DOS_HEADER/*, NT_HEADER, FILE_HEADER, OPTIONAL_HEADER, DATA_DIRECTORY*/);
int main(void)
{
DOS_HEADER dos_header;
char file_path[1000];
printf("Please input your file path : ");
scanf("%[^\n]s", file_path);
FILE* fp = NULL;
fp = fopen(file_path, "rb");
if(fp == NULL)
printf("Unalbe to open file :/\n");
// To calculate file size.
long fp_size = 0;
fseek(fp, 0, SEEK_END);
fp_size = ftell(fp);
rewind(fp);
// Declare to use as buffer
char* fp_buffer = malloc(sizeof(char) * (fp_size + 1));
// Use function to save analyzed information.
DOS_HEADER info_dos_header = get_dos_header(fp, fp_buffer);
// Print information.
print_data_of_structures(info_dos_header);
fclose(fp);
free(fp_buffer);
return 0;
}
DOS_HEADER get_dos_header(FILE* fp, char* fp_buffer)
{
DOS_HEADER raw_info_dos_header = {0, };
// Read hex info from fp 2 byte 1 time and save at fp_buffer.
fseek(fp, 0, SEEK_SET);
fread(fp_buffer, 2, 1, fp);
raw_info_dos_header.e_magic = fp_buffer;
return raw_info_dos_header;
}
void print_data_of_structures(DOS_HEADER info_dos_header/*, NT_HEADER info_nt_header, FILE_HEADER info_file_header, OPTIONAL_HEADER info_optional_header, DATA_DIRECTORY info_data_directory*/)
{
// print info_dos_header
printf("Print DOS_HEADER\n");
// I tried several print format(for example %hu, %x, %d) But I coudn't "MZ" or any numbers has realation with "MZ".
printf("%s", info_dos_header.e_magic);
}
You have 2 big problems with your code: you are mixing types.
In DOS_HEADER all members (except the last one) are of type unsigned short.
That's important.
In get_dos_header you are doing
fread(fp_buffer, 2, 1, fp);
raw_info_dos_header.e_magic = fp_buffer;
which is wrong.
Don't use magic numbers, use sizeof to get the correct sizes
Check the return value of fread, specially if you are analyzing a binary
format, you must be sure that you've read exactly what you're expecting.
It's much easier to deal with fread when the size argument is 1, because
only when the size argument is 1 the return value of fread matches the
number of bytes read.
e_magic is a unsigned short, fp_buffer is a char*. This assignment is
not copying the contents pointed to by fp_buffer, you are storing an address
as if it were a unsigned short value. You need to copy the memory pointed to
by fp_buffer.
Also I don't see the point of you allocating a buffer of the size of the file
when you are reading chunk by chunk. It would be easier if you don't allocate a
buffer at all and use an array of a size larger than what you are going to read.
int get_dos_header(FILE* fp, DOS_HEADER *dos)
{
unsigned char buffer[8];
size_t ret = fread(buffer, 1, sizeof(dos->e_magic), fp);
if(ret != sizeof(dos->e_magic))
{
fprintf(stderr, "Invalid file size\n");
return 0;
}
memcpy(&dos->e_magic, buffer, sizeof(dos->e_magic));
// DO the others fread operation
...
return 1;
}
Then in main you can do this:
DOS_HEADER raw_info_dos_header = {0, };
if(get_dos_header(fp, &raw_info_dos_header) == 0)
{
fprintf(stderr, "failed to get the DOS header\n");
return 1;
}
...
The second problem is in print_data_of_structures:
printf("%s", info_dos_header.e_magic);
e_magic is a unsigned short, %s expects a pointer to char, it expects a
string. e_magic is definitively not a string. This yield undefined behaviour.
The printf should look like this:
printf("e_magic: %hu\n", info_dos_header.e_magic);
or
printf("e_magic: 0x%04hx\n", info_dos_header.e_magic);
to print it in hexadecimal format.
I also advice you to use pointers instead. Your struct is big and passing a
pointer to a function is much cheaper than passing a copy of a large struct to a
functions. So instead of
void print_data_of_structures(DOS_HEADER info_dos_header);
declare it as
void print_data_of_structures(DOS_HEADER *info_dos_header);
And also don't declare function that can fail (like get_dos_header) as
void, otherwise how do you tell the calling function that it failed? It's
better for such functions to return an int (1 for success, 0 for failure) and
expect a pointer to the struct where the information is stored (see how I
changed get_dos_header above.
Right now, I'm working on an example code that I wish to integrate into my program later. What essentially I'm trying to do is read a .dat file byte by byte and interpret the data (ie. interpret boot sector to output the sector size, reserved sectors etc.)
To do this, I am reading the data byte by byte and, using the descriptions in fat12 of https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html#ss1.3 , I translate the data into the information that I want. Right now, I can pull individual bytes from the file (Is it right to assume that the data pulled is in hex?). However, I need two bytes to have something meaningful. So, I need to combine two bytes into one, convert the hex data into decimal and output the information. Unfortunately, right now, I'm getting a seg fault and for the life of me, I can't figure out what's wrong. Thanks in advance!
int main (int argc, char **argv){
FILE *fp ,*fptest;
long lSize;
char *buffer;
//Open file
fptest= open("fat_volume.dat", "rb");
//Read file into buffer
fread(buffer,1,512,fptest);
//Parse the boot sector
char tmpA, tmpB;
tmpA = buffer[10]; //First byte
tmpB = buffer[11]; //Second byte
//Combine the two bytes into one
char combinedBytes[3];
strcpy (combinedBytes, tmpA);
strcat (combinedBytes, tmpB);
//Hex to decimal converter
long int li1;
li1 = strtol (combinedBytes,NULL,16);
printf ("The sector size is: %ld.\n", li1);
return 0;
}
You must allocate buffer; e.g.
char buffer[512];
or
char *buffer = malloc(512);
EDIT:
The string operations
strcpy (combinedBytes, tmpA);
strcat (combinedBytes, tmpB);
do not make sense either and access/copy too much data (the compiler will warn you about this!).
I suggest do read values as
unsigned char tmpA = buffer[10];
unsigned char tmpB = buffer[11];
unsigned int tmp = (tmpA << 8) | (tmpB << 0); /* or revert in in case of
little-endian */
To make things more efficient, I would write it as
struct fat_header {
uint8_t pad0[10];
uint16_t my_val;
uint8_t pad1[500];
} __attribute__((__packed__)); /* this is not portable and for gcc! */
...
struct fat_header hdr;
fread(&hdr, 1, sizeof hdr, f);
uint16_t val = be16toh(hdr.my_val); /* or le16toh() in case of le */
You are reading into a buffer you never allocated memory for.
What you're trying now is to read from some junk value in memory, who knows, which almost always leads to a segmentation fault.
Use:
char *buffer = malloc(512 * sizeof(char)); // this allocates 512 times the size of a single char of memory
If you don't specify the number inside malloc to be of a specific size (e.g. malloc(512) the number is in bytes, though I think it's better to always include it.
This specific error is called dereferencing a null pointer
EDIT:
I've managed to run this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
FILE *fp ,*fptest;
long lSize;
char *buffer;
//Open file
fptest = fopen("input.txt", "rb");
if (fptest == NULL)
{
printf("Error occurred when opening file");
return 1;
}
buffer = malloc(sizeof(char) * 512);
//Read file into buffer
fread(buffer,1,512,fptest);
//Parse the boot sector
char tmpA, tmpB;
tmpA = buffer[10]; //First byte
tmpB = buffer[11]; //Second byte
//Combine the two bytes into one
char combinedBytes[3];
strcpy (combinedBytes, &tmpA);
strcat (combinedBytes, &tmpB);
//Hex to decimal converter
long int li1;
li1 = strtol (combinedBytes,NULL,16);
printf ("The sector size is: %ld.\n", li1);
return 0;
}
You also used a function open() which must be fopen(), and you need to pass the address of tmpA and tmpB to strcpy and strcat.
This is why I don't understand why your compiler doesn't give any errors or warnings..
I have written a program in C which will read the bytes at a specific memory address from its own address space.
it works like this:
first it reads a DWORD from a File.
then it uses this DWORD as a memory address and reads a byte from this memory address in the current process' address space.
Here is a summary of the code:
FILE *fp;
char buffer[4];
fp=fopen("input.txt","rb");
// buffer will store the DWORD read from the file
fread(buffer, 1, 4, fp);
printf("the memory address is: %x", *buffer);
// I have to do all these type castings so that it prints only the byte example:
// 0x8b instead of 0xffffff8b
printf("the byte at this memory address is: %x\n", (unsigned)(unsigned char)(*(*buffer)));
// And I perform comparisons this way
if((unsigned)(unsigned char)(*(*buffer)) == 0x8b)
{
// do something
}
While this program works, I wanted to know if there is another way to read the byte from a specific memory address and perform comparisons? Because each time, I need to write all the type castings.
Also, now when I try to write the byte to a file using the following syntax:
// fp2 is the file pointer for the output file
fwrite(fp2, 1, 1, (unsigned)(unsigned char)(*(*buffer)));
I get the warnings:
test.c(64) : warning C4047: 'function' : 'FILE *' differs in levels of indirectio
n from 'unsigned int'
test.c(64) : warning C4024: 'fwrite' : different types for formal and actual para
meter 4
thanks.
You can use the C language union construct to represent an alias for your type as shown
typedef union {
char char[4];
char *pointer;
} alias;
alias buffer;
This assumes a 32-bit architecture (you could adjust the 4 at compile time, but would then also need to change the fread() byte count).
Then, you can simply use *(buffer.pointer) to reference the contents of the memory location.
From your question, the application is not clear, and the technique seems error prone. How do you take into account the movement of addresses in memory as things change? There may be some point in using the linker maps to extract symbolic information for locations to avoid the absolute addresses.
Take note of the definition of fwrite,
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
which means that the warnings at the last part of your question are because you should be writing from a character pointer rather than writing the actual value of the character.
You can remove the extra type castings by assigning the pointer you read from the file to another variable of the correct type.
Examples to think about:
#include <stdio.h>
int main() {
union {
char buffer[8];
char *character;
long long number;
} indirect;
/* indirect is a single 8-byte variable that can be accessed
* as either a character array, a character pointer, or as
* an 8-byte integer! */
char *x = "hi";
long long y;
char *z;
printf("stored in the memory beginning at x: '%s'\n", x); /* 'hi' */
printf("bytes used to represent the pointer x: %ld\n", sizeof(x)); /* 8 */
printf("exact value (memory location) of (pointed to by) the pointer x: %p\n", x); /* 4006c8 */
y = (long long) x;
printf("%llx\n", y); /* 4006c8 */
z = (char *) y;
printf("%s\n", z); /* 'hi' */
/* the cool part--we can access the exact same 8 bytes of data
* in three different ways, as a 64-bit character pointer,
* as an 8-byte character buffer, or as
* an 8-byte integer */
indirect.character = z;
printf("%s\n", indirect.character); /* 'hi' */
printf("%s\n", indirect.buffer); /* binary garbage which is the raw pointer */
printf("%lld\n", indirect.number); /* 4196040 */
return 0;
}
By the way, reading arbitrary locations from memory seems concerning. (You say that you are reading from a specific memory address within the program's own address space, but how do you make sure of that?)
fp=fopen("input.txt","rb");
The file has an extension of .txt and you are trying to read it as a binary file. Please name files accordingly. If on Windows, name binary files with .bin extention. On Linux file extension do not matter.
// buffer will store the DWORD read from the file
fread(buffer, 1, 4, fp);
If you want to read 4 bytes, declare an unsinged int variable and read 4 bytes into it as shown below
fread(&uint, 1, 4, fp);
Why do you want to use a character array ? That is incorrect.
printf("the memory address is: %x", *buffer);
What are you trying to do here ? buffer is a pointer to a const char and the above statement prints the hex value of the first character in the array. The above statement is equal to
printf("the memory address is: %x", buffer[0]);
(*(*buffer)
How is this working ? Aren't there any compiler warnings and errors ? Is it Windows or Linux ? (*buffer) is a char and again de-referencing it should throw and error unless properly cast which I see you are not doing.
Edit: I am not sure if this code does what I think it does. Could someone tell me how to test it? I.e. what should the buffer in my main function look like? I am assuming that a buffer has data of two fields in the following order type(16 bits), length(32 bits). I'm assuming that the buffer is read in from a file and each of the fields is separated by a space. The fields are stored in network byte order and when I read them I have to convert them back to host byte order.
I'm expecting that the code will read the contents from the file (which should be in network byte order) and display the contents in host byte order. I'm a bit confused about type conversions and what the network byte order will be inside of a file, so I don't know what values to use to test it. Also, I'm not sure if my code is written correctly, could someone who does this sort of thing or knows a bit more about such conversions tell me if my code is correct?
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printRecords(char *buffer)
{
unsigned int recordType;
unsigned long recordLength;
char *data;
char *index;
if (!buffer)
printf("Empty buffer\n");
while(*buffer)
{
memcpy(&recordType,(const void *) buffer,2);
buffer += 3;
recordType = ntohs(recordType);
printf("Record type normal: %u\n",recordType);
memcpy(&recordLength,(const void *) buffer,4);
buffer += 5;
recordLength = ntohl(recordLength);
printf("Record Length normal: %l\n",recordLength);
break;
}
}
void main()
{
char * buffer = "0000000000000001 00000000000000000000000000000001";
printRecords(buffer);
}
char *buffer = malloc(sizeof(buf));
sizeof means "size of buf's type", ie the size of a pointer to char; you probably want
malloc(strlen(buf) + 1); /* 1 for trailing '\0' */
Then you are mistaking the value of the bytes for their conversion to string:
"256" is byte '2' followed by byte '5' and '6' -- '2' is not equals to 2, '5' is not equals to 5 etc.
The 256 you are talking about is 00000001 00000000 instead (try dumping the bytes to stdout and you'll see).
Also, recordType should be of type uint16_t, not unsigned -- you're never too paranoid.
EDIT: atoi takes a pointer to char, as in
atoi("123")
not a pointer to int!
I'm sorry to bother you with this, but i'm stuck with it for too long already.
I get the following warning on fread: "warning: passing argument 1 of ‘fread’ makes pointer from integer without a cast"
I'm new to C and really like it, but don't get over this.
Thanks in advance.
typedef unsigned char byte;
int main( int argc, char *argv[]){
FILE * filein;
filein = fopen(argv[1], "r" );
int width=10;
int height=10;
byte ** data;
// Allocation
data = (byte **) malloc(height*sizeof(byte *));
for(int i=0;i<height;i++){
data[i]=(byte *) malloc(width*sizeof(byte));
}
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
fread(data[i][j], sizeof(const char), 1, infile);
}
}
for(int i=0;i<height;i++){
free(data[i]);
}
free(data);
fclose(filein);
return 0;
exit(0);
}
This is only a small piece of the actual program. The task is to read a binary pgm-image, store it in a data-matrix, normalize the values and write them to a new binary pgm-image.
fread() expects the void* pointer to the buffer. You are passing the value stored in data[i][j], not the pointer to the element data[i][j].
Try using the
fread(&data[i][j], sizeof(const char), 1, infile);
By the way, .pgm file format (if this is it) has a header and it is not sufficient to read only the width*height characters. The pixel values are also separated by spaces, so a little parsing is required. Also keep in mind that the end-of-line symbols also take space (.pgm cannot have more than 70 characters on one line)
The type of data[i][j] is byte. That is not a pointer. What you really want is to read to &data[i][j], if you're reading one byte at a time.
To read a single char, you can do
int c; // not char, because it must be able to hold EOF
c = getc(infile);
if( c == EOF ){
// do something about error or premature EOF
}
data[i][j] = c;
This is more verbose mostly because of the error checking that your code doesn't do.