How to pass string object(std::string) using fifo? [duplicate] - c++

I am trying to write a char* to a binary file.
This is what I have now.
void Write(char* fileName, char* pData)
{
ofstream binFile (fileName, ios::out | ios::binary);
if (binFile.open())
{
binFile.write((char*)&pData, sizeof(pData));
binFile.close();
}
}
void Read(char* fileName, char* pData)
{
ifstream binFile(fileName, ios::in | ios::binary);
if(binFile.open())
{
binFile.read(char*)&pData, sizeof(pData));
binFile.close
}
}
int main()
{
char* testData = "ABCdEFG"; // not real data
char* getTestData;
char* file = "C:\\testData.dat";
Write(file, testData);
Read(file, getTestData);
}
Test data will be of unknown length. May not always be the same.
When i run the program once, and write and read. I can get back the test data.
But when i stop the program and run it again, this time without writing. Just reading, i cannot get back the test data.
I don't really understand whats happening here.
Can some one explain it to me?

binFile.write((char*)&pData, sizeof(pData));
is wrong. It just writes the value of the pointer. It does not write the data.
You need to use:
binFile.write(pData, strlen(pData));
However, that won't be adequate to read the data back. To be able to read the data back, you'll need to write the size of the string first.
size_t len = strlen(pData);
binFile.write((char*)&len, sizeof(len));
binFile.write(pData, len);
And when reading the data back, you will need to use:
size_t len = 0;
binFile.read(char*)&len, sizeof(len));
binFile.read(pData, len);
and then, null terminate the string.
pData[len] = '\0';
PS
Make sure getTestData is properly initialized before using it to read the data.
char getTestData[100];
will be adequate for your test case.
Update
You can make your program a bit better by using std::string instead of char*. The size of the saved data can be more easily managed when a std::string is used.
void Write(std::string const& fileName, std::string const& data)
{
std::ofstream binFile(fileName, std::ios::out | std::ios::binary);
if (binFile.is_open())
{
size_t len = data.size();
binFile.write((char*)&len, sizeof(len));
binFile.write((char*)&data[0], len);
// No need. The file will be closed when the function returns.
// binFile.close();
}
}
void Read(std::string const& fileName, std::string& data)
{
std::ifstream binFile(fileName, std::ios::in | std::ios::binary);
if(binFile.is_open())
{
size_t len = 0;
binFile.read((char*)&len, sizeof(len));
data.resize(len);
binFile.read((char*)&data[0], len);
}
}
int main()
{
std::string file = "testData.dat";
std::string testData = "ABCdEFG";
Write(file, testData);
std::string getTestData;
Read(file, getTestData);
std::cout << getTestData << std::endl;
}

Related

Use OpenSSL to encrypt file contents in c++

