Use quicklz to compress a txt file - c

I am working with an arm-cortex, programming in C/C++. I am generating a CSV file with the board, which only contains numbers (amplitudes of microphone 16bit).
I want to compress this file using a portable, small and fast library so iI chose QuickLZ. (I don't need the best compression).
Here is the link: http://www.quicklz.com/download.html
I understand that the algorithm is supposed to check the characters in the file and compress so the src/dst are char*. I have tried to do some code but I obtained a 0 byte zip file.
#include <stdio.h>
#include <stdlib.h>
#include "quicklz.h"
int main()
{
FILE *ifile = fopen("new_text_file.csv", "w");
FILE *ofile = fopen("new_zip_file.zip", "w");
char *src, *dst;
if (ifile != NULL) {
printf("OPEN SUCESS!\r\n");
}
else {
printf ("OPEN ERROR");
}
fprintf (ifile,"23483209489"); //Just for example
ifile = fopen("new.csv", "r");
qlz_state_compress *state_compress = (qlz_state_compress *)malloc(sizeof(qlz_state_compress));
size_t len, len2;
// allocate source buffer and read file
fseek(ifile, 0, SEEK_END);
len = ftell(ifile);
fseek(ifile, 0, SEEK_SET);
src = (char*) malloc(len);
fread(src, 1, len, ifile);
// allocate "uncompressed size" + 400 for the destination buffer
dst = (char*) malloc(len + 400);
// compress and write result
len2 = qlz_compress(src, dst, len, state_compress);
fwrite(dst, len2, 1, ofile);
fclose(ifile);
fclose(ofile);
}
Thanks all.

Related

Reading from file and store it to string with unknown length in c

I'm trying to read text from a file and store it into a string so that I can then encrypt and decrypt it using openssl. How can I do this?
You could use dynamic memory. My "skeleton" code for reading any type of file is this:
// Assumes: the file # file name is a text file; ASCII or UTF-8 (no BOM)
void readwholefile(char *filename)
{
FILE *fp;
char *buffer = NULL;
size_t i, len;
fp = fopen(filename, "rb");
fseek(fp, 0, SEEK_END);
len = ftell(fp);
rewind(fp);
buffer = malloc(len + 1);
if (NULL == buffer)
{
// Handle malloc failure & exit
exit(-1);
}
fread(buffer, 1, len, fp);
fclose(fp);
buffer[len] = '\0';
// buffer now contains the content of your file; do what you want with it
free(buffer);
buffer = NULL;
}
If you are using a POSIX system, you can use getline:
char *line = nullptr;
size_t line_size = 0
ssize_t len = getline(&line, &line_size, fp);
This will read until a newline and malloc enough space for the resulting line. You can use getdelim to read up to some delimiter other than a newline.

Why does the measurement of the size of a file differ from the size of the string that contains it once buffered?

In order to write the content of a file in a buffer, I first need to know the size of the string to allocate. To do this, I use the following function:
long file_length(FILE *fp)
{
if (fp == NULL) return -1L;
fseek(fp, 0L, SEEK_END);
const long len = ftell(fp);
rewind(fp);
return len;
}
And I use it as follows to store the contents of my file:
char *file_content(const char *fname)
{
assert(access(fname, F_OK) != -1);
assert(access(fname, R_OK) != -1);
FILE *fp = fopen(fname, "r");
assert(fp != NULL);
const long flen = file_length(fp);
printf("Length of file: %ld\n", flen);
char *buff = malloc(flen + 1);
assert(buff != NULL);
fread(buff, sizeof(char), flen, fp);
buff[flen + 1] = '\0';
fclose(fp);
return buff;
}
And then I test:
int main()
{
char *content = file_content("test.txt");
printf("Length of buffer: %lld\n", strlen(content));
free(content);
return 0;
}
Here's test.txt:
Hello, world!
This is a simple test.
Stackoverflow.
My program then displays this:
Length of file: 57
Length of buffer: 53
As the file has 4 line feeds, I imagine that the result is related to their interpretation according to the different readings that are made (for the position of the file, with fseek, and for its buffering, with fread). But is it? Or maybe it changes depending on the platform or a reading mode?
If that's the case, so I would like to know how to get the same results, so that I can allocate the exact size of the string directly from my file_length function, without having to subtract the number of line feeds the file contains (if it's possible?) in order to be as optimal as possible.

