I'm trying to save binary data of images in Key-Value Store
1st, read data using "fread" function. 2nd, save it into RocksDB. 3rd, Get the data from RocksDB and restore the data into form of image.
Now I don't know whether I have problem in 2nd step of 3rd step.
2nd step Put
#include <iostream>
#include <string.h>
#include "rocksdb/db.h"
DB* db;
Options options;
options.create_if_missing = true;
Status s = DB::Open(options, <DBPath>, &db);
assert(s.ok());
//read image
FILE* file_in;
int fopen_err = fopen_s(&file_in, <input_file_path>, "rb");
if (fopen_err != 0) {
printf(input_file_path, "%s is not valid");;
}
fseek(file_in, 0, SEEK_END);
long int file_size = ftell(file_in);
rewind(file_in);
//malloc buffer
char* buffer = (char*)malloc(file_size);
if (buffer == NULL) { printf("Memory Error!!"); }
fread(buffer, file_size, 1, file_in);
//main func
db->Put(WriteOptions(), file_key, buffer);
assert(s.ok());
fclose(file_in);
free(buffer);
buffer = NULL;
delete db;
3rd step Get
#include <iostream>
#include <string.h>
#include "rocksdb/db.h"
DB* db;
Options options;
options.create_if_missing = true;
Status s = DB::Open(options, <DBPath>, &db);
assert(s.ok());
//main func
std::string file_data
s = db->Get(ReadOptions(), file_key, &file_data);
assert(s.ok());
//convert std::string to char*
char* buffer = (char*)malloc(file_data.size() + 1);
std::copy(file_data.begin(), file_data.end(), buffer);
//restore image
FILE* test;
fopen_s(&test, "test.jpg", "wb");
fwrite(buffer, file_data.size(), 1, test);
fclose(test);
free(buffer);
delete db;
The output image is not valid, and if I convert jpg to txt, I only get "???".
I tried on BerkeleyDB in the same process, and I succeed to restore image.(I think it's because of Dbt class of BerkeleyDB)
I don't know where the data get crashed. Did I missed some options or process...?
char* buffer = ...
db->Put(WriteOptions(), file_key, buffer);
How is RocksDB supposed to know the length of the buffer? When passing in a char* here, it is assumed to be a nul-terminated C string using the Slice(char *) implicit conversion. Nul-terminated C strings cannot be used for binary data because the data will be cut off at the first zero byte.
Although some RocksDB APIs are not up to modern C++ standards (for API compatibility), it is written for use with C++. Nul-terminated char *, FILE, fseek etc. are from C and cause lots of difficulty when attempting to interact with C++. If buffer were std::string, this bug would be fixed because the Slice(std::string) implicit conversion is very safe.
Other bugs:
Failure to re-assign s for the db->Put
Failure to abort on error cases with printf
Better to call DB::Close(db) before delete to check status, as there could be a background error
Not checking for error in fread
Performance/clarity issue:
In 3rd step, no need to create char *buffer and copy in std::string file_data to it. file_data.data() and file_data.size() give you access to the underlying char buffer if needed (but using C++ APIs is better).
Related
First off, I understand that RC4 is not the safest encryption method and that it is outdated, this is just for a school project. Just thought I put it out there since people may ask.
I am working on using RC4 from OpenSSL to make a simple encryption and decryption program in C++. I noticed that the encryption and decryption is inconsistent. Here is what I have so far:
#include <fcntl.h>
#include <openssl/evp.h>
#include <openssl/rc4.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int inputFile = open(argv[1], O_RDONLY);
if (inputFile < 0) {
printf("Error opening file\n");
return 1;
}
unsigned char *keygen = reinterpret_cast<unsigned char*>(argv[2]);
RC4_KEY key;
size_t size = lseek(inputFile, 0, SEEK_END);
lseek(inputFile, 0, SEEK_SET);
unsigned char *fileIn = (unsigned char*) calloc(size, 1);
if (pread(inputFile, fileIn, size, 0) == -1) {
perror("Error opening read\n");
return 1;
}
unsigned char *fileOut = (unsigned char*) calloc(size, 1);
unsigned char *actualKey;
EVP_BytesToKey(EVP_rc4(), EVP_sha256(), NULL, keygen, sizeof(keygen), 1, actualKey, NULL);
RC4_set_key(&key, sizeof(actualKey), actualKey);
RC4(&key, size, fileIn, fileOut);
int outputFile = open(argv[3], O_WRONLY | O_TRUNC | O_CREAT, 0644);
if (outputFile < 0) {
perror("Error opening output file");
return 1;
}
if (pwrite(outputFile, fileOut, size, 0) == -1) {
perror("error writing file");
return 1;
}
close(inputFile);
close(outputFile);
free(fileIn);
free(fileOut);
return 0;
}
The syntax for running this in Ubuntu is:
./myRC4 test.txt pass123 testEnc.txt
MOST of the time this works fine, and encrypts and decrypts the file. However occasionally I get a Segmentation fault. If I do, I run the same exact command again and it encrypts or decrypts fine, at least for .txt files.
When I test on .jpg files, or any larger file, the issue seems to be more common and inconsistent. I notice that sometimes the images appear to have been decrypted (no segmentation fault) but in reality it has not, which I test by doing a diff between the original and the decrypted file.
Any ideas as to why I get these inconsistencies? Does it have to do with how I allocate memory for fileOut and fileIn?
Thank you in advance
actualKey needs to be pointing to a buffer of appropriate size before you pass it to EVP_BytesToKey. As it is you are passing in an uninitialised pointer which would explain your inconsistent results.
The documentation for EVP_BytesToKey has this to say:
If data is NULL, then EVP_BytesToKey() returns the number of bytes needed to store the derived key.
So you can call EVP_BytesToKey once with the data parameter set to NULL to determine the length of actualKey, then allocate a suitable buffer and call it again with actualKey pointing to that buffer.
As others have noted, passing sizeof(keygen) to EVP_BytesToKey is also incorrect. You probably meant strlen (argv [2]).
Likewise, passing sizeof(actualKey) to RC4_set_key is also an error. Instead, you should pass the value returned by EVP_BytesToKey.
I need to create a custom reading callback function that can read contents of a file in the form of a std::string into a uint8_t * buf. I tried multiple different methods found around the internet and on stackoverflow but sometimes it works and other the the program infinitely loops or stops execution half way.
I have no problems with amr/3gp files but all wav/pcm files are causing some problems for some reason. All I know its something to do with the reading function I have so far.
Ideally I would like to be able to give the program any type of file and then it converts it.
This is how I am calling the readCallback function from the code:
//create the buffer
uint8_t * avio_ctx_buffer = NULL;
//allocate space for the buffer using ffmpeg allocation method
avio_ctx_buffer = (uint8_t *) av_malloc(avio_ctx_buffer_size);
//Allocate and initialize an AVIOContext for buffered I/O.
//audio variable contains the contents of the audio file
avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,0, &audio, &readCallback, NULL, NULL);
Here is the callback function that works on some types of files:
static int readCallback(void* opaque, uint8_t * buf, int buf_size){
std::string * file =static_cast<std::string *>(opaque);
if(file->length() == 0){
return AVERROR_EOF; //if we reach to the end of the string, return
// return End of file
}
// Creating a vector of the string size
std::vector<uint8_t> array(file->length());
//Copying the contents of the string into the vector
std::copy(file->begin(),file->end(),array.begin());
//Copying the vector into buf
std::copy(array.begin(),array.end(),buf);
return file->length();
}
After tyring some stuff for awhile, I got a solution using std::stringstream and it works well with several formats I tested with so far: 3gp/amr,wav/pcm,mp3.
Here a the snippet of code:
//Create a string stream that contains the audio
std::stringstream audio_stream(audio);
//create the buffer
uint8_t * avio_ctx_buffer = NULL;
//allocate space for the buffer using ffmpeg allocation method
avio_ctx_buffer = (uint8_t *) av_malloc(avio_ctx_buffer_size);
//Allocate and initialize an AVIOContext for buffered I/O.
//Pass the stringstream audio_stream
avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,0,&audio_stream, &readCallback, NULL, NULL);
The callback function:
static int readFunction1(void* opaque, uint8_t * buf, int buf_size){
//Cast the opaque pointer to std::stringstream
std::stringstream * me =static_cast<std::stringstream *>(opaque);
//If we are at the end of the stream return FFmpeg's EOF
if(me->tellg() == buf_size){
return AVERROR_EOF;
}
// Read the stream into the buf and cast it to char *
me->read((char*)buf, buf_size);
//return how many characters extracted
return me->tellg();
}
I'm trying to make a exe program that can read any file to binary and later use this binary to make the exact same file.
So I figured out that I can use fopen(content,"rb") to read a file as binary,
and using fwrite I can write block of data into stream. But the problem is when I fwrite it doesn't seems copy everything.
For example the text I opened contains 31231232131 in it. When I write it into another file it only copies 3123 (first 4 bytes).
I can see that it's a very simple thing that I'm missing but I don't know what.
#include <stdio.h>
#include <iostream>
using namespace std;
typedef unsigned char BYTE;
long getFileSize(FILE *file)
{
long lCurPos, lEndPos;
lCurPos = ftell(file);
fseek(file, 0, 2);
lEndPos = ftell(file);
fseek(file, lCurPos, 0);
return lEndPos;
}
int main()
{
//const char *filePath = "C:\\Documents and Settings\\Digital10\\MyDocuments\\Downloads\\123123.txt";
const char *filePath = "C:\\Program Files\\NPKI\\yessign\\User\\008104920100809181000405,OU=HNB,OU=personal4IB,O=yessign,C=kr\\SignCert.der";
BYTE *fileBuf;
FILE *file = NULL;
if ((file = fopen(filePath, "rb")) == NULL)
cout << "Could not open specified file" << endl;
else
cout << "File opened successfully" << endl;
long fileSize = getFileSize(file);
fileBuf = new BYTE[fileSize];
fread(fileBuf, fileSize, 1, file);
FILE* fi = fopen("C:\\Documents and Settings\\Digital10\\My Documents\\Downloads\\gcc.txt","wb");
fwrite(fileBuf,sizeof(fileBuf),1,fi);
cin.get();
delete[]fileBuf;
fclose(file);
fclose(fi);
return 0;
}
fwrite(fileBuf,fileSize,1,fi);
You did read fileSize bytes, but are writing sizeof(...) bytes, that is size of pointer, returned by new.
A C++ way to do it:
#include <fstream>
int main()
{
std::ifstream in("Source.txt");
std::ofstream out("Destination.txt");
out << in.rdbuf();
}
You have swapped the arguments of fread and fwrite. Element size precedes the number of elements. Should be like so:
fread(fileBuf, 1, fileSize, file);
And
fwrite(fileBuf, 1, fileSize, fi);
Also address my comment from above:
Enclose the else clause in { and }. Indentation does not determine blocks in c++. Otherwise your code will crash if you fail to open the file.
EDIT: and the another problem - you have been writing sizeof(fileBuf) bytes which is constant. Instead you should write the exact same number of bytes as you've read. Having in mind the rest of your code you could simply replace sizeof(fileBuf) with fileSize as I've done above.
fileBuf = new BYTE[fileSize];
fread(fileBuf, fileSize, 1, file);
FILE* fi = fopen("C:\\Documents and Settings\\[...]\gcc.txt","wb");
fwrite(fileBuf,sizeof(fileBuf),1,fi);
fileBuf is a pointer to BYTE. You declared it yourself, look: BYTE *fileBuf. And so sizeof(filebuf) is sizeof(BYTE *).
Perhaps you wanted:
fwrite(fileBuf, fileSize, 1, fi);
which closely mirrors the earlier fread call.
I strongly recommend that you capture the return values of I/O functions and check them.
I am trying to constantly read data into a buffer of type unsigned char* from different files. However, I can't seem to set the buffer to NULL prior to reading in the next file.
Here is only the relevant code:
#include <stdio.h>
#include <fstream>
int
main (int argc, char** argv) {
FILE* dataFile = fopen("C:\\File1.txt", "rb");
unsigned char *buffer = NULL;
buffer = (unsigned char*)malloc(1000);
fread(buffer,1,1000,dataFile);
fclose(dataFile);
dataFile = fopen("C:\\File2.txt", "rb");
buffer = NULL;
fread(buffer,1,1000,dataFile);
fclose(dataFile);
system("pause");
return 0;
}
The error I run into is at the second occurrence of this line: fread(buffer,1,1000,dataFile);
The error I get is:
Debug Assertion Failed!
Expression: (buffer != NULL)
It points me to Line 147 of fread.c which is basically:
/* validation */
_VALIDATE_RETURN((buffer != NULL), EINVAL, 0);
if (stream == NULL || num > (SIZE_MAX / elementSize))
{
if (bufferSize != SIZE_MAX)
{
memset(buffer, _BUFFER_FILL_PATTERN, bufferSize);
}
_VALIDATE_RETURN((stream != NULL), EINVAL, 0);
_VALIDATE_RETURN(num <= (SIZE_MAX / elementSize), EINVAL, 0);
}
I did Google for ways to get the buffer pointer to NULL and tried the various suggestions, but none seem to work. Anyone can clarify what is the right way to set it to NULL?
Your buffer is a pointer.
When you do this:
buffer = (unsigned char*)malloc(1000);
you allocate some space in memory, and assign its starting position to buffer. Remember, buffer holds the address of the beginning of the space, that's all. When you do this:
buffer = NULL;
you have thrown away that address.
EDIT:
C++ style, without dynamic memory:
#include <fstream>
using std:: string;
using std:: ifstream;
void readFromFile(string fname)
{
char buffer[1000];
ifstream fin(fname.c_str());
fin.read(buffer, sizeof(buffer));
// maybe do things with the data
}
int main ()
{
readFromFile("File1.txt");
readFromFile("File2.txt");
return 0;
}
There's no need to erase the contents of the buffer. If the cost of allocating and deallocating the buffer with each call is too much, just add static:
static char buffer[1000];
It will be overwritten each time.
You can't say buffer = NULL because fread wil try to dereference it. Dereferencing NULL is one of the things that are certainly and completely illegal in C++. In effect you're losing what you got from malloc. Perhaps you're looking for memset and trying to zero the buffer:
memset(buffer, 0, 1000);
However, you don't need to do this before calling fread. There's simply no reason since fread will write the buffer anyway: it doesn't care if it's zeroed or not.
As a side note: you're writing very C-ish code in what I suspect is C++ (given your fstream header). There are better-suited I/O options for C++.
I got lzo library to use in our application. The version was provided is 1.07.
They have given me .lib along with some header file and some .c source files.
I have setup test environment as per specs. I am able to see lzo routine functions in my application.
Here is my test application
#include "stdafx.h"
#include "lzoconf.h"
#include "lzo1z.h"
#include <stdlib.h>
int _tmain(int argc, _TCHAR* argv[])
{
FILE * pFile;
long lSize;
unsigned char *i_buff;
unsigned char *o_buff;
int i_len,e = 0;
unsigned int o_len;
size_t result;
//data.txt have a single compressed packet
pFile = fopen("data.txt","rb");
if (pFile==NULL)
return -1;
// obtain file size:
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
// allocate memory to contain the whole file:
i_buff = (unsigned char*) malloc (sizeof(char)*lSize);
if (i_buff == NULL)
return -1;
// copy the file into the buffer:
result = fread (i_buff,1,lSize,pFile);
if (result != lSize)
return -1;
i_len = lSize;
o_len = 512;
// allocate memory for output buffer
o_buff = (unsigned char*) malloc(sizeof(char)*o_len);
if (o_buff == NULL)
return -1;
lzo_memset(o_buff,0,o_len);
lzo1z_decompress(i_buff,i_len,o_buff,&o_len,NULL);
return 0;
}
It gives access violation on last line.
lzo1z_decompress(i_buff,i_len,o_buff,&o_len,NULL);
in provided library signature for above functiion is
lzo1z_decompress ( const lzo_byte *src, lzo_uint src_len,
lzo_byte *dst, lzo_uint *dst_len,
lzo_voidp wrkmem /* NOT USED */ );
What is wrong?
Are you sure 512 bytes is big enough for the decompressed data? You shouldn't be using an arbitrary value, but rather you should have stowed away the original size somewhere as a header when your file was compressed:
LZO Decompression Buffer Size
You should probably make your data types match the interface spec (e.g. o_len should be a lzo_uint...you're passing an address so the actual underlying type matters).
Beyond that, it's open source. So why don't you build lzo with debug info and step into it to see where the problem is?
http://www.oberhumer.com/opensource/lzo/
Thans everyone for suggestion and comments.
The problem was with data. I have successfully decomressed it.