I am creating an application which encrypts some text and then it writes it to a file.
The problem I am seeing is that when I run the encryption more than once, I am only able to decrypt the text I added firstly.
This is the code:
encrypt and decrypt functions:
std::vector<char> CryptCTR::encrypt(const char* textToEncrypt)
{
size_t sizeToEncrypt = strlen(textToEncrypt);
std::vector< char > encryptedText ( sizeToEncrypt );
unsigned long long lengthProcessed = 0;
do {
auto maxCipherLen = sizeToEncrypt > std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : sizeToEncrypt;
encryptCTR(textToEncrypt,
&encryptedText[lengthProcessed],
maxCipherLen);
lengthProcessed += maxCipherLen;
sizeToEncrypt -= maxCipherLen;
} while (sizeToEncrypt > 0);
return encryptedText;
}
std::vector<char> CryptCTR::decrypt(const char* textToDecrypt/*, SecurityKey& key*/)
{
size_t sizeToDecrypt = strlen(textToDecrypt);
unsigned long long lengthProcessed = 0;
std::vector< char > recoveredText ( sizeToDecrypt );
do
{
int maxPlainLen = sizeToDecrypt > std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : sizeToDecrypt;
decryptCTR(textToDecrypt,
&recoveredText[lengthProcessed],
sizeToDecrypt/*, &key*/);
lengthProcessed += maxPlainLen;
sizeToDecrypt -= maxPlainLen;
} while(sizeToDecrypt > 0);
return recoveredText;
}
void CryptCTR::encryptCTR ( const char* pvBufferIn, char* pvBufferOut, unsigned long dwLength )
{
CRYPTO_ctr128_encrypt(
(const unsigned char*)pvBufferIn,
(unsigned char*)pvBufferOut,
dwLength,
(AES_KEY*)&m_aesSecurityKey.getKey().front(),
state.ivec,
state.ecount,
&state.num,
(block128_f)AES_encrypt);
}
void CryptCTR::decryptCTR ( const char* pvBufferIn, char* pvBufferOut, unsigned long dwLength)
{
CRYPTO_ctr128_encrypt((const unsigned char*)pvBufferIn,
(unsigned char*)pvBufferOut,
dwLength,
(AES_KEY*)&m_aesSecurityKey.getKey().front(),
state.ivec,
state.ecount,
&state.num,
(block128_f)AES_encrypt);
}
If I encrypt decrypt and then decrypt once it works. But the problem starts when I try to do this:
// ENCODING //
{
for (int i=0;i<kStrVector.size();++i)
{
CryptCTR cryptCtr;
//SecurityKey aesExampleKey ( std::vector< char > (1) );
cryptCtr.initializeAesKey(/*&aesExampleKey*/);
const char* textToEncrypt = kStrVector.at(i).c_str();
auto output = cryptCtr.encrypt(textToEncrypt/*, aesExampleKey*/);
std::ofstream out("encoded-append.dat", std::ios::app);
for (const auto &e : output)
out << e;
out.close();
}
}
// DECODING //
{
CryptCTR cryptCtr;
std::ifstream t("encoded-append.dat");
std::stringstream buffer;
buffer << t.rdbuf();
std::string ss = buffer.str();
//SecurityKey aesExampleKey2 ( std::vector< char > (1) );
cryptCtr.initializeAesKey(/*&aesExampleKey2*/);
//initializeAesKey ( (const unsigned char*)CRYPT_AES_KEY, sizeof(CRYPT_AES_KEY) * 8, &aesExmapleKey2 );
auto output = cryptCtr.decrypt(buffer.str().c_str()/*, aesExampleKey2*/);
std::string s2(output.begin(), output.end());
std::ofstream out("decoded-append.dat");
out << s2;
out.close();
}
Then the program is able to decrypt only the text written in the first iteration.
Could you please tell me what I have wrong in my code?
Thanks in advance and regards
Shot in the dark guess, but encryption is typically binary. As such your encrypted output will have null char bytes inside it. So if you treat the encrypted data as a null terminated string, you risk losing data. Hence, your decrypt function should taking in a vector instead of a null terminated string.
Also, don't forget to pass ios_base::binary into the constructor of your ifstream and ofstream constructors for reading/writing to your .dat file. This will be important if you want your code to run reliably on Windows.

C++ DirectX CreateVertexShader COM error

When i try to create my shader with CreateVertexShader(), I get COM error 'The paremeter is incorrect.'.
struct ShaderData
{
LPVOID ShaderCode;
size_t ShaderSize;
};
This function works but it leaks. When delete[] buffer is uncommented I get the error.
Shader::ShaderData Shader::LoadShader(const std::string& file)
{
std::ifstream ifs(file, std::ios::in | std::ios::binary);
if (!ifs) return;
ifs.seekg(0, std::ios::end);
size_t size = static_cast<std::size_t>(ifs.tellg());
ifs.seekg(0, std::ios::beg);
char* buffer = new char[size];
ifs.read(buffer, len);
ShaderData data = { buffer, size };
//delete[] buffer;
return data;
}
Another version of the same function but using std::vector, I still get the same error.
Shader::ShaderData Shader::LoadShader(const std::string& file)
{
std::ifstream ifs(file, std::ios::in | std::ios::binary);
if (!ifs) return;
ifs.seekg(0, std::ios::end);
size_t size = static_cast<std::size_t>(ifs.tellg());
ifs.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
ifs.read(buffer.data(), size);
ShaderData data = { static_cast<void*>(buffer.data()), size };
return data;
}
Function creating the shaders. m_vertex_data and m_pixel_data are both member variables of class Shader, and holds the data returned from LoadShader().
void Shader::CreateShaders(ID3D11Device* device)
{
device->CreateVertexShader(m_vertex_data.ShaderCode,
m_vertex_data.ShaderSize,
nullptr,
m_vertex_shader.GetAddressOf()));
device->CreatePixelShader(m_pixel_data.ShaderCode,
m_pixel_data.ShaderSize,
nullptr,
m_pixel_shader.GetAddressOf()));
}
You need to keep the buffer pointed to by ShaderData::ShaderCode; valid until you create a shader. To avoid leaks just replace it with ::std::vector< char > ShaderCode; so the buffer will be kept safe. Actually you don't need ShaderData struct at all, just return a vector containing shader code.