C not reading entire BMP file - fopen

So I am trying to read a .bmp file in C. I am later going to encrypt the file using openssl libraries - but that's only background info.
I need to open the file in binary mode (obviously) but for whatever reason when I try to open the file, it only reads in 4 bytes. When I try to output this exact file I just opened (for error testing) it outputs the following - 88 24 AD FB.
In my troubleshooting I decided to try this on a text file (54 bytes) and I get the exact same result.
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){
char * fileName="pic_original.bmp";
//read the file from given filename in binary mode
printf("Start to read the .bmp file \n");
FILE *image;
image = fopen(fileName,"rb");
//print the size of the image (4 bytes every damn time)
printf("Size of image: %d\n",sizeof(image));
//output the exact file that was read (error testing)
FILE *test;
test = fopen("./test.bin", "w");
fwrite(image, sizeof(image), 1, test);
fclose(test);
fclose(image);
return 1;
}
This is the image (uploaded as png for some reason)
Not exactly sure where I'm going wrong here but I'm not very seasoned in C.
Cheers,
Liam
EDIT 1:
//allocate memory for the header and image
char *headerBuf = (char *)malloc(54);
char *imageBuf = (char *)malloc(sizeof(image)-54); //this line is wrong - thanks to user EOF
//allocate memory for the final ciphertext
char *imagecipherCBC = (char *)malloc(sizeof(image)); //wrong also
//read first 54 bytes (header)
rewind(image);
fread(headerBuf,54,1,image);
//read the bitmap image until the end of the file
fread(imageBuf,sizeof(image),1,image); //also wrong
Well,
The size of the image is of course, 4 bytes which is a file pointer on a 32 bit machine.
I think you have to prepare some image buffer of your bmp file as a simple example, then you can do encrypt and decrypt the contents of this image buffer if your file is not too big.
static void read_from_image(char *imageBuf, int fileLength)
{
const char * outFileName="c:/DEV/temp/test.bin";
char headerBuf[54];
char *imagecipherCBC;
FILE *test;
test = fopen(outFileName, "wb");
//allocate memory for the final ciphertext
imagecipherCBC = (char *)malloc(fileLength *sizeof(char));
//read first 54 bytes (header)
//fread(headerBuf,54,1,image);
memcpy(headerBuf, imageBuf, 54 * sizeof(char));
//read the bitmap image until the end of the file
//fread(imageBuf,sizeof(image),1,image); //also wrong
fwrite(imageBuf, fileLength * sizeof(char), 1, test);
fflush(test);
fclose(test);
free(imagecipherCBC),imagecipherCBC = NULL;
free(imageBuf),imageBuf = NULL;
return;
}
You can have a file length and an image buffer in a main function.
int main(int argc, char *argv[])
{
const char * fileName="c:/DEV/temp/pic_original.bmp";
int fileLength = 0;
FILE *image;
char *imageBuffer;
imageBuffer = NULL;
image = fopen(fileName,"rb");
printf("read the file from given filename in binary mode \n");
printf("Start to read the .bmp file \n");
//try to get a file length;
fseek(image, 0, SEEK_END);
fileLength = ftell(image);
fseek(image, 0, SEEK_SET);
rewind(image);
imageBuffer = (char*)malloc(fileLength * sizeof(char));
//print the size of the image (4 bytes every damn time)
printf("read the file from given filename in binary mode \n");
printf("Size of image file pointer: %d\n",sizeof(image));
printf("Size of image: %d\n",fileLength);
//output the exact file that was read (error testing)
fread(imageBuffer,sizeof(char),fileLength*sizeof(char), image);
fclose(image);
read_from_image(imageBuffer, fileLength);
return 0;
}
good luck
If your goal is to encrypt the file then read the entire file in to buffer, encrypt it, and save it as binary. You can find the file size by moving the file pointer to the end. Example:
int main()
{
FILE *fin;
fin = fopen("pic_original.bmp", "rb");
fseek(fin, 0, SEEK_END);
int filesize = ftell(fin);
rewind(fin);
char *buf = malloc(filesize);
fread(buf, 1, filesize, fin);
fclose(fin);
//encrypt the buffer...
FILE *fout = fopen("output.bmp", "wb");
fwrite(buf, 1, filesize, fout);
fclose(fout);
return 0;
}
This will work with any file. OpenSSL already has functions to encrypt files directly.
If for some reason you want to keep the header the same, and only change the bits which follow, then read the header separately:
int main()
{
FILE *fin = fopen("input.bmp", "rb");
if(!fin) { printf("cannot open input\n"); return 0; }
FILE *fout = fopen("output.bmp", "wb");
if(!fout) { printf("cannot open output\n"); return 0; }
fseek(fin, 0, SEEK_END);
int filesize = ftell(fin);
if(filesize <= 54)
{
printf("wrong filesize\n");
return 0;
}
rewind(fin);
char *header = malloc(54);
char *buf = malloc(filesize - 54);
//encrypt buf...
fread(header, 1, 54, fin);
fread(buf, 1, filesize - 54, fin);
fclose(fin);
fwrite(header, 1, 54, fout);
fwrite(buf, 1, filesize - 54, fout);
fclose(fout);
free(header);
free(buf);
return 0;
}
I suppose this has the advantage that encrypted bitmap will still be recognized as a bitmap. But only encryption methods does not add extra bytes to the output.
Note that 8-bit, 4-bit and monochrome bitmaps have a palette which come after the 54 byte heading, then comes the image bits.

