Possible to change file extension via c++ stream facilities? - c++

I was wondering if there is a way to change a file extension via any c++ facilities.
Example: .txt to .xyz

The extension is just part of the filename, and to change it you simply have to rename the file. For that you have two choices, the POSIX compliant rename function in the CRT, or the WIN32 function MoveFile (and its variants).

the Rename function is actually performed directly on a file
int main ()
{
int result =1;
char oldname[] ="oldname.txt";
char newname[] ="newname.docx";
FILE* fp = fopen(oldname , "r+" );
bool exists = (fp != NULL);
if (exists)
{
fclose(fp);
result= rename( oldname , newname );
}
if ( result == 0 )
puts ( "File successfully renamed" );
else
perror( "Error renaming file" );
return 0;
}

Related

Move files to Trash/Recycle Bin in Qt

Is there a Qt function to move files to Recycle Bin instead of truly deleting them, for OSes that support it, or do I need to use OS-specific code?
Since Qt 5.15.0 Alpha, this method has been added, which should be what you were looking for.
bool QFile::moveToTrash()
The corresponding code changes can be found here.
(This issue is old and the corresponding Bugreport at https://bugreports.qt.io/browse/QTBUG-47703 has already been posted, but I currently lack the reputation to comment, and found this to be a useful information.)
Qt doesnt provide a MoveToTrash. Here's a part of my code
for Windows
#ifdef Q_OS_WIN32
#include "windows.h"
void MoveToTrashImpl( QString file ){
QFileInfo fileinfo( file );
if( !fileinfo.exists() )
throw OdtCore::Exception( "File doesnt exists, cant move to trash" );
WCHAR from[ MAX_PATH ];
memset( from, 0, sizeof( from ));
int l = fileinfo.absoluteFilePath().toWCharArray( from );
Q_ASSERT( 0 <= l && l < MAX_PATH );
from[ l ] = '\0';
SHFILEOPSTRUCT fileop;
memset( &fileop, 0, sizeof( fileop ) );
fileop.wFunc = FO_DELETE;
fileop.pFrom = from;
fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
int rv = SHFileOperation( &fileop );
if( 0 != rv ){
qDebug() << rv << QString::number( rv ).toInt( 0, 8 );
throw OdtCore::Exception( "move to trash failed" );
}
}
#endif
and for Linux
#ifdef Q_OS_LINUX
bool TrashInitialized = false;
QString TrashPath;
QString TrashPathInfo;
QString TrashPathFiles;
void MoveToTrashImpl( QString file ){
#ifdef QT_GUI_LIB
if( !TrashInitialized ){
QStringList paths;
const char* xdg_data_home = getenv( "XDG_DATA_HOME" );
if( xdg_data_home ){
qDebug() << "XDG_DATA_HOME not yet tested";
QString xdgTrash( xdg_data_home );
paths.append( xdgTrash + "/Trash" );
}
QString home = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
paths.append( home + "/.local/share/Trash" );
paths.append( home + "/.trash" );
foreach( QString path, paths ){
if( TrashPath.isEmpty() ){
QDir dir( path );
if( dir.exists() ){
TrashPath = path;
}
}
}
if( TrashPath.isEmpty() )
throw Exception( "Cant detect trash folder" );
TrashPathInfo = TrashPath + "/info";
TrashPathFiles = TrashPath + "/files";
if( !QDir( TrashPathInfo ).exists() || !QDir( TrashPathFiles ).exists() )
throw Exception( "Trash doesnt looks like FreeDesktop.org Trash specification" );
TrashInitialized = true;
}
QFileInfo original( file );
if( !original.exists() )
throw Exception( "File doesnt exists, cant move to trash" );
QString info;
info += "[Trash Info]\nPath=";
info += original.absoluteFilePath();
info += "\nDeletionDate=";
info += QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss.zzzZ");
info += "\n";
QString trashname = original.fileName();
QString infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
QString filepath = TrashPathFiles + "/" + trashname;
int nr = 1;
while( QFileInfo( infopath ).exists() || QFileInfo( filepath ).exists() ){
nr++;
trashname = original.baseName() + "." + QString::number( nr );
if( !original.completeSuffix().isEmpty() ){
trashname += QString( "." ) + original.completeSuffix();
}
infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
filepath = TrashPathFiles + "/" + trashname;
}
QDir dir;
if( !dir.rename( original.absoluteFilePath(), filepath ) ){
throw Exception( "move to trash failed" );
}
File infofile;
infofile.createUtf8( infopath, info );
#else
Q_UNUSED( file );
throw Exception( "Trash in server-mode not supported" );
#endif
}
#endif
There is no API yet.
https://bugreports.qt.io/browse/QTBUG-181
The issue is closed and the fix version is: Some future release
Edit: A new issue has been opened at https://bugreports.qt.io/browse/QTBUG-47703.
Edit Apparently it is now done in 5.15.0 Alpha bool QFile::moveToTrash()
I think that there is no cross-platform way. Simple moving files to "trash" location will not give effect, because user may switch off this possibility.
Maybe, this url will help: http://www.hardcoded.net/articles/send-files-to-trash-on-all-platforms.htm
I'm relatively certain that there is no Qt API that wraps this for all supported platforms. That means, unfortunately, that you will have to write platform-specific code.
I don't know anything about where/how Linux distributions store deleted files, and I imagine that it probably varies depending on which file manager you're using. I believe that moving files to a ~/.Trash folder is the standard way of doing it, but I'm not sure if this is reliable. For example, in the case of files stored on external volumes.
Things are a bit easier on Mac OS X, where there is a supported API to do this: FSMoveObjectToTrashSync, provided by Core Services. At least, that's how I remember you're supposed to do it. The documentation claims that this method is now deprecated in OS X 10.8. I have no idea what the recommended alternative is.
As a Windows programmer, I think that platform is much easier. :-) The basic solution is to call the SHFileOperation function:
#include <Windows.h> // general Windows header file
#include <ShellAPI.h> // for shell functions, like SHFileOperation
#include <string> // (or use QString)
void RecycleFileOnWindows()
{
std::wstring path = L"C:\\Users\\Administrator\\Documents\\deleteme.txt";
path.append(1, L'\0'); // path string must be double nul-terminated
SHFILEOPSTRUCT shfos = {};
shfos.hwnd = nullptr; // handle to window that will own generated windows, if applicable
shfos.wFunc = FO_DELETE;
shfos.pFrom = path.c_str();
shfos.pTo = nullptr; // not used for deletion operations
shfos.fFlags = FOF_ALLOWUNDO; // use the recycle bin
const int retVal = SHFileOperation(&shfos);
if (retVal != 0)
{
// The operation failed...
if (shfos.fAnyOperationsAborted)
{
// ...but that's because the user canceled.
MessageBox(nullptr, L"Operation was canceled", nullptr, MB_OK | MB_ICONINFORMATION);
}
else
{
// ...for one of the other reasons given in the documentation.
MessageBox(nullptr, L"Operation failed", nullptr, MB_OK | MB_ICONERROR);
}
}
}
There are also flags that you can set to customize confirmation, error reporting, and other behavior. The linked documentation contains all the details you need to build upon this basic example.
On Windows Vista and later, the SHFileOperation function has been superseded by the methods provided by the IFileOperation interface. If you're targeting only these later versions of Windows, you should prefer to use this interface. Otherwise, SHFileOperation will continue to work fine.
if(QSysInfo::kernelType()=="linux")
{
QDateTime currentTime(QDateTime::currentDateTime()); // save System time
QString trashFilePath=QDir::homePath()+"/.local/share/Trash/files/"; // trash file path contain delete files
QString trashInfoPath=QDir::homePath()+"/.local/share/Trash/info/"; // trash info path contain delete files information
// create file format for trash info file----- START
QFile infoFile(trashInfoPath+FileName.completeBaseName()+"."+FileName.completeSuffix()+".trashinfo"); //filename+extension+.trashinfo // create file information file in /.local/share/Trash/info/ folder
infoFile.open(QIODevice::ReadWrite);
QTextStream stream(&infoFile); // for write data on open file
stream<<"[Trash Info]"<<endl;
stream<<"Path="+QString(QUrl::toPercentEncoding(FileName.absoluteFilePath(),"~_-./"))<<endl; // convert path string in percentage decoding scheme string
stream<<"DeletionDate="+currentTime.toString("yyyy-MM-dd")+"T"+currentTime.toString("hh:mm:ss")<<endl; // get date and time format YYYY-MM-DDThh:mm:ss
infoFile.close();
// create info file format of trash file----- END
QDir file;
file.rename(FileName.absoluteFilePath(),trashFilePath+FileName.completeBaseName()+"."+FileName.completeSuffix()); // rename(file old path, file trash path)
}
Trash files in linux exist /home/user_name/.local/share/Trash/files/ directory but it also require info file for each trash file which exist in /home/user_name/.local/share/Trash/info/ directory. when we want to move file into trash, actually move file into /home/user_name/.local/share/Trash/files/ directory and create info file in /home/user_name/.local/share/Trash/info/ directory. inside .trashinfo format use percentage decoding scheme for set file path where file existed, info file also contain time and date of deletion.