Writing char* to binary file using ostream::write

I am trying to write a char* to a binary file.
This is what I have now.
void Write(char* fileName, char* pData)
{
ofstream binFile (fileName, ios::out | ios::binary);
if (binFile.open())
{
binFile.write((char*)&pData, sizeof(pData));
binFile.close();
}
}
void Read(char* fileName, char* pData)
{
ifstream binFile(fileName, ios::in | ios::binary);
if(binFile.open())
{
binFile.read(char*)&pData, sizeof(pData));
binFile.close
}
}
int main()
{
char* testData = "ABCdEFG"; // not real data
char* getTestData;
char* file = "C:\\testData.dat";
Write(file, testData);
Read(file, getTestData);
}
Test data will be of unknown length. May not always be the same.
When i run the program once, and write and read. I can get back the test data.
But when i stop the program and run it again, this time without writing. Just reading, i cannot get back the test data.
I don't really understand whats happening here.
Can some one explain it to me?
binFile.write((char*)&pData, sizeof(pData));
is wrong. It just writes the value of the pointer. It does not write the data.
You need to use:
binFile.write(pData, strlen(pData));
However, that won't be adequate to read the data back. To be able to read the data back, you'll need to write the size of the string first.
size_t len = strlen(pData);
binFile.write((char*)&len, sizeof(len));
binFile.write(pData, len);
And when reading the data back, you will need to use:
size_t len = 0;
binFile.read(char*)&len, sizeof(len));
binFile.read(pData, len);
and then, null terminate the string.
pData[len] = '\0';
PS
Make sure getTestData is properly initialized before using it to read the data.
char getTestData[100];
will be adequate for your test case.
Update
You can make your program a bit better by using std::string instead of char*. The size of the saved data can be more easily managed when a std::string is used.
void Write(std::string const& fileName, std::string const& data)
{
std::ofstream binFile(fileName, std::ios::out | std::ios::binary);
if (binFile.is_open())
{
size_t len = data.size();
binFile.write((char*)&len, sizeof(len));
binFile.write((char*)&data[0], len);
// No need. The file will be closed when the function returns.
// binFile.close();
}
}
void Read(std::string const& fileName, std::string& data)
{
std::ifstream binFile(fileName, std::ios::in | std::ios::binary);
if(binFile.is_open())
{
size_t len = 0;
binFile.read((char*)&len, sizeof(len));
data.resize(len);
binFile.read((char*)&data[0], len);
}
}
int main()
{
std::string file = "testData.dat";
std::string testData = "ABCdEFG";
Write(file, testData);
std::string getTestData;
Read(file, getTestData);
std::cout << getTestData << std::endl;
}

Read data from Buffer

How can i access the data from a buffer?
int WINAPI mRecv( SOCKET s, char *buf, int len, int flags ) {
// Code to access the data from buffer
}
You are probably looking for std::istream::read. It is used to extract characters from stream.
And if you want to iterate over the data then you can use the std::istreambuf_iterator
std::string
getBufferContent(const std::string& path)
{
std::ifstream file(path);
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
return content;
}

C++: Store read binary file into buffer