LzmaLib: compress / decompress buffer in C

I'm trying to use LzmaLib's LzmaCompress() and LzmaDecompress() with buffers, adapting the examples provided here.
I'm testing with a ~3MB buffer and the compression function seems to work fine (produces a ~1.2MB compressed buffer), but when I try to decompress, it just extracts ~300 bytes and returns SZ_ERROR_DATA.
The few extracted bytes are right, but I don't know why it stops there.
My code:
#include <stdio.h>
#include <stdlib.h>
#include "LzmaLib.h"
void compress(
unsigned char **outBuf, size_t *dstLen,
unsigned char *inBuf, size_t srcLen)
{
unsigned propsSize = LZMA_PROPS_SIZE;
*dstLen = srcLen + srcLen / 3 + 128;
*outBuf = (unsigned char*)malloc(propsSize + *dstLen);
int res = LzmaCompress(
(unsigned char*)(*outBuf + LZMA_PROPS_SIZE), dstLen,
inBuf, srcLen,
*outBuf, &propsSize,
-1, 0, -1, -1, -1, -1, -1);
assert(res == SZ_OK);
*dstLen = *dstLen + LZMA_PROPS_SIZE;
}
void uncompress(
unsigned char **outBuf, size_t *dstLen,
unsigned char *inBuf, size_t srcLen
) {
*dstLen = 5000000;
*outBuf = (unsigned char*)malloc(*dstLen);
srcLen = srcLen - LZMA_PROPS_SIZE;
int res = LzmaUncompress(
*outBuf, dstLen,
(unsigned char*)(inBuf + LZMA_PROPS_SIZE), &srcLen,
inBuf, LZMA_PROPS_SIZE);
assert(res == SZ_OK);
}
void do_compress() {
FILE* file = fopen("Module.dll", "r");
size_t size, decSize;
unsigned char *data, *dec = NULL;
fseek(file, 0L, SEEK_END);
size = ftell(file);
fseek(file, 0L, SEEK_SET);
data = (unsigned char*)malloc(size);
fread(data, 1, size, file);
fclose(file);
compress((unsigned char**)&dec, &decSize, data, size);
file = fopen("Module.lzma", "w");
fwrite(dec, 1, decSize, file);
fclose(file);
}
void do_uncompress() {
FILE* file = fopen("Module.lzma", "r");
size_t size, decSize;
unsigned char *data, *dec = NULL;
fseek(file, 0L, SEEK_END);
size = ftell(file);
fseek(file, 0L, SEEK_SET);
data = (unsigned char*)malloc(size);
fread(data, 1, size, file);
fclose(file);
uncompress((unsigned char**)&dec, &decSize, data, size);
file = fopen("Module_DEC.dll", "w");
fwrite(dec, 1, decSize, file);
fclose(file);
}
int main()
{
do_compress();
do_uncompress();
return 0;
}
If this code is not the better way to compress buffers with LzmaLib, I'm happy to accept suggestions.
I bet the problem lurks in how you read/write your files. You need to open them in binary mode to prevent any substitutions during read/write operations.
Change all instances of:
fopen(xxx, "r") -> fopen(xxx, "rb")
fopen(xxx, "w") -> fopen(xxx, "wb")
I didn't check this specificly for LzmaCompress but most of the other compressing libraries like libz handle that function similar to the standard read/write or fread/fwrite functions, i.e. allowing you to continuously calling the functions to compress more and more data in one stream. So at some point, you will have to say "I'm done, please flush everything not written so far". Possibly, you forgot that part. If not, a Minimal, Complete, and Verifiable example would be cool.
When you compress, you pass the number of compressed output bytes to the caller. But your buffer contains LZMA_PROPS_SIZE additional bytes. So, when writing the lzma file, you actually forget the last LZMA_PROPS_SIZE bytes and on later reading, those are missing.

How to read the content of a file to a string in C?

What is the simplest way (least error-prone, least lines of code, however you want to interpret it) to open a file in C and read its contents into a string (char*, char[], whatever)?
I tend to just load the entire buffer as a raw memory chunk into memory and do the parsing on my own. That way I have best control over what the standard lib does on multiple platforms.
This is a stub I use for this. you may also want to check the error-codes for fseek, ftell and fread. (omitted for clarity).
char * buffer = 0;
long length;
FILE * f = fopen (filename, "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = malloc (length);
if (buffer)
{
fread (buffer, 1, length, f);
}
fclose (f);
}
if (buffer)
{
// start to process your data / extract strings here...
}
Another, unfortunately highly OS-dependent, solution is memory mapping the file. The benefits generally include performance of the read, and reduced memory use as the applications view and operating systems file cache can actually share the physical memory.
POSIX code would look like this:
int fd = open("filename", O_RDONLY);
int len = lseek(fd, 0, SEEK_END);
void *data = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
Windows on the other hand is little more tricky, and unfortunately I don't have a compiler in front of me to test, but the functionality is provided by CreateFileMapping() and MapViewOfFile().
If "read its contents into a string" means that the file does not contain characters with code 0, you can also use getdelim() function, that either accepts a block of memory and reallocates it if necessary, or just allocates the entire buffer for you, and reads the file into it until it encounters a specified delimiter or end of file. Just pass '\0' as the delimiter to read the entire file.
This function is available in the GNU C Library, http://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getdelim-994
The sample code might look as simple as
char* buffer = NULL;
size_t len;
ssize_t bytes_read = getdelim( &buffer, &len, '\0', fp);
if ( bytes_read != -1) {
/* Success, now the entire file is in the buffer */
If you are reading special files like stdin or a pipe, you are not going to be able to use fstat to get the file size beforehand. Also, if you are reading a binary file fgets is going to lose the string size information because of embedded '\0' characters. Best way to read a file then is to use read and realloc:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main () {
char buf[4096];
ssize_t n;
char *str = NULL;
size_t len = 0;
while (n = read(STDIN_FILENO, buf, sizeof buf)) {
if (n < 0) {
if (errno == EAGAIN)
continue;
perror("read");
break;
}
str = realloc(str, len + n + 1);
memcpy(str + len, buf, n);
len += n;
str[len] = '\0';
}
printf("%.*s\n", len, str);
return 0;
}
Note: This is a modification of the accepted answer above.
Here's a way to do it, complete with error checking.
I've added a size checker to quit when file was bigger than 1 GiB. I did this because the program puts the whole file into a string which may use too much ram and crash a computer. However, if you don't care about that you could just remove it from the code.
#include <stdio.h>
#include <stdlib.h>
#define FILE_OK 0
#define FILE_NOT_EXIST 1
#define FILE_TOO_LARGE 2
#define FILE_READ_ERROR 3
char * c_read_file(const char * f_name, int * err, size_t * f_size) {
char * buffer;
size_t length;
FILE * f = fopen(f_name, "rb");
size_t read_length;
if (f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek(f, 0, SEEK_SET);
// 1 GiB; best not to load a whole large file in one string
if (length > 1073741824) {
*err = FILE_TOO_LARGE;
return NULL;
}
buffer = (char *)malloc(length + 1);
if (length) {
read_length = fread(buffer, 1, length, f);
if (length != read_length) {
free(buffer);
*err = FILE_READ_ERROR;
return NULL;
}
}
fclose(f);
*err = FILE_OK;
buffer[length] = '\0';
*f_size = length;
}
else {
*err = FILE_NOT_EXIST;
return NULL;
}
return buffer;
}
And to check for errors:
int err;
size_t f_size;
char * f_data;
f_data = c_read_file("test.txt", &err, &f_size);
if (err) {
// process error
}
else {
// process data
free(f_data);
}
What is the simplest way (least error-prone, least lines of code, however you want to interpret it) to open a file in C and read its contents into a string ...?
Sadly, even after years, answers are error prone and many lack proper string formation and error checking.
#include <stdio.h>
#include <stdlib.h>
// Read the file into allocated memory.
// Return NULL on error.
char* readfile(FILE *f) {
// f invalid? fseek() fail?
if (f == NULL || fseek(f, 0, SEEK_END)) {
return NULL;
}
long length = ftell(f);
rewind(f);
// Did ftell() fail? Is the length too long?
if (length == -1 || (unsigned long) length >= SIZE_MAX) {
return NULL;
}
// Convert from long to size_t
size_t ulength = (size_t) length;
char *buffer = malloc(ulength + 1);
// Allocation failed? Read incomplete?
if (buffer == NULL || fread(buffer, 1, ulength, f) != ulength) {
free(buffer);
return NULL;
}
buffer[ulength] = '\0'; // Now buffer points to a string
return buffer;
}
Note that if the text file contains null characters, the allocated data will contain all the file data, yet the string will appear to be short. Better code would also return the length information so the caller can handle that.
char* readfile(FILE *f, size_t *ulength_ptr) {
...
if (ulength_ptr) *ulength_ptr == *ulength;
...
}
If the file is text, and you want to get the text line by line, the easiest way is to use fgets().
char buffer[100];
FILE *fp = fopen("filename", "r"); // do not use "rb"
while (fgets(buffer, sizeof(buffer), fp)) {
... do something
}
fclose(fp);
If you're using glib, then you can use g_file_get_contents;
gchar *contents;
GError *err = NULL;
g_file_get_contents ("foo.txt", &contents, NULL, &err);
g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));
if (err != NULL)
{
// Report error to user, and free error
g_assert (contents == NULL);
fprintf (stderr, "Unable to read file: %s\n", err->message);
g_error_free (err);
}
else
{
// Use file contents
g_assert (contents != NULL);
}
}
Just modified from the accepted answer above.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char *readFile(char *filename) {
FILE *f = fopen(filename, "rt");
assert(f);
fseek(f, 0, SEEK_END);
long length = ftell(f);
fseek(f, 0, SEEK_SET);
char *buffer = (char *) malloc(length + 1);
buffer[length] = '\0';
fread(buffer, 1, length, f);
fclose(f);
return buffer;
}
int main() {
char *content = readFile("../hello.txt");
printf("%s", content);
}
// Assumes the file exists and will seg. fault otherwise.
const GLchar *load_shader_source(char *filename) {
FILE *file = fopen(filename, "r"); // open
fseek(file, 0L, SEEK_END); // find the end
size_t size = ftell(file); // get the size in bytes
GLchar *shaderSource = calloc(1, size); // allocate enough bytes
rewind(file); // go back to file beginning
fread(shaderSource, size, sizeof(char), file); // read each char into ourblock
fclose(file); // close the stream
return shaderSource;
}
This is a pretty crude solution because nothing is checked against null.
I will add my own version, based on the answers here, just for reference. My code takes into consideration sizeof(char) and adds a few comments to it.
// Open the file in read mode.
FILE *file = fopen(file_name, "r");
// Check if there was an error.
if (file == NULL) {
fprintf(stderr, "Error: Can't open file '%s'.", file_name);
exit(EXIT_FAILURE);
}
// Get the file length
fseek(file, 0, SEEK_END);
long length = ftell(file);
fseek(file, 0, SEEK_SET);
// Create the string for the file contents.
char *buffer = malloc(sizeof(char) * (length + 1));
buffer[length] = '\0';
// Set the contents of the string.
fread(buffer, sizeof(char), length, file);
// Close the file.
fclose(file);
// Do something with the data.
// ...
// Free the allocated string space.
free(buffer);
easy and neat(assuming contents in the file are less than 10000):
void read_whole_file(char fileName[1000], char buffer[10000])
{
FILE * file = fopen(fileName, "r");
if(file == NULL)
{
puts("File not found");
exit(1);
}
char c;
int idx=0;
while (fscanf(file , "%c" ,&c) == 1)
{
buffer[idx] = c;
idx++;
}
buffer[idx] = 0;
}

Resources