Simple way to unzip a .zip file using zlib [duplicate]

This question already has answers here:
Unzip a zip file using zlib
(4 answers)
Closed 7 years ago.
Is there a simple example of how to unzip a .zip file and extract the files to a directory? I am currently using zlib, and while I understand that zlib does not directly deal with zip files, there seems to be several additional things in zlibs's "contrib" library. I noticed and read about "minizip", and after reading some documents and looking at some of the code, I do not see a simple example of how to unzip a .zip file and extract the files to a directory.
I would like to find a platform independent way of doing so, but if that is not possible then I need to find a way for windows and mac.
zlib handles the deflate compression/decompression algorithm, but there is more than that in a ZIP file.
You can try libzip. It is free, portable and easy to use.
UPDATE: Here I attach quick'n'dirty example of libzip, with all the error controls ommited:
#include <zip.h>
int main()
{
//Open the ZIP archive
int err = 0;
zip *z = zip_open("foo.zip", 0, &err);
//Search for the file of given name
const char *name = "file.txt";
struct zip_stat st;
zip_stat_init(&st);
zip_stat(z, name, 0, &st);
//Alloc memory for its uncompressed contents
char *contents = new char[st.size];
//Read the compressed file
zip_file *f = zip_fopen(z, name, 0);
zip_fread(f, contents, st.size);
zip_fclose(f);
//And close the archive
zip_close(z);
//Do something with the contents
//delete allocated memory
delete[] contents;
}
Minizip does have an example programs to demonstrate its usage - the files are called minizip.c and miniunz.c.
Update: I had a few minutes so I whipped up this quick, bare bones example for you. It's very smelly C, and I wouldn't use it without major improvements. Hopefully it's enough to get you going for now.
// uzip.c - Simple example of using the minizip API.
// Do not use this code as is! It is educational only, and probably
// riddled with errors and leaks!
#include <stdio.h>
#include <string.h>
#include "unzip.h"
#define dir_delimter '/'
#define MAX_FILENAME 512
#define READ_SIZE 8192
int main( int argc, char **argv )
{
if ( argc < 2 )
{
printf( "usage:\n%s {file to unzip}\n", argv[ 0 ] );
return -1;
}
// Open the zip file
unzFile *zipfile = unzOpen( argv[ 1 ] );
if ( zipfile == NULL )
{
printf( "%s: not found\n" );
return -1;
}
// Get info about the zip file
unz_global_info global_info;
if ( unzGetGlobalInfo( zipfile, &global_info ) != UNZ_OK )
{
printf( "could not read file global info\n" );
unzClose( zipfile );
return -1;
}
// Buffer to hold data read from the zip file.
char read_buffer[ READ_SIZE ];
// Loop to extract all files
uLong i;
for ( i = 0; i < global_info.number_entry; ++i )
{
// Get info about current file.
unz_file_info file_info;
char filename[ MAX_FILENAME ];
if ( unzGetCurrentFileInfo(
zipfile,
&file_info,
filename,
MAX_FILENAME,
NULL, 0, NULL, 0 ) != UNZ_OK )
{
printf( "could not read file info\n" );
unzClose( zipfile );
return -1;
}
// Check if this entry is a directory or file.
const size_t filename_length = strlen( filename );
if ( filename[ filename_length-1 ] == dir_delimter )
{
// Entry is a directory, so create it.
printf( "dir:%s\n", filename );
mkdir( filename );
}
else
{
// Entry is a file, so extract it.
printf( "file:%s\n", filename );
if ( unzOpenCurrentFile( zipfile ) != UNZ_OK )
{
printf( "could not open file\n" );
unzClose( zipfile );
return -1;
}
// Open a file to write out the data.
FILE *out = fopen( filename, "wb" );
if ( out == NULL )
{
printf( "could not open destination file\n" );
unzCloseCurrentFile( zipfile );
unzClose( zipfile );
return -1;
}
int error = UNZ_OK;
do
{
error = unzReadCurrentFile( zipfile, read_buffer, READ_SIZE );
if ( error < 0 )
{
printf( "error %d\n", error );
unzCloseCurrentFile( zipfile );
unzClose( zipfile );
return -1;
}
// Write data to file.
if ( error > 0 )
{
fwrite( read_buffer, error, 1, out ); // You should check return of fwrite...
}
} while ( error > 0 );
fclose( out );
}
unzCloseCurrentFile( zipfile );
// Go the the next entry listed in the zip file.
if ( ( i+1 ) < global_info.number_entry )
{
if ( unzGoToNextFile( zipfile ) != UNZ_OK )
{
printf( "cound not read next file\n" );
unzClose( zipfile );
return -1;
}
}
}
unzClose( zipfile );
return 0;
}
I built and tested it with MinGW/MSYS on Windows like this:
contrib/minizip/$ gcc -I../.. -o unzip uzip.c unzip.c ioapi.c ../../libz.a
contrib/minizip/$ ./unzip.exe /j/zlib-125.zip