I'm trying to read a binary file and store it in a buffer. The problem is, that in the binary file are multiple null-terminated characters, but they are not at the end, instead they are before other binary text, so if I store the text after the '\0' it just deletes it in the buffer.
Example:
char * a = "this is a\0 test";
cout << a;
This will just output: this is a
here's my real code:
this function reads one character
bool CStream::Read (int * _OutChar)
{
if (!bInitialized)
return false;
int iReturn = 0;
*_OutChar = fgetc (pFile);
if (*_OutChar == EOF)
return false;
return true;
}
And this is how I use it:
char * SendData = new char[4096 + 1];
for (i = 0; i < 4096; i++)
{
if (Stream.Read (&iChar))
SendData[i] = iChar;
else
break;
}
I just want to mention that there is a standard way to read from a binary file into a buffer.
Using <cstdio>:
char buffer[BUFFERSIZE];
FILE * filp = fopen("filename.bin", "rb");
int bytes_read = fread(buffer, sizeof(char), BUFFERSIZE, filp);
Using <fstream>:
std::ifstream fin("filename.bin", ios::in | ios::binary );
fin.read(buffer, BUFFERSIZE);
What you do with the buffer afterwards is all up to you of course.
Edit: Full example using <cstdio>
#include <cstdio>
const int BUFFERSIZE = 4096;
int main() {
const char * fname = "filename.bin";
FILE* filp = fopen(fname, "rb" );
if (!filp) { printf("Error: could not open file %s\n", fname); return -1; }
char * buffer = new char[BUFFERSIZE];
while ( (int bytes = fread(buffer, sizeof(char), BUFFERSIZE, filp)) > 0 ) {
// Do something with the bytes, first elements of buffer.
// For example, reversing the data and forget about it afterwards!
for (char *beg = buffer, *end=buffer + bytes; beg < end; beg++, end-- ) {
swap(*beg, *end);
}
}
// Done and close.
fclose(filp);
return 0;
}
static std::vector<unsigned char> read_binary_file (const std::string filename)
{
// binary mode is only for switching off newline translation
std::ifstream file(filename, std::ios::binary);
file.unsetf(std::ios::skipws);
std::streampos file_size;
file.seekg(0, std::ios::end);
file_size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<unsigned char> vec;
vec.reserve(file_size);
vec.insert(vec.begin(),
std::istream_iterator<unsigned char>(file),
std::istream_iterator<unsigned char>());
return (vec);
}
and then
auto vec = read_binary_file(filename);
auto src = (char*) new char[vec.size()];
std::copy(vec.begin(), vec.end(), src);
The problem is definitievely the writing of your buffer, because you read a byte at a time.
If you know the length of the data in your buffer, you could force cout to go on:
char *bf = "Hello\0 world";
cout << bf << endl;
cout << string(bf, 12) << endl;
This should give the following output:
Hello
Hello world
However this is a workaround, as cout is foreseent to output printable data. Be aware that the output of non printable chars such as '\0' is system dependent.
Alternative solutions:
But if you manipulate binary data, you should define ad-hoc data structures and printing. Here some hints, with a quick draft for the general principles:
struct Mybuff { // special strtucture to manage buffers of binary data
static const int maxsz = 512;
int size;
char buffer[maxsz];
void set(char *src, int sz) // binary copy of data of a given length
{ size = sz; memcpy(buffer, src, max(sz, maxsz)); }
} ;
Then you could overload the output operator function:
ostream& operator<< (ostream& os, Mybuff &b)
{
for (int i = 0; i < b.size; i++)
os.put(isprint(b.buffer[i]) ? b.buffer[i]:'*'); // non printables replaced with *
return os;
}
ANd you could use it like this:
char *bf = "Hello\0 world";
Mybuff my;
my.set(bf, 13); // physical copy of memory
cout << my << endl; // special output
I believe your problem is not in reading the data, but rather in how you try to print it.
char * a = "this is a\0 test";
cout << a;
This example you show us prints a C-string. Since C-string is a sequence of chars ended by '\0', the printing function stops at the first null char.
This is because you need to know where the string ends either by using special terminating character (like '\0' here) or knowing its length.
So, to print whole data, you must know the length of it and use a loop similar to the one you use for reading it.
Are you on Windows? If so you need to execute _setmode(_fileno(stdout), _O_BINARY);
Include <fcntl.h> and <io.h>