If I read special characters from a file and then try to compare them (like with an if) it doesn't recognize them.
std::wstring c;
std::wifstream file;
file.open("test.txt");
while (file)
{
wchar_t tmp = file.get();
c += tmp;
}
file.close();
size_t l = c.length();
for (int i = 0; i < l; i++)
{
wchar_t a = c[i];
if (a == L'ä') {
std::cout << "if triggered.";
}
}
But when I create a wchar and predefine a special character it does work.
wchar_t a = L'ä';
if (a == L'ä') {
std::cout << "if triggered";
}
and if I put the wstring that was loaded from the file, in the file I get the text back. Nothing weird happens there.
This depends on the kind of file encoding.
I would implicitly say that, in this case, UTF-8.
The code below may be work fine:
std::string str;
{
std::ifstream file;
file.open("D:/test.txt");
file >> str;
}
wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
wstring wstr = myconv.from_bytes(str);
size_t l = wstr.length();
for (int i = 0; i < l; i++)
{
auto a = wstr[i];
if (a == L'ä') {
std::cout << "if triggered.";
}
}
However, std::codecvt_utf8 is deprecated in C++17
For the cases using higher C++17:
By MSVC++
I recommend using CString, it's too easy and worked on every almost version of C++, follow this:
std::string str;
{
std::ifstream file;
file.open("D:/test.txt");
file >> str;
}
CString wstr = (CString)CA2W(str.c_str(), CP_UTF8);
size_t l = wstr.GetLength();
for (int i = 0; i < l; i++)
{
auto a = wstr[i];
if (a == L'ä') {
std::cout << "if triggered.";
}
}
#include <atlstr.h> for non-MFC
Related
i have been working on this project for a week and i cant find the solution to my problems.
i'm making an encryptor which can encrypt/decrypt binary file(like .exe, .jpg etc).
i am able to correctly get the data from the binary file using vector.
but i cannot correctly encrypt/decrypt the data from the vector.
some code:
if (encryptFile)
{
Crypt crypt;
//TOencryptfile.open(writeFile, ios::binary | ios::out);
vector<char> buffer((istreambuf_iterator<char>(encryptFile)),(istreambuf_iterator<char>()));
cout << buffer.size() << endl;
_getch();
for (std::vector<char>::iterator i = buffer.begin(); i != buffer.end(); ++i) {
// encryption that fails
temp = crypt.getKeyFromString(&*i , key, strlen(&*i));
}
TOencryptfile.close();
encryptFile.close();
}
and the function getKeyFromString:
KEYCRYPT Crypt::getKeyFromString(KEYCRYPT text, KEYCHAR charkey, keylength length) {
int string_size = std::strlen(text);
KEYCRYPT textcrypt = new char[string_size + 1];
std::strcpy(textcrypt, text);
int key = strlen(charkey);
for (int i = 0; i < length; i++) {
if (strlen(text) != 0) {
textcrypt[i] = text[i] ^ charkey[i % (sizeof(charkey) / sizeof(char))];
//keylvl += text[i] ^ (int(charkey) + i) % key;
//keyfnl += keylvl[i] ^ (int(charkey) - i) * key;
}
}
return textcrypt;
}
and at last the types:
typedef char* KEYCRYPT;
typedef int KEY;
typedef char* KEYCHAR;
typedef int keylength;
does anybody know a good way to encrypt *i?
because my way does not work, it does not return the same when calling the function again with getKeyFromString(temp, key, strlen(temp))
well, according to the response of #Barmar:
#waterlight Put the file contents into a string and pass that to the crypto API.
i managed to fix the problem.
all i had to do was:
stringstream result;
std::copy(buffer.begin(), buffer.end(), std::ostream_iterator<char>(result, " "));
string now = result.str();
and everything worked.
thanks to everybody who replied!!
I'm trying to read an array object (Array is a class I've made using read and write functions to read and write from binary files. So far the write functions works but it won't read from the file properly for some reason. This is the write function :
void writeToBinFile(const char* path) const
{
ofstream ofs(path, ios_base::out | ios_base::app | ios_base::binary);
if (ofs.is_open())
{
ostringstream oss;
for (unsigned int i = 0; i < m_size; i++)
{
oss << ' ';
oss << m_data[i];
}
ofs.write(oss.str().c_str(), oss.str().size());
}
}
This is the read function :
void readFromBinFile(const char* path)
{
ifstream ifs(path, ios_base::in | ios_base::binary || ios_base::ate);
if (ifs.is_open())
{
stringstream ss;
int charCount = 0, spaceCount = 0;
ifs.unget();
while (spaceCount != m_size)
{
charCount++;
if (ifs.peek() == ' ')
{
spaceCount++;
}
ifs.unget();
}
ifs.get();
char* ch = new char[sizeof(char) * charCount];
ifs.read(ch, sizeof(char) * charCount);
ss << ch;
delete[] ch;
for (unsigned int i = 0; i < m_size; i++)
{
ss >> m_data[i];
m_elementCount++;
}
}
}
those are the class fields :
T* m_data;
unsigned int m_size;
unsigned int m_elementCount;
I'm using the following code to write and then read (1 execution for reading another for writing):
Array<int> arr3(5);
//arr3[0] = 38;
//arr3[1] = 22;
//arr3[2] = 55;
//arr3[3] = 7;
//arr3[4] = 94;
//arr3.writeToBinFile("binfile.bin");
arr3.readFromBinFile("binfile.bin");
for (unsigned int i = 0; i < arr3.elementCount(); i++)
{
cout << "arr3[" << i << "] = " << arr3[i] << endl;
}
The problem is now at the readFromBinFile function, it get stuck in an infinite loop and peek() returns -1 for some reason and I can't figure why.
Also note I'm writing to the binary file using spaces to make a barrier between each element so I would know to differentiate between objects in the array and also a space at the start of the writing to make a barrier between previous stored binary data in the file to the array binary data.
The major problem, in my mind, is that you write fixed-size binary data in variable-size textual form. It could be so much simpler if you just stick to pure binary form.
Instead of writing to a string stream and then writing that output to the actual file, just write the binary data directly to the file:
ofs.write(reinterpret_cast<char*>(m_data), sizeof(m_data[0]) * m_size);
Then do something similar when reading the data.
For this to work, you of course need to save the number of entries in the array/vector first before writing the actual data.
So the actual write function could be as simple as
void writeToBinFile(const char* path) const
{
ofstream ofs(path, ios_base::out | ios_base::binary);
if (ofs)
{
ofs.write(reinterpret_cast<const char*>(&m_size), sizeof(m_size));
ofs.write(reinterpret_cast<const char*>(&m_data[0]), sizeof(m_data[0]) * m_size);
}
}
And the read function
void readFromBinFile(const char* path)
{
ifstream ifs(path, ios_base::in | ios_base::binary);
if (ifs)
{
// Read the size
ifs.read(reinterpret_cast<char*>(&m_size), sizeof(m_size));
// Read all the data
ifs.read(reinterpret_cast<char*>(&m_data[0]), sizeof(m_data[0]) * m_size);
}
}
Depending on how you define m_data you might need to allocate memory for it before reading the actual data.
Oh, and if you want to append data at the end of the array (but why would you, in the current code you show, you rewrite the whole array anyway) you write the size at the beginning, seek to the end, and then write the new data.
I have one array like this:
static WCHAR FilesToShow[][100] = { { L"start.cmd" },{ L"image.xml" }, { L"xyz" }};
as you see that there is "xyz" which I have to replace with some unique name. For this I have to read image.xml file.
Please can you tell me how can I do this.
I wrote a method like this:
PRIVATE WCHAR GetSystemName(WCHAR *pName)
{
WCHAR line;
wfstream in("image.xml");
WCHAR tmp;
bool begin_tag = false;
while (getline(in,line))
{
// strip whitespaces from the beginning
for (int i = 0; i < line.length(); i++)
{
if (line[i] == ' ' && tmp.size() == 0)
{
}
else
{
tmp += line[i];
}
}
if (wcswcs(tmp,"<SystemPath>") != NULL)
{
???????? how to get "vikash" from here <SystemPath>C:\Users\rs_user\Documents\RobotStudio\Systems\vikash</SystemPath>
}
else
{
continue;
}
}
return tmp;
}
I'm getting exception for wfstream, getline and line.length() method.
I have included fstream.h header file but I think It's not supported in COM.
Please help me how to solve this issue without parsing xml file.
If your xml-file is simple enough so that there is only a single tag with given name, you could do it like this:
#include <string>
#include <sstream>
#include <iostream>
std::wstring get_value(std::wistream & in, std::wstring const & tagname)
{
std::wstring text = std::wstring(std::istreambuf_iterator<std::wstring::value_type>(in),
std::istreambuf_iterator<std::wstring::value_type>());
std::wstring start_tag = L"<" + tagname + L">";
std::wstring end_tag = L"</" + tagname + L">";
std::wstring::size_type start = text.find(start_tag);
if (start == std::wstring::npos)
{
throw 123;
}
start += start_tag.length();
std::wstring::size_type end = text.find(end_tag);
if (end == std::wstring::npos)
{
throw 123;
}
return text.substr(start, end - start);
}
std::wstring get_substr_after(std::wstring const & str, wchar_t delim)
{
std::wstring::size_type pos = str.rfind(delim);
if (pos == std::wstring::npos)
{
throw 123;
}
return str.substr(pos + 1);
}
void stackoverflow()
{
std::wstring text(L"<foo>\n<bar>abc/def/ghi</bar>\n<baz>123/456/789</baz>\n</foo>\n");
std::wistringstream wiss(text);
std::wcout << text << std::endl;
std::wcout << get_substr_after(get_value(wiss, std::wstring(L"bar")), L'/') << std::endl;
}
The output of this program is:
<foo>
<bar>abc/def/ghi</bar>
<baz>123/456/789</baz>
</foo>
ghi
I hope that answered your question.
you have several issues here.
what you are getting are compiler errors and not exceptions
the header file to include is 'fstream' not 'fstream.h'.
make sure you have a line saying using namespace std;
You are declaring line as a variable of type WCHAR, so it is a single wide character, which surely is not a wstring object. Therefore line.length() is incorrect.
Why are you mixing C (wcswcs()) and C++ (STL) ? maybe you should re-design your function signature.
However, try the below function. I have modified the signature to return a pointer to WCHAR, and place the requested string in the buffer space provided by pName. I added a check to verify that the buffer is large enough to fit the name and the terminating NULL character.
WCHAR* GetSystemName(WCHAR *pName, size_t buflen)
{
wstring line;
wifstream in("image.xml");
WCHAR* tmp = NULL;
while (getline(in,line))
{
// strip whitespaces from the beginning
size_t beg_non_whitespace = line.find_first_not_of(L" \t");
if (beg_non_whitespace != wstring::npos)
{
line = line.substr( beg_non_whitespace );
}
size_t beg_system_path = line.find( L"<SystemPath>" );
if ( beg_system_path != wstring::npos )
{
// strip the tags (assuming closing tag is present)
size_t beg_data = beg_system_path + wstring( L"<SystemPath>" ).length();
size_t range = line.find( L"</SystemPath>" ) - beg_data;
line = line.substr( beg_data, range );
// get file name
size_t pos_last_backslash = line.find_last_of( L'\\' );
if ( pos_last_backslash != wstring::npos )
{
line = line.substr( pos_last_backslash + 1 );
if ( buflen <= line.length() )
{
// ERROR: pName buffer is not large enough to fit the string + terminating NULL character.
return NULL;
}
wcscpy( pName, line.c_str() );
tmp = pName;
break;
}
}
}
return tmp;
}
EDIT: Moreover, if you are using and/or parsing XML in other areas of your program, I strongly suggest using an XML parsing library such as Xerces-C or libXml2.
Thank you all for your answer. Here I got solution of my question.
PRIVATE WCHAR* GetNewSystemName()
{
WCHAR line[756];
WCHAR tempBuffer[100];
CComBSTR path = CurrentFolder.Path();
CComBSTR imagePath1 = L"rimageinfo.xml";
path.AppendBSTR(imagePath1);
std::wfstream in(path);
WCHAR tmp[756];
in.getline(line, 756);
WCHAR* buffer;
buffer = wcswcs(line, L"<SystemPath>");
WCHAR *dest = wcsstr(buffer, L"</SystemPath>");
int pos;
pos = dest - buffer;
unsigned int i = 0;
if (wcswcs(buffer,L"<SystemPath>") != NULL && wcswcs(buffer,L"</SystemPath>") != NULL)
{
for (; i < pos; i++)
{
if (buffer[i] == ' ' && sizeof(tmp) == 0)
{
}
else
{
tmp[i] = buffer[i];
}
}
tmp[i] = NULL;
//break;
}
int j = i;
for (; j > 0; j--)
{
if (tmp[j] == '\\')
{
break;
}
}
j++;
int k = 0;
for (; j < i ; j++)
{
System_Name[k] = tmp[j];
k++;
}
System_Name[k] = NULL;
return System_Name;
I have a text file that contains keys and values like this:
keyOne=1
keyTwo=734
keyThree=22.3
keyFour=5
The keys are just lower-case and upper-case letters like in my example. The values are either integers or floats. Each key and value is separated by an equals sign (=). Now I want to read the values into variables I have in my program.
This is the code I have tried to read the values:
(I omitted the part where I store the values in my program's variables, and just print them out now for demonstration.)
std::fstream file(optionsFile, std::fstream::in);
if (file.good()) {
int begin;
int end;
std::string line;
while(std::getline(file, line)) {
// find the position of the value in the line
for (unsigned int i = 0; i < line.length(); i++) {
if (line.at(i) == '=') {
begin = i + 1;
end = line.length();
break;
}
}
// build the string... it starts at <begin> and ends at <end>
const char *string = "";
for (int i = begin; i < end; i++) {
string += line.at(i);
}
// only gibberish is printed in the following line :(
std::cout << "string=" << string << std::endl;
}
}
I don't understand why it won't print the value.. instead only weird stuff or even nothing is printed
Please help this broke my spirit so hard :(
You are using C-style strings (char arrays) without properly allocated memory, and you are just manipulating with the pointer, so you are not appending characters into your string:
// build the string... it starts at <begin> and ends at <end>
const char *string = "";
for (int i = begin; i < end; i++) {
string += line.at(i);
}
Use std::string instead:
/// build the string... it starts at <begin> and ends at <end>
std::string str;
for (int i = begin; i < end; i++) {
str += line.at(i);
}
Or allocate memory by hand, use the proper indexing, terminate the string with '\0' character and don't forget to delete the string after you don't need it anymore:
char *string = new char[end - begin + 1];
int j = 0;
for (int i = begin; i < end; i++) {
string[j++] = line.at(i);
}
// Don't forget to end the string!
string[j] = '\0';
// Don't forget to delete string afterwards!
delete [] string;
So, just use std::string.
Edit Why did you mix C strings and std::string in the first place?
As was already mentioned, native string types in c/c++ do not support straightforward concatenation since they are essentially pointers to some preallocated memory. You should always use std::string when a string is supposed to be mutable.
Btw, think about the following refactoring:
void process_option (const std::string& a_key, const std::string& a_value)
{
std::cout << a_key << " <-- " << a_value << std::endl;
}
void read_options (std::istream& a_in, const char* a_source)
{
int line_n = 0;
std::string line;
while (std::getline(a_in, line))
{
++ line_n;
std::string::size_type p = line. find('=');
if (p == line. npos)
{
// invalid_entry(a_source, line_n);
continue;
}
process_option(
line. substr(0, p), // key
line. substr(p + 1, line. find_first_of("\t\r\n", p + 1)) // value
);
}
}
void read_options (const char* a_filename)
{
std::ifstream file(a_filename);
if (! file)
{
// read_error(a_filename);
return;
}
read_options(file, a_filename);
file. close();
}
void read_options (const std::string& a_filename)
{
read_options(a_filename. c_str());
}
I have to implement the LZW algorithm but I have found some trouble with the decoding part.
I think the code is right because it works with a example I've found somewhere on the web: if I initialize my dictionary as follows
m_dictionary.push_back("a");
m_dictionary.push_back("b");
m_dictionary.push_back("d");
m_dictionary.push_back("n");
m_dictionary.push_back("_");
and my input file has the string banana_bandana, I get the following results:
compressed.txt: 1036045328
decompressed.txt:banana_bandana
But if I initialize the dictionary with all the 255 ASCII characters, the decoding process fails miserably. I think the problem rests in the number of bits used on the codes because when I'm going to decode, I always read from the input file char by char (8 bits) instead the correct number of bits, I guess.
Below is the code of my implementation of this algorithm:
template <class T>
size_t toUnsigned(T t) {
std::stringstream stream;
stream << t;
size_t x;
stream >> x;
return x;
}
bool LempelZivWelch::isInDictionary(const std::string& entry) {
return (std::find(m_dictionary.begin(), m_dictionary.end(), entry) != m_dictionary.end());
}
void LempelZivWelch::initializeDictionary() {
m_dictionary.clear();
for (int i = 0; i < 256; ++i)
m_dictionary.push_back(std::string(1, char(i)));
}
void LempelZivWelch::addEntry(std::string entry) {
m_dictionary.push_back(entry);
}
size_t LempelZivWelch::encode(char *data, size_t dataSize) {
initializeDictionary();
std::string s;
char c;
std::ofstream file;
file.open("compressed.txt", std::ios::out | std::ios::binary);
for (size_t i = 0; i < dataSize; ++i) {
c = data[i];
if(isInDictionary(s + c))
s = s + c;
else {
for (size_t j = 0; j < m_dictionary.size(); ++j)
if (m_dictionary[j] == s) {
file << j;
break;
}
addEntry(s + c);
s = c;
}
}
for (size_t j = 0; j < m_dictionary.size(); ++j)
if (m_dictionary[j] == s) {
file << j;
break;
}
file.close();
return dataSize;
}
size_t LempelZivWelch::decode(char *data, size_t dataSize) {
initializeDictionary();
std::string entry;
char c;
size_t previousCode, currentCode;
std::ofstream file;
file.open("decompressed.txt", std::ios::out | std::ios::binary);
previousCode = toUnsigned(data[0]);
file << m_dictionary[previousCode];
for (size_t i = 1; i < dataSize; ++i) {
currentCode = toUnsigned(data[i]);
entry = m_dictionary[currentCode];
file << entry;
c = entry[0];
addEntry(m_dictionary[previousCode] + c);
previousCode = currentCode;
}
file.close();
return dataSize;
}
And this is the function that reads the input files:
void Compression::readFile(std::string filename) {
std::ifstream file;
file.open(filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if (!file.is_open())
exit(EXIT_FAILURE);
m_dataSize = file.tellg();
m_data = new char [m_dataSize];
file.seekg(0, std::ios::beg);
file.read(m_data, m_dataSize);
file.close();
}
My guess is the decoding problem resides in reading the input file as a array of chars and/or writing to the compressed file the chars as size_t.
Thanks in advance!
It looks like you are outputting the dictionary indices as ASCII encoded numbers. How are you going to tell the sequence 1,2,3 from 12,3 or 1,23.
You need to encode the data in an unambiguous way using either 9-bit (10, 11 or whatever) numbers or some sort of prefix-free code like huffman coding.