I have methods which returns unicode texts and i need to write them into file but some characters are not written. I have the following:
const wchar_t* getStandardText() {
return L"test";
}
const wchar_t* getUnicodeText()
{
return L"testíček";
}
int main()
{
FILE *file = fopen(FILE_NAME, "a");
fputws(getStandardText(), file);
fputws(getUnicodeText(), file);
fclose(file);
}
Output in file:
testtestí
Much more confusing for me is that some characters like "í" works and others like "č" not.
I am on Windows with VS 2015 Pro.
For reading of file i use Notepad++ which tells me the file has ANSI encoding.
This works on Windows... Change your mode parameter to have an explicit encoding...
FILE *file = fopen("foobar.txt", "a+, ccs=UTF-16LE");
OR
FILE *file = fopen("foobar.txt", "a+, ccs=UTF-8");
That appears to force the byte-order-marks (FF FE) onto the file header to indicate the file's text is Unicode.
The file has to be created with appropriate BOM. Following is the most preferred way, and make sure you're dumping only UTF-8 characters to the file. And open through notepad++ to view it.
FILE *file = fopen("test.txt", "a+, ccs=UTF-8");
Related
I working on the creation of a game. I want to hide all my .tga files.
I concatenate the string content of all my files on a single file in order to make it illisible for players.
I want my program to load a picture by creating a temporaly .tga file from
the saved content.
So that, I'm trying to copy a .tga file from the content of an original one.
More precisely, I read a .tga file as a text and a write it.
Eventhough Notepad++ finds original file and new file as identical, the new file can not be open as .tga file. Windows detects the size of files with 1 byte offset.
Can you explain me what I'm doing wrong ?
Or may be suggest me a better way to hide my files.
Regards
More precisely, I read a .tga file as a text and a write it
Herein may lie your problem: You have to read and write the .tga file as a binary file. Otherwise, any occurence of the byte sequence 0x0D 0x0A (CR LF, Windows line ending) may be replaced with a single 0x0A (LF, Unix line ending) or vice versa, or 0x1A (DOS end of file) may be stripped or appended. Depending on the code you are using, you may also end up stripping any 0x00 (NUL) bytes.
I tried to read / write with my program (c++) a .tga file as binary file but the generated file was still corrupted. The code is below.
std::string name = "my_picture.tga";
std::ifstream FileIn(name, std::ios_base::binary);
std::vector<char> listChar;
bool stopp = false;
if (FileIn) {
while (!(stopp))
{
char xin;
FileIn.read(reinterpret_cast<char*>(&xin), sizeof(char));
listChar.push_back(xin);
if (FileIn.eof()) stopp = true;
}
FileIn.close();
}
std::ofstream FileOut(".\\test.tga", std::ios_base::binary);
bool isCarierReturn = false;
for (char xout : listChar) {
isCarierReturn = xout == '\r';
if (!isCarierReturn) FileOut.write(reinterpret_cast<const char*>(&xout), sizeof(char));
}
FileOut.close();
I compared the original file and the new one on a hexadecimal reader and files are effectively different.
The difference between original and new file consists in a mismatch on lines ending, instead of just having 0x0A ('\n') on the original file, the new file had the byte sequence 0x0D 0x0A ('\r' and '\n'). On some other pictures the generated file was incomplete, the break is always before a 0x1A value (as said #Christoph Lipka).
I manage to write the right sequence by testing if the char is a carrier return, the char is not written on this case and only the byte 0x0D is skipped, see below :
std::ofstream FileOut(".\\test.tga", std::ios_base::binary);
bool isCarrierReturn = false;
char xout_p1 = '\0';
if (listChar.size() >= 1) xout_p1 = listChar.at(0);
for (unsigned i(0); i < listChar.size(); i++) {
char xout = xout_p1;
if (i < listChar.size() - 1) xout_p1 = listChar.at(i + 1);
else xout_p1 = '\0';
isCarrierReturn = xout == '\r' && xout_p1 == '\n';
if (!isCarrierReturn) FileOut.write(reinterpret_cast<const char*>(&xout), sizeof(char));
}
FileOut.close();
The incomplete file reading is solved by reading the file as binary file.
It works.
I need to modify code written in c++. The code opens a file authfile and writes 49 bytes to it. In case the file already exists, I need to make sure the existing data will be overwritten.
The original code first deleted the file and then created a new file. For reasons beyond this discussion, I cannot delete the file, I only need to make sure it is empty, before i write new data to it.
Below is the function that writes the data. How can I modify it, so thatexisting content of the file will be overwritten ?
I suppose, I need to tchange the options of popen
bool Util::add_mcookie(const std::string &mcookie, const char *display,
const std::string &xauth_cmd, const std::string &authfile)
{
FILE *fp;
std::string cmd = xauth_cmd + " -f " + authfile + " -q";
fp = popen(cmd.c_str(), "w");
if (!fp)
return false;
fprintf(fp, "remove %s\n", display);
fprintf(fp, "add %s %s %s\n", display, ".", mcookie.c_str());
fprintf(fp, "exit\n");
pclose(fp);
return true;
}
Change popen to fopen and pclose to fclose. popen / pclose is for opening / closing a process. Also, it looks like you're creating the process with flags. You just need to give fopen the file path
I have been unable to open the file. The fb.is_Open() never returns true. Only when I hard code the data source in the fb.open() it works.
I've tried converting it to a string, char, and wstring with no effect.
What am I missing? The correct code would be fantastic but also and explanation.
Trying to open a file with the data source variable:
wchar_t dataSource[2048];
DWORD errNum = GetModuleFileName(NULL, dataSource, sizeof(dataSource)); //get current dir.
ifstream fb;
wcscat_s(dataSource, L".confg"); //adds ".config" to get full data Sournce
fb.open(dataSource, ios::in);
if (fb.is_open())
{
//get information
}
fb.close();
Here are some things Ive tried that have not worked:
wstring x = dataSource;
x.c_str()
char* cnvFileLoc = (char*)malloc(2048);
size_t count;
count = wcstombs_s(&count, cnvFileLoc, 2048, dataSource, 2048);
what does work is:
fb.open(X:\CPP.Lessons\PluralSight\PluralSight.Fundamentals\Debug\PluralSight.Fundamentals.exe.config, ios::in)
Your call to GetModuleFileName() is wrong. The last parameter is expressed in characters, not in bytes, and the return value tells how many characters were copied:
wchar_t dataSource[2048];
if (GetModuleFileName(NULL, dataSource, 2048) > 0)
{
...
}
Or:
wchar_t dataSource[2048];
if (GetModuleFileName(NULL, dataSource, sizeof(dataSource)/sizeof(dataSource[0])) > 0)
{
...
}
Or:
wchar_t dataSource[2048];
if (GetModuleFileName(NULL, dataSource, _countof(dataSource)) > 0)
{
...
}
Or:
wchar_t dataSource[2048];
if (GetModuleFileName(NULL, dataSource, ARRAYSIZE(dataSource)) > 0)
{
...
}
That being said, you are appending .confg to the end of the full filename. So, if your application is named myapp.exe, you are trying to open myapp.exe.confg. Is that what you really want?
If yes, then make sure the .confg file actually exists, and that your app has permission to access it. CreateFile() would offer much more useful error info then ifstream does.
Otherwise, assuming the .confg file is at least in the same folder as your app, you would have to manually remove the filename portion from the buffer and then substitute in the correct filename. Have a look at PathRemoveFileSpec() and PathCombine() for that. Or, if the file is named myapp.confg, look at PathRenameExtension().
Update: I just noticed that your code is appending .confg, but your comment says .config instead:
//wcscat_s(dataSource, L".confg");
wcscat_s(dataSource, L".config");
You may have mistyped the file extension: L".confg" instead of L".config" as stated by the comment in your code.
I have a string that may or may not have unicode characters in it, I am trying to write that to a file on windows. Below I have posted a sample bit of code, my problem is that when I fopen and read the values back out windows, they are all being interpreted as UTF-16 characters.
char* x = "Fool";
FILE* outFile = fopen( "Serialize.pef", "w+,ccs=UTF-8");
fwrite(x,strlen(x),1,outFile);
fclose(outFile);
char buffer[12];
buffer[11]=NULL;
outFile = fopen( "Serialize.pef", "r,ccs=UTF-8");
fread(buffer,1,12,outFile);
fclose(outFile);
The characters are also interpreted as UTF-16 if I open the file in wordpad etc. What am I doing wrong?
Yes, when you specify that the text file should be encoded in UTF-8, the CRT implicitly assumes that you'll be writing Unicode text to the file. Not doing so doesn't make sense, you wouldn't need UTF-8. This will work proper:
wchar_t* x = L"Fool";
FILE* outFile = fopen( "Serialize.txt", "w+,ccs=UTF-8");
fwrite(x, wcslen(x) * sizeof(wchar_t), 1, outFile);
fclose(outFile);
Or:
char* x = "Fool";
FILE* outFile = fopen( "Serialize.txt", "w+,ccs=UTF-8");
fwprintf(outFile, L"%hs", x);
fclose(outFile);
It is easy if you use the C++11 standard (because there are a lot of additional includes like "utf8" which solves this problems forever).
But if you want to use multi-platform code with older standards, you can use this method to write with streams:
Read the article about UTF converter for streams
Add stxutif.h to your project from sources above
Open the file in ANSI mode and add the BOM to the start of a file, like this:
std::ofstream fs;
fs.open(filepath, std::ios::out|std::ios::binary);
unsigned char smarker[3];
smarker[0] = 0xEF;
smarker[1] = 0xBB;
smarker[2] = 0xBF;
fs << smarker;
fs.close();
Then open the file as UTF and write your content there:
std::wofstream fs;
fs.open(filepath, std::ios::out|std::ios::app);
std::locale utf8_locale(std::locale(), new utf8cvt<false>);
fs.imbue(utf8_locale);
fs << .. // Write anything you want...
I'm trying to find a way to replace all instances of a string token in a file with another string.
How can I do this in C++ with the win32 API?
In other languages this is an easy thing to do, but in C++ I am just lost.
EDIT: For some context, this is for a WiX custom action. So portability is not a main priority, just the most simplest solution.
If the file fits in memory – it's simpler. Call OpenFile() to open file, GetFileSize() to determine file size, allocate enough memory, call ReadFile() to read file, then CloseFile. Do replacement in memory (use strstr() or similar function), then again OpenFile(), WriteFile(), CloseFile().
If the file is large - create a temporary file and read the source file in chunks and write filtered text to the temporary file, then call DeleteFile() to delete the original file and MoveFile() to move the filtered file.
You could use the Boost.Regex Library which should resemble most of the functionality you find on other platforms.
It would work like this:
In this example you’ll find how you can replace a string matching a pattern.
#include <boost/regex.hpp>
#include <string>
int main()
{
boost::regex pattern ("b.lug",boost::regex_constants::icase|boost::regex_constants::perl);
std::string stringa ("Searching for bolug");
std::string replace ("BgLug");
std::string newString;
newString = boost::regex_replace (stringa, pattern, replace);
printf("The new string is: |%s|\n",newString.c_str());
return 0;
}
but you would have of course to add the file reading/writing.
As per sharptooth's solution, I knocked up some C code to do a find and replace on a file. I used stdio calls (strlen, strstr, strcpy and strcat) to do the string manipulation (rather than win32 calls), so your only dependancy is the C run time.
This is certainly not code I would use in a production system. I would use stuff from toolkit string manipulation libraries to make this much cleaner (and not so much with the fixed length buffers). I probably wouldn't use boost, I don't like the overhead. But I figured you might like an example with just the basics (N.B. This writes the altered buffers out to .temp).
#include <stdio.h>
#define BUF_LEN 2048
int findAndReplace (const char * file, const char * find, const char * replace)
{
int replaceCount = 0;
FILE * f = fopen (file, "rt");
if (strstr(replace, find))
return 0; // replacing blah with stuff_blah_stuff
unsigned int findLen = strlen (find);
char tempFile [BUF_LEN];
strcpy (tempFile, file);
strcat (tempFile, ".temp");
FILE * writeF = fopen (tempFile, "wt");
if (!f || !writeF)
return 0;
printf ("Processing %s - %s to %s\n", file, find, replace);
char lineBuf [BUF_LEN];
memset (lineBuf, 0, BUF_LEN);
char tempLineBuf [BUF_LEN];
memset (tempLineBuf, 0, BUF_LEN);
// read each line of the file
while (fgets (lineBuf, BUF_LEN, f))
{
// get the position of find in the line buffer
char * pos = strstr (lineBuf, find);
while (pos)
{
strncpy (tempLineBuf, lineBuf, pos - lineBuf);
strcat (tempLineBuf, replace);
strcat (tempLineBuf, pos + findLen);
replaceCount++;
// replace the current buf with the replaced buffer
strncpy (lineBuf, tempLineBuf, BUF_LEN);
memset (tempLineBuf, 0, BUF_LEN);
pos = strstr (lineBuf, find);
}
printf ("writing new line %s\n", lineBuf);
fputs (lineBuf, writeF);
}
fclose (f);
fclose (writeF);
return replaceCount;
}
int main ()
{
printf ("Made %d replacements\n", findAndReplace ("blah.txt", "marker", "testing_blah"));
}
Why do you have to use the Win32 API? It's easy enough using straight C++, I wouldn't confuse the issue by adding artificial constraints. Just open your input file, open an output file, and read a line from your input. While you haven't hit EOF in your input file, use a regex to look for your token. If you find it, then replace it with your text. Write the line to the output file. Read another line from the input. When you get EOF on the input, close it. Be sure any pending output gets flushed from the output buffer. Close the output file. Done.