C++ write to front of file

I need to open a file as ofstream and write to the front of the file, while preserving
the remaining contents of the file, which will be "moved". Similar to "prepend"
a file.
Is this possible using the STL or boost ?
No -- the language (or library) doesn't really make much difference here. Most file systems just don't allow it, full stop.
The usual way to get the same effect is to write your new data to a new file, then copy the data in the old file to the new file following the data you wrote.
No it isn't. And this has been asked here many times before. If you want to do this you have to create new file, write the "prepend" data to it, then open the existing file and copy its contents to the new file.
A new iostream class can wrap that functionality. This assumes your prepend data isn't too large to comfortably fit in memory. Use it like a regular ofstream.
#include <fstream>
#include <sstream>
#include <vector>
class prepend_ofstream
: public std::ostringstream {
std::filebuf file;
public:
prepend_ofstream() {}
prepend_ofstream( char const *name, openmode mode = out ) {
open( name, mode );
}
~prepend_ofstream() {
if ( is_open() ) close();
}
void open( char const *name, openmode mode ) {
if ( ! file.open( name, mode & binary | in | out ) ) {
setstate( failbit );
}
}
bool is_open() { return file.is_open(); }
void close() {
if ( ! is_open() ) {
setstate( failbit );
return;
}
char *strbuf = &str()[0];
std::vector<char> buf( str().size() );
int rdsz;
do {
rdsz = file.sgetn( &buf[0], buf.size() );
file.pubseekoff( -rdsz, cur );
file.sputn( strbuf, buf.size() );
file.pubseekoff( 0, cur ); // "update the output sequence"
std::copy( &buf[0], &buf[0]+rdsz, strbuf );
} while ( rdsz == buf.size() );
file.sputn( &buf[0], rdsz );
if ( ! file.close() ) {
setstate( failbit );
}
}
};
Typically features are added through new stream buffer classes, not actual streams, but in this case the new functionality is in close, which is unfortunately not virtual.

Starting a program fails with error code 1

I made an application and a dll, which are working this way:
I have to register the dll. After registering the dll if i right click on an .exe file, the pop-up menu appears, and i have inserted into this menu one line ("Start MyApp"), and if i click there, it should start MyApp. MyApp has one parameter which is the full path of the selected .exe file. After starting MyApp with this path it should create a process with CreateProcessWithLogonW(). This application reads the username, password and the domain from an .ini file. My problem is, that after MyApp starts, it fails always, because it can't find the ini file. Errorcode is: 1 (Incorrect function).
If i start MyApp manually, than it works fine.
Does anyone has any idea why is this, and how could i fix this problem?
Thanks in advance!
kampi
Update1:
Here is the code which reads from the ini file.
int main ( int argc, char *argv[] )
{
int i, slash = 0, j;
char application[size];
wchar_t wuser[65], wdomain[33], wpass[129];
memset( user, 0, sizeof ( user ) );
memset( password, 0, sizeof ( password ) );
memset( domain, 0, sizeof ( domain ) );
file_exists( "RunAs.ini" );
readfile( "RunAs.ini" );
....
....
....
}
void file_exists( const char * filename )
{
if (FILE * file = fopen(filename, "r"))
{
fclose(file);
}
else
{
printf("\nCan't find %s!\n",filename);
getch();
exit(1);
}
}//file_exists
void readfile( char * filename )
{
FILE *inifile;
char tmp[256], buf[256], what[128];
int i, j;
inifile = fopen( "RunAs.ini", "r" );
while ( fgets(tmp, sizeof tmp, inifile) != NULL )
{
if ( tmp[ strlen(tmp) - 1 ] == '\n' )
{
tmp[ strlen(tmp) - 1 ] = '\0';
}//if
memset ( buf, 0, sizeof( buf ) );
for ( i = 0; tmp[i]!= '='; i++ )
{
buf[i] = tmp[i];
}
buf[i] = '\0';
i++;
// memset ( what, 0, sizeof( what ) );
SecureZeroMemory( what, sizeof(what) * 128 );
for ( j = 0; i != strlen(tmp); i++ )
{
what[j] = tmp[i];
j++;
}
what[j] = '\0';
upcase( buf );
removespace( what );
if ( strcmp( buf, "USERNAME" ) == 0 )
{
strcpy( user, what );
}
if ( strcmp( buf, "PASSWORD" ) == 0 )
{
strcpy( password, what );
}
if ( strcmp( buf, "DOMAIN" ) == 0 )
{
strcpy( domain, what );
}
}//while
fclose (inifile);
}//readfile
As others have said, your problem is here:
file_exists( "RunAs.ini" );
readfile( "RunAs.ini" );
Neither of the function calls provides a path. You're expecting the current working directory to be the folder where your application is located, but it doesn't have to be (in fact, you should never assume that it is). The context menu isn't setting the working directory first.
Your safest bet is to retrieve the path to your folder using the path provided in argv[] (the 0th element is the fully qualified path and name of the application itself, and you can extract the path from that). You'll then have exact knowledge of where the file is located, and can append the name of the ini file to that path.
I suspect you're looking for the ini file in the wrong folder. I would try changing the ini file name in the application to the fully qualified name of the ini file. (i.e from "foo.ini" to "c:\\temp\\foo.ini")
(Please note that I've doubled the backslashes because without this, the single backslash may change the meaning of the next character or the backslash may be ignored.)
Are you providing an absolute path or a relative path? Your CWD may be different on startup.
When starting your application directly, the current path is the path that your application is installed to.
However, when starting it from that context menu, the current path is something else.
There are two ways to resolve this. First, don't use an ini file. Instead, store your information to the registry. That way you don't care where the program is started from.
Alternatively, your app will have to locate the directory where it was actually installed, then load the ini file from there.
Obviously the first choice is the easiest path.
Have you checked whether file path for the ini is valid ?

how to capture result from system() in C/C++ [duplicate]

This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
How can I run an external program from C and parse its output?
Hi,
Could someone please tell us how to capture a result when executing system() function ?
Actually I wrote a c++ program that displays the machine's IP address, called "ipdisp" and I want when a sever program executes this ipdisp program, the server captes the display IP address. So, is this possible? if yes, how?
thanks for your replies
Yes, you can do this but you can't use system(), you'll have to use popen() instead. Something like:
FILE *f = popen("ipdisp", "r");
while (!feof(f)) {
// ... read lines from f using regular stdio functions
}
pclose(f);
Greg is not entirely correct. You can use system, but it's a really bad idea. You can use system by writing the output of the command to a temporary file and then reading the file...but popen() is a much better approach. For example:
#include <stdlib.h>
#include <stdio.h>
void
die( char *msg ) {
perror( msg );
exit( EXIT_FAILURE );
}
int
main( void )
{
size_t len;
FILE *f;
int c;
char *buf;
char *cmd = "echo foo";
char *path = "/tmp/output"; /* Should really use mkstemp() */
len = (size_t) snprintf( buf, 0, "%s > %s", cmd, path ) + 1;
buf = malloc( len );
if( buf == NULL ) die( "malloc");
snprintf( buf, len, "%s > %s", cmd, path );
if( system( buf )) die( buf );
f = fopen( path, "r" );
if( f == NULL ) die( path );
printf( "output of command: %s\n", buf );
while(( c = getc( f )) != EOF )
fputc( c, stdout );
return EXIT_SUCCESS;
}
There are lots of problems with this approach...(portability of the syntax for redirection, leaving the file on the filesystem, security issues with other processes reading the temporary file, etc, etc.)