I have a project in C++ Builder6. There's an OpenDialog where I upload images to the project. I'd like my project to be safe and because it only accepts .jpg or .bmp images I decided to make a restriction. As far as I'm concerned I can recognize a .jpg file by setting my stream reader to the 4th position. If I find "JFIF" here, It'll be .jpeg file. And so on.
Here's my code
if(OpenDialog1->Execute())
{
TFileStream *stream = new TFileStream(OpenDialog1->FileName, fmOpenRead);
if(stream != NULL)
{
if(stream->Size < 10)
{
delete stream;
return;
}
char str[10];
stream->Read(str, 10);
if(AnsiString(str + 6).SetLength(4)=="JFIF")
{
ShowMessage("It's jpeg");
}
else if ( AnsiString(str).SetLength(2)=="BM") {
ShowMessage("It's bmp");
}
else
{
ShowMessage("It can not be downloaded");
return;
}
}
delete stream;
}
But unfortunately that code raises an exception about JPEG error #41 when I put here a text file with renamed extension.
So my idea doesn't work. The whole question is:
Can I make my program return my error messages without using try-catch method?
By the way, I understand why the exception is being raised, because my jpeg file is empty. But I'd like to handle it using my own system, not the standart exception.
Related
I have a function that allocates a text font on the heap from a filename. It looks like this:
std::unique_ptr<sf::Font> newFont(std::string&& fileName)
{
auto font = std::make_unique<sf::Font>();
if (!font->loadFromFile(fileName))
{
exit(0);
}
return font;
}
Someone on Stack Exchange - Code Review told me that I needed better error messages, since my program just silently exits if the file is not found. But since I'm writing a game, I'm not using a console window for output. I was thinking that maybe I could throw some kind of custom compiler error that triggers when the file is not found. Something like "Unable to allocate font: <font_path>". Is there a way to do this, or should I solve this some other way?
Exceptions are what you are looking for:
std::unique_ptr<sf::Font> newFont(std::string&& fileName) noexcept(false)
{
auto font = std::make_unique<sf::Font>();
if (!font->loadFromFile(fileName))
{
throw std::runtime_error("Unable to allocate font: " + fileName);
}
return font;
}
Now we can print error messages using a try-catch block:
int main() {
std::unique_ptr<sf::Font> font;
try {
font = newFont("myfont.ttf");
} catch ( const std::exception & ex ) {
PRINT_ERROR(ex.what());
return 1;
}
// do something with font ...
}
Normally you could implement PRINT_ERROR by just printing to std::cerr, but since you don't have a console to print to, you will need to do something else with the error message. Options include:
creating a log file and printing errors to the log using std::ofstream
displaying the error messages directly in your game
Years ago I created a C++ function using FILE to create bitmap files. Recently (not sure when or why) this code is now failing when opening the file. The problem is with the open call ...
file_ptr = fopen("ScreenShots/Screenshot1.bmp", "wb");
Currently this results in an error 13, permission denied error. Change the filename extension to something else and the fopen works fine. For example,
file_ptr = fopen("ScreenShots/Screenshot1.bm2", "wb");
The file saves correctly and when changing the extension back to BMP I can display the file correctly in Paintshop.
Did a quick check using ofstream and same problem.
Any ideas why I get a permission denied error when trying to open BMP files to write data? For information I am using Visual Studio Community 2017 on Windows 10.
To give the complete section of code ...
BITMAPFILEHEADER bitmap_header;
BITMAPINFOHEADER bitmap_info;
FILE *file_ptr;
unsigned int count;
unsigned char tempRGB;
char filename[256];
bool finished;
// CREATE A UNIQUE FILENAME
count = 1;
finished = false;
do
{
// CREATE NAME
sprintf(filename, "ScreenShots/Screenshot%d.bmp", count);
// CHECK IF FILE EXISTS
errno = 0;
file_ptr = fopen(filename, "rb");
if (file_ptr)
{
// FILE EXISTS
fclose(file_ptr);
count = count + 1;
}
else
{
// UNIQUE FILENAME
file_ptr = fopen(filename, "wb");
if (file_ptr == NULL)
{
// UNABLE TO OPEN FOR WRITING - GIVE UP
// (USING OWN LOGGING CLASS)
jalog.log("\nERROR on Screenshot >");
jalog.log(filename);
jalog.log("< >");
jalog.log((short)errno);
return;
}
finished = true;
}
}
while (finished == false);
I've managed to find the issue ... Avast antivirus. I noticed that trying to do an open action for a BMP file took a few seconds while opening any other file type (successfully or unsuccessfully) was instantaneous. As something similar happens when running new programs I tried disabling all the Avast shields and I could successfully create a BMP file using the existing code.
For my own personal use I can whitelist my own programs, but annoying if I get to distributing the program to other people.
Thanks for the help ... and sorry for raising a C++ issue that in the end had nothing to do with C++!
How could I use QuaZip to extract a .zip file and show its extraction progress in a QProgressDialog?
I've tried an example from this question1 (and also this question2) without success. Because I need to unzip .zip files (not .gz files) and that code shows % of progress but not unzip the files.
And even that, I don't know how to show that % in a QProgressDialog.
I've been able to extract .zip file using:
JlCompress::extractDir("C:/test/test.zip", "C:/test/");
However, that is not enought for my goal, because I need to show that extraction progress in a QProgressDialog in real time...
This is my code:
QString fileName = "C:/test/firefox-29.0.1.gz"; //I need to unzip .zip files
qDebug() << "Opened";
progressUnzip->setWindowTitle(tr("Unzip Manager"));
progressUnzip->setLabelText(tr("Unzipping %1. \nThis can take a long time to complete").arg(fileName));
progressUnzip->setAttribute(Qt::WA_DeleteOnClose);
QFile file(fileName);
file.open(QFile::ReadOnly);
QuaGzipFile gzip;
gzip.open(file.handle(), QuaGzipFile::ReadOnly);
progressUnzip->show();
while(true) {
QByteArray buf = gzip.read(1000);
//process buf
if (buf.isEmpty()) { break; }
QFile temp_file_object;
temp_file_object.open(file.handle(), QFile::ReadOnly);
double progress = 100.0 * temp_file_object.pos() / file.size();
updateUnzipProgress(temp_file_object.pos(), file.size());
qDebug() << qRound(progress) << "%";
}
unzipFinished();
qDebug() << "Finish";
Where:
void MainWindow::updateUnzipProgress(qint64 bytesRead, qint64 totalBytes)
{
qDebug() << bytesRead << "/" << totalBytes;
qint64 th = 1;
if (totalBytes >= 100000000)
{
th = 1000;
}
progressUnzip->setMaximum(totalBytes/th);
progressUnzip->setValue(bytesRead/th);
}
// When unzip finished or canceled, this will be called
void MainWindow::unzipFinished()
{
qDebug() << "Unzip finished.";
progressUnzip->hide();
}
In this code, QProgressDialog doesn't show any progress bar and at the end the file is not unzipped.
Any idea?
Thanks for your help,
I'm not going to write the whole code for you, but I can give you some hints to help you solve the problem.
QuaZIP library does not provide any Qt signals about the extraction progress, and that means that you should implement it yourself.
First, take a look at JlCompress::extractDir function implementation to see how it works. The source code can be found here. The function creates a QuaZip object which describes the zip archive you want to extract. Then it iterates over the files in the archive. On every iteration it creates a QuaZipFile object which describes a compressed file in the archive and then writes (=extracts) its data to a new file.
This is the copy function:
static bool copyData(QIODevice &inFile, QIODevice &outFile)
{
while (!inFile.atEnd()) {
char buf[4096];
qint64 readLen = inFile.read(buf, 4096);
if (readLen <= 0)
return false;
if (outFile.write(buf, readLen) != readLen)
return false;
}
return true;
}
inFile is the compressed (QuaZipFile) file and outFile is a new file where the compressed data is extracted to.
Now you should understand the underlying logic.
To add signals about extraction progress, you can can copy the JlCompress::extractDir source code to some wrapper class and make some changes.
While iterating over the files in the archive, you can get information about them using QuaZipFile::getFileInfo. That information contains uncompressed file size. Now go back to the copyData function. You know how many bytes you have written and you know the expected file size. That means you can calculate the single file extraction progress. Also you can get total files count and their uncompressed sizes using QuaZip::getFileInfoList64. That will let you calculate the whole extraction progress too.
In a simple application (a skeleton put together with Visual Studio designer) I recently worked around an error that only manifests if I use drag/drop to execute the program.
Problem: I drag and drop a file onto my program. I later use File->SaveAs to save the contents of a rich text box. If I attempt to type a filename or drop down the hierarchy of directory paths, the application instantly quits. If I select a file displayed in the SaveAs dialog, this works fine (after accepting the overwrite).
Workaround: Add a try/catch block above the ShowDialog call in the saveAsToolStripMenuItem_Click function containing an attempt to open and write to a file. A simple fputs will cause the exception, which I then ignore and delete any file created in the process.
If someone knows a simpler (or cleaner!) solution, thanks in advance. Otherwise, here is my ugly solution:
private: System::Void saveAsToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{
static bool fFirstTime = true;
static char *sBogusFileName = "c:\\__$$TrashFileIMustCreateThenDelete";
SaveFileDialog^ dialog = gcnew SaveFileDialog();
{
System::Windows::Forms::DialogResult DR;
dialog->Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
dialog->FilterIndex = 2;
dialog->RestoreDirectory = true;
// dialog->InitialDirectory = "c:\\";
if (fFirstTime)
{
FILE *fp;
// This is a strange problem that came up on my Windows XP machine.
// The first time through this logic, I would get a System.AccessViolationException
// If I do it with this simple fputs, the error is recoverable.
// If it happens during the dialog->ShowDialog that follows, the application quietly exits.
// No event logs, nothing. This solved it for me.
try {
// The fopen that follows make the MS compiler unhappy. The filename is hard-coded, so I don't care.
#pragma warning( suppress: 4996 )
fp=fopen(sBogusFileName, "w");
fputs("A string that might never be actually written - this causes an exception on some machines\n", fp);
}
catch(Exception ^e)
{
(void)e; // Suppress another compiler error (unused variable)
// Debug code that I later removed. This logging is not required to fix the problem.
// RRCLOGB1("\nError attempting to write to a file:\n%s\n\n", e->ToString());
}
finally
{
fclose(fp);
}
remove(sBogusFileName);
fFirstTime = false; // Only cause the exception once...but why is it necessary?!?
}
DR = dialog->ShowDialog(this);
if ( DR == System::Windows::Forms::DialogResult::OK )
{
o
o
o
getting this error in an application written in C++ (VS 2010):
Unhandled exception at 0x77648da9 in divt.exe: 0xC0000005: Access
violation writing location 0x00000014.
it points to this function in free.c:
void __cdecl _free_base (void * pBlock)
{
int retval = 0;
if (pBlock == NULL)
return;
RTCCALLBACK(_RTC_Free_hook, (pBlock, 0));
retval = HeapFree(_crtheap, 0, pBlock);
if (retval == 0) //<-----------------------right here
{
errno = _get_errno_from_oserr(GetLastError());
}
}
Via debugging I was able to determine where its actually crashing:
void MenuState::LoadContentFromFile(char* File,std::string &Content)
{
std::string strbuf;
char buffer[1028];
std::fstream file;
file.open(File,std::ios_base::in);
if(file.fail())
{
Content = ErrorTable->GetString("W0001");
return;
}
if(file.is_open())
{
while(!file.eof())
{
file.getline(buffer,128,'\n'); // <----here
strbuf = buffer;
Content += strbuf + "\n";
}
}
file.close();
strbuf.clear();
}
It crashes on file.getline(buffer,128,'\n');
I don't understand why but it's only doing it in release build (Optimizations turned off), on debug build its working fine.
Any Ideas?
I know this is an old question, but when you encounter these sorts of issues buried deep in files such as, free.c or xmemory, you may also want to double check your project configuration. Especially when the issue pertains to only certain build configurations.
For example, in MSVC check your Project Properties > Configuration Properties > C/C++ > Code Generation > Runtime Library. Make sure it consistent for all dependencies and that it is set to a Debug/Release variant depending on the current build.
I would bet that the read prior to the read crashing the application actually failed (although I'm not quite sure why it would crash). The important thing to note is that eof() is only good for determining what caused a read failure (and typically suppressing an error message). In addition, you always want to check after the read whether it was successful. Finally, I can't see any reason why you don't read an std::string directly. In summary, try to use this loop instead:
for (std::string strbuf; std::getline(file, strbuf); ) {
Content += strbuf;
}
Asked a friend for help, we came up with this Solution:
std::string strbuf;
char buffer[256] = "\0";
FILE* f = fopen(File, "rt");
while(fgets(buffer,sizeof(buffer),f) != NULL)
{
Content += buffer;
}
fclose(f);
strbuf.clear();
Works fine, still thanks for your efforts.