Reading and printing characters from a user defined text file - c++

I am trying to work out how I can print character by character the contents of a user-defined text file. I believe I have got the retrieval of the file correct but I am unsure how I can print each character.
#include <stdio.h>
#include <ctype.h>
#define ELEMENT 300
#define LENGTH 20
void main(char str[ELEMENT][LENGTH])
{
FILE *infile;
char textfile[1000];
char read_char;
int endoff;
int poswithin = 0;
int wordnum= 0;
printf("What is the name of your text file?: ");
scanf("%s", &textfile);
infile=fopen(textfile,"r");
if (infile == NULL) {
printf("Unable to open the file.");
}
else
{
endoff=fscanf(infile,"%c",&read_char);
while(endoff!=EOF);
{
This is where I believe I'm stuck. The first character is read into the variable read_char but then it doesn't seem to print anything?
if(read_char>=65&&read_char<=90 || read_char<=65)
{
str[wordnum][poswithin]=read_char;
printf("%c", read_char);
poswithin++;
}
else
{
str[wordnum][poswithin]=(char)"\n";
poswithin=0; wordnum++;
}
endoff=fscanf(infile, "%s", &read_char);
}
}
fclose(infile);
}

Typo in the format specifier to your second call to fscanf
endoff=fscanf(infile, "%s", &read_char);
should be
endoff=fscanf(infile, "%c", &read_char);
Also,
str[wordnum][poswithin]=(char)"\n";
shouldn't be casting a string literal to char and probably should be adding a NULL terminator rather than a newline:
str[wordnum][poswithin]='\0';
Finally, you shouldn't try to declare str as an argument to main.
char str[ELEMENT][LENGTH];
int main() // or int main(int argc, char* argv[])

Using fscanf with %c format specifier is overkill for reading a single character from a file.
Try fgetc to read one character. The function avoids the overhead of parsing a format specifier string and variable number of arguments.
A more efficient method is to allocate a buffer or array and read "chunks" of chars from a file, using fread. You can then scan the buffer or array. This has less function call overhead than many calls to read single bytes. Efficient buffer sizes are multiples of 512 to conform with disk drive sector sizes.

Related

Load shellcode from file to char* comes strange characters in end of text

I have a char array[] and is like following:
// MessageBox
char xcode[] = "\x31\xc9\x64\x8b\x41\x30\x8b\x40\xc\x8b\x70\x14\xad\x96\xad\x8b\x58\x10\x8b\x53\x3c\x1\xda\x8b\x52\x78\x1\xda\x8b\x72\x20\x1\xde\x31\xc9\x41\xad\x1\xd8\x81\x38\x47\x65\x74\x50\x75\xf4\x81\x78\x4\x72\x6f\x63\x41\x75\xeb\x81\x78\x8\x64\x64\x72\x65\x75\xe2\x8b\x72\x24\x1\xde\x66\x8b\xc\x4e\x49\x8b\x72\x1c\x1\xde\x8b\x14\x8e\x1\xda\x31\xc9\x53\x52\x51\x68\x61\x72\x79\x41\x68\x4c\x69\x62\x72\x68\x4c\x6f\x61\x64\x54\x53\xff\xd2\x83\xc4\xc\x59\x50\x51\x66\xb9\x6c\x6c\x51\x68\x33\x32\x2e\x64\x68\x75\x73\x65\x72\x54\xff\xd0\x83\xc4\x10\x8b\x54\x24\x4\xb9\x6f\x78\x41\x0\x51\x68\x61\x67\x65\x42\x68\x4d\x65\x73\x73\x54\x50\xff\xd2\x83\xc4\x10\x68\x61\x62\x63\x64\x83\x6c\x24\x3\x64\x89\xe6\x31\xc9\x51\x56\x56\x51\xff\xd0";
Then i had inserted all this content of variable above into a file (file with UTF-8 format and content without the "") and tried load this way:
ifstream infile;
infile.open("shellcode.bin", std::ios::in | std::ios::binary);
infile.seekg(0, std::ios::end);
size_t file_size_in_byte = infile.tellg();
char* xcode = (char*)malloc(sizeof(char) * file_size_in_byte);
infile.seekg(0, std::ios::beg);
infile.read(xcode, file_size_in_byte);
printf("%s\n", xcode); // << prints content of xcode after load from file
if (infile.eof()) {
size_t bytes_really_read = infile.gcount();
}
else if (infile.fail()) {
}
infile.close();
I'm seeing some strange characters in end of text see:
What is need to fix it?
The issue is that the printf format specifier "%s" requires that the string is null-terminated. In your case, the null-terminator just happens to be after those characters you're seeing, but nothing guarantees where the null is unless you put one there.
Since you're using C++, one way to print the characters is to use the write() function available for streams:
#include <iostream>
//...
std::cout.write(xcode, file_size_in_bytes);
The overall point is this -- if you have a character array that is not null-terminated and contains data, you must either:
Put the null in the right place before using the array in functions that look for the null-terminator or
Use functions that state how many characters to process from the character array.
The answer above uses item 2.

How do I remove Chars from the end of a Char*?

I am writing a program in C++ that takes in an argument for a filename, the argument is a char*
ex: myFile.lan
I need to remove the last 3 digits of this char* ("lan") and change them to "asm" (ex: myFile.asm)
It seems really easy to add chars to a char pointer through strcpy, but does anyone know how I can remove chars from a char pointer?
If you're using C++, you should convert your argument to an std::string. This will protect you from going out of bounds and is more clear.
#include <string>
#include <iostream>
int main ()
{
// ... get the arg
const char* arg = "myFile.lan";
std::string filenameAsm(arg);
filenameAsm = filenameAsm.substr(0, filenameAsm.find_last_of("."));
filenameAsm += ".asm";
std::cout << filenameAsm; // prints myFile.asm
return 0;
}
What this code does is take only the part of the filename preceding the "." file extension delimiter (if it doesn't exist, it will take the whole filename) and append the desired ".asm" extension.
Working with a char * is basic 'C'. You can write anything into the memory space, but be careful about not going past the end of allocated space.
char * strings are all terminated with the null byte \0. So, to truncate, you could put a \0 at the appropriate location.
On the other hand, to overwrite characters, just use array syntax; e.g. if the string is length 10 and you want to change the last character, c_string[9] = 'X'; would change that character to an X.
You have to know how a string is ended in C. The length of your string is determined by the first occurrence of the \0 character. Thus, by moving this character backwards, your string becomes shorter. So you probably want to search your string for the first position of the dot, and then replace this dot with \0 (this depends on how exactly the string input looks like though. i'm assuming it's always filenames with a dot somewhere, but you know better).
Using the tools in string.h can simplify the task. strrchr will find the last '.' in the filename allowing you to manipulate the extension. Don't forget to test the lengths of new/old extension to prevent overwriting the \0 - null-terminating character (if the lengths differ, you can always concatenate or realloc the string size, but that's beyond the scope of this example). Look over the solution and let me know if you have any questions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv) {
if (argc < 3) {
fprintf (stderr, "\n error: insufficient input. Usage: %s <filename> <new_ext>\n\n", argv[0]);
return 1;
}
char *filename = strdup (argv[1]); /* copy argv[1] to prevent clobbering it */
char *p = strrchr (filename, '.'); /* pointer to last '.' in filename */
char *ext = strdup (p+1); /* make a copy of existing extension */
size_t esz = strlen (ext); /* length of existing extension in filename */
size_t nesz = strlen (argv[2]); /* length of new extension */
if (esz < nesz) {
fprintf (stderr, "\n error: invalid extension size. (%s > %s)\n\n", argv[2], ext);
return 1;
}
printf ("\n The original filename: %s\n", filename);
strncpy (p+1, argv[2], nesz); /* copy new extension to filename */
if (nesz < esz) /* if new extension is shorter than old */
*(p+1+nesz) = 0; /* null terminate after new extesion size */
printf (" The amended filename : %s\n\n", filename);
if (filename) free (filename); /* free memory allocated by strdup */
if (ext) free (ext);
return 0;
}
output:
$ ./bin/swapext myfile.lan asm
The original filename: myfile.lan
The amended filename : myfile.asm
$ ./bin/swapext myfile.lan c
The original filename: myfile.lan
The amended filename : myfile.c

Reading null characters into char array for hex conversion

I am writing a program which reads input from a text file and converts it to hexadecimal for later processing.
ifstream fin("input.txt"); //open file with ifstream
if(fin.is_open()){ //check if file is open
for(int i = 0; i<length; i++){ //int length for how many characters I need
fin.get(buffer[i]); //write into char array buffer[256]
}
}
else{
cout<<"Can't open file";
exit(0);
}
fin.close();
So everything is fine, it opens up nicely and gets exactly as many characters as I need from there, later I use a function to turn that into a hexadecimal string:
std::string string_to_hex(const std::string input)
{
static const char* const lut = "0123456789ABCDEF";
size_t len = input.length();
string output;
output.reserve(2 * len);
for (size_t i = 0; i < len; ++i)
{
const unsigned char c = input[i];
output.push_back(lut[c >> 4]);
output.push_back(lut[c & 15]);
}
return output;
}
which also works fine, it gives me the correct hexadecimal value for the characters that I get.
Now here is the problem: my file contains null characters (hexadecimal "00" characters aka '\0') which I need to read into my program and do a proper conversion so every null character in my array after conversion should look like "00". Every time I
try to convert null characters in my array they change into spaces (hexadecimal "20"), which ruins my data for processing later. Changing "20" into "00" is also not an option since the file contains real spaces that also need to be properly processed.
This is my first time working with null characters and I am absolutely confused on how to properly process them. All I know is that null characters are used at the end of a string or an array so when I print them out the program would know when to stop.
I do not know how I should do it properly. I tried opening the file differently using fopen, I tried copying my input.txt into an array differently. Maybe it copies it properly but the hex conversion doesn't work. Maybe I shouldn't send it as a string for conversion. I don't know. I also noticed that when I tried to copy paste a sample from the file to another file, all the null characters have been replaced by spaces, maybe it has something to do with this?

Trouble with fscanf() in c programming

I am trying to read some data in a file called "data" with specific format. The data in this file is:
0 mpi_write() 100
1 mpi_write() 200
2 mpi_write() 300
4 mpi_write() 400
5 mpi_write() 1000
then code is as follow:
#include<stdlib.h>
#include<stdio.h>
typedef struct tracetype{
int pid;
char* operation;
int size;
}tracetyper;
void main(){
FILE* file1;
file1=fopen("./data","r");
if(file1==NULL){
printf("cannot open file");
exit(1);
}else{
tracetyper* t=(tracetyper*)malloc(sizeof(tracetyper));
while(feof(file1)!=EOF){
fscanf(file1,"%d %s %d\n",&t->pid,t->operation,&t->size);
printf("pid:%d,operation:%s,size:%d",t->pid,t->operation,t->size);
}
free(t);
}
fclose(file1);
}
When running with gdb, I found fscanf doesn't write data to t->pid,t->operation and t->size. Any thing wrong with my code or what? Please help me!
Your program has undefined behavior: you are reading %s data into an uninitialized char* pointer. You need to either allocate operation with malloc, or if you know the max length is, say, 20 characters, you can put a fixed string for it into the struct itself:
typedef struct tracetype{
int pid;
char operation[21]; // +1 for null terminator
int size;
} tracetyper;
When you read %s data, you should always tell fscanf the limit on the length, like this:
fscanf(file1,"%d %20s %d\n",&t->pid,t->operation,&t->size);
Finally, you should remove \n at the end of the string, and check the count of returned values instead of checking feof, like this:
for (;;) { // Infinite loop
...
if (fscanf(file1,"%d %20s %d",&t->pid,t->operation,&t->size) != 3) {
break;
}
...
}
You should loop with something like:
while ( (fscanf(file1,"%d %s %d\n",&t->pid,t->operation,&t->size)) != EOF) {
printf("pid:%d,operation:%s,size:%d",t->pid,t->operation,t->size);
}
You also need to add malloc for char array in the structure.
Also, insert a check for t as
if (t == NULL)
cleanup();

Passing a character array to function | Strange error

Basically I have a buffer in which i am looking for various flags to read certain fields from a binary file format. I have file read into a buffer but as i started to write code to search the buffer for the flags i immediately hit a wall. I am a C++ noob, but here is what i have:
void FileReader::parseBuffer(char * buffer, int length)
{
//start by looking for a vrsn
//Header seek around for a vrns followed by 32 bit size descriptor
//read 32 bits at a time
int cursor = 0;
char vrsn[4] = {'v','r','s','n'};
cursor = this->searchForMarker(cursor, length, vrsn, buffer);
}
int FileReader::searchForMarker(int startPos, int eof, char marker[], char * buffer)
{
int cursor = startPos;
while(cursor < eof) {
//read ahead 4 bytes from the cursor into a tmpbuffer
char tmpbuffer[4] = {buffer[cursor], buffer[cursor+1], buffer[cursor+2], buffer[cursor+3]};
if (strcmp(marker, tmpbuffer)) {
cout << "Found: " << tmpbuffer;
return cursor;
}
else {
cout << "Didn't Find Value: " << marker << " != " << tmpbuffer;
}
cursor = cursor + 4;
}
}
my header looks like this:
#ifndef __FILEREADER_H_INCLUDED__
#define __FILEREADER_H_INCLUDED__
#include <iostream>
#include <fstream>
#include <sys/stat.h>
class FileReader {
public:
FileReader();
~FileReader();
int open(char *);
int getcode();
private:
void parseBuffer(char *, int);
int searchForMarker(int, int, char[], char *);
char *buffer;
};
#endif
I would expect to get back a match for vrsn with strcmp but my result looks like this
Didn't Find Value: vrsn != vrsn
Found:
It looks like it finds it on the second pass after its passed the char array i am looking for.
Relevant hexcode
Your problem is two-fold:
strcmp returns "0" on success, not on failure. Read the documentation.
strcmp expects null-terminated strings. You say that you have chosen non-terminated char arrays because that's what your DB library uses. Well, fine. But still, you are violating the requirements of strcmp. Use strncmp instead (which takes a length argument) or, preferably, actually write C++ and start using std::vector<char> and friends.
Shouldn't that be something like int FileReader::searchForMarker(...) { .... }?
For the second query, I guess the strcmp works when it has two null terminated strings as its arguments. For example str1[]="AAA"; and str2[]="AAA"; then strcmp() would be used as
if(strcmp(str1,str2)==0) which will return 0 to indicate that they are equal. In your case, the tmpbuffer that you have created is not a null terminated string unless you add \0 in the end.So you might want to add \0 in the end of your tmpbuffer to create a string of 'v' 'r' 'n' 's'.
char vrsn[4] = {'v','r','s','n'};
Contains only the 4 characters specified. There is no room for a null character at the end.
char tmpbuffer[4] = {buffer[cursor], buffer[cursor+1], buffer[cursor+2], buffer[cursor+3]};
Contains only the 4 characters from buffer. There is no room for a null character at the end.
Eventually you call:
if (strcmp(marker, tmpbuffer)) {
The strcmp() function expects each of its parameters to end with a null character ('\0'). It wants to work with strings, which are null terminated.
Since your data is not null terminated, you probably want to use memcmp() instead of strcmp().
Also, strcmp() returns zero when its arguments are equal, so the condition in the if statement is inverted. (Zero is false, everything else is true.) The memcmp() function will also return zero when its arguments are equal.