2010-01-23 19:44:49 +00:00
/**********************************************************************
2010-07-06 21:39:08 +00:00
Audacity : A Digital Audio Editor
Audacity ( R ) is copyright ( c ) 1999 - 2010 Audacity Team .
License : GPL v2 . See License . txt .
2010-01-23 19:44:49 +00:00
2010-07-06 21:39:08 +00:00
AutoRecovery . cpp
2010-01-23 19:44:49 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /**
\ class AutoRecoveryDialog
2014-06-03 20:30:19 +00:00
\ brief The AutoRecoveryDialog prompts the user whether to
2010-01-23 19:44:49 +00:00
recover previous Audacity projects that were closed incorrectly .
*/ /********************************************************************/
# include "AutoRecovery.h"
# include "Audacity.h"
# include "AudacityApp.h"
# include "FileNames.h"
# include "blockfile/SimpleBlockFile.h"
# include <wx/wxprec.h>
# include <wx/filefn.h>
# include <wx/dir.h>
# include <wx/dialog.h>
# include <wx/app.h>
enum {
ID_RECOVER_ALL = 10000 ,
ID_RECOVER_NONE ,
ID_QUIT_AUDACITY ,
ID_FILE_LIST
} ;
class AutoRecoveryDialog : public wxDialog
{
public :
AutoRecoveryDialog ( wxWindow * parent ) ;
private :
void PopulateList ( ) ;
void PopulateOrExchange ( ShuttleGui & S ) ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
void OnQuitAudacity ( wxCommandEvent & evt ) ;
void OnRecoverNone ( wxCommandEvent & evt ) ;
void OnRecoverAll ( wxCommandEvent & evt ) ;
wxListCtrl * mFileList ;
public :
DECLARE_EVENT_TABLE ( )
} ;
AutoRecoveryDialog : : AutoRecoveryDialog ( wxWindow * parent ) :
wxDialog ( parent , - 1 , _ ( " Automatic Crash Recovery " ) ,
wxDefaultPosition , wxDefaultSize ,
wxDEFAULT_DIALOG_STYLE & ( ~ wxCLOSE_BOX ) ) // no close box
{
ShuttleGui S ( this , eIsCreating ) ;
PopulateOrExchange ( S ) ;
}
BEGIN_EVENT_TABLE ( AutoRecoveryDialog , wxDialog )
EVT_BUTTON ( ID_RECOVER_ALL , AutoRecoveryDialog : : OnRecoverAll )
EVT_BUTTON ( ID_RECOVER_NONE , AutoRecoveryDialog : : OnRecoverNone )
EVT_BUTTON ( ID_QUIT_AUDACITY , AutoRecoveryDialog : : OnQuitAudacity )
END_EVENT_TABLE ( )
void AutoRecoveryDialog : : PopulateOrExchange ( ShuttleGui & S )
{
S . SetBorder ( 5 ) ;
S . StartVerticalLay ( ) ;
{
2014-08-01 20:06:55 +00:00
S . AddVariableText ( _ ( " Some projects were not saved properly the last time Audacity was run. \n Fortunately, the following projects can be automatically recovered: " ) , false ) ;
2010-01-23 19:44:49 +00:00
S . StartStatic ( _ ( " Recoverable projects " ) ) ;
2014-06-03 20:30:19 +00:00
{
2010-01-23 19:44:49 +00:00
mFileList = S . Id ( ID_FILE_LIST ) . AddListControlReportMode ( ) ;
2012-03-20 15:36:02 +00:00
/*i18n-hint: (noun). It's the name of the project to recover.*/
2010-01-23 19:44:49 +00:00
mFileList - > InsertColumn ( 0 , _ ( " Name " ) ) ;
mFileList - > SetColumnWidth ( 0 , 220 ) ;
PopulateList ( ) ;
}
S . EndStatic ( ) ;
2014-08-01 20:06:55 +00:00
S . AddVariableText ( _ ( " After recovery, save the project to save the changes to disk. " ) , false ) ;
2010-01-23 19:44:49 +00:00
S . StartHorizontalLay ( true ) ;
{
S . Id ( ID_QUIT_AUDACITY ) . AddButton ( _ ( " Quit Audacity " ) ) ;
2014-08-01 20:06:55 +00:00
S . Id ( ID_RECOVER_NONE ) . AddButton ( _ ( " Discard Projects " ) ) ;
2010-01-23 19:44:49 +00:00
S . Id ( ID_RECOVER_ALL ) . AddButton ( _ ( " Recover Projects " ) ) ;
}
S . EndHorizontalLay ( ) ;
}
S . EndVerticalLay ( ) ;
Layout ( ) ;
Fit ( ) ;
SetMinSize ( GetSize ( ) ) ;
Center ( ) ;
}
void AutoRecoveryDialog : : PopulateList ( )
{
mFileList - > DeleteAllItems ( ) ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
wxDir dir ( FileNames : : AutoSaveDir ( ) ) ;
if ( ! dir . IsOpened ( ) )
return ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
wxString filename ;
int i = 0 ;
for ( bool c = dir . GetFirst ( & filename , wxT ( " *.autosave " ) , wxDIR_FILES ) ;
c ; c = dir . GetNext ( & filename ) )
mFileList - > InsertItem ( i + + , wxFileName ( filename ) . GetName ( ) ) ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
mFileList - > SetColumnWidth ( 0 , wxLIST_AUTOSIZE ) ;
}
2013-08-25 21:51:26 +00:00
void AutoRecoveryDialog : : OnQuitAudacity ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
EndModal ( ID_QUIT_AUDACITY ) ;
}
2013-08-25 21:51:26 +00:00
void AutoRecoveryDialog : : OnRecoverNone ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
int ret = wxMessageBox (
2014-08-01 20:06:55 +00:00
_ ( " Are you sure you want to discard all projects? \n \n Choosing \" Yes \" discards all projects immediately. " ) ,
_ ( " Confirm Discard Projects " ) , wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT , this ) ;
2010-01-23 19:44:49 +00:00
if ( ret = = wxYES )
EndModal ( ID_RECOVER_NONE ) ;
}
2013-08-25 21:51:26 +00:00
void AutoRecoveryDialog : : OnRecoverAll ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
EndModal ( ID_RECOVER_ALL ) ;
}
////////////////////////////////////////////////////////////////////////////
static bool HaveFilesToRecover ( )
{
wxDir dir ( FileNames : : AutoSaveDir ( ) ) ;
if ( ! dir . IsOpened ( ) )
{
2010-07-06 21:39:08 +00:00
wxMessageBox ( _ ( " Could not enumerate files in auto save directory. " ) ,
2010-01-23 19:44:49 +00:00
_ ( " Error " ) , wxICON_STOP ) ;
return false ;
}
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
wxString filename ;
bool c = dir . GetFirst ( & filename , wxT ( " *.autosave " ) , wxDIR_FILES ) ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
return c ;
}
static bool RemoveAllAutoSaveFiles ( )
{
wxArrayString files ;
wxDir : : GetAllFiles ( FileNames : : AutoSaveDir ( ) , & files ,
wxT ( " *.autosave " ) , wxDIR_FILES ) ;
for ( unsigned int i = 0 ; i < files . GetCount ( ) ; i + + )
{
if ( ! wxRemoveFile ( files [ i ] ) )
{
// I don't think this error message is actually useful.
// -dmazzoni
//wxMessageBox(wxT("Could not remove auto save file: " + files[i]),
// _("Error"), wxICON_STOP);
return false ;
}
}
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
return true ;
}
static bool RecoverAllProjects ( AudacityProject * * pproj )
{
wxDir dir ( FileNames : : AutoSaveDir ( ) ) ;
if ( ! dir . IsOpened ( ) )
{
2010-07-06 21:39:08 +00:00
wxMessageBox ( _ ( " Could not enumerate files in auto save directory. " ) ,
2010-01-23 19:44:49 +00:00
_ ( " Error " ) , wxICON_STOP ) ;
return false ;
}
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
// Open a project window for each auto save file
wxString filename ;
AudacityProject * proj = NULL ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
wxArrayString files ;
wxDir : : GetAllFiles ( FileNames : : AutoSaveDir ( ) , & files ,
wxT ( " *.autosave " ) , wxDIR_FILES ) ;
for ( unsigned int i = 0 ; i < files . GetCount ( ) ; i + + )
{
if ( * pproj )
{
// Reuse existing project window
proj = * pproj ;
* pproj = NULL ;
} else
{
// Create new project window
proj = CreateNewAudacityProject ( ) ;
}
// Open project. When an auto-save file has been opened successfully,
// the opened auto-save file is automatically deleted and a new one
// is created.
proj - > OpenFile ( files [ i ] , false ) ;
}
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
return true ;
}
bool ShowAutoRecoveryDialogIfNeeded ( AudacityProject * * pproj ,
bool * didRecoverAnything )
{
2012-02-08 05:09:14 +00:00
if ( didRecoverAnything )
* didRecoverAnything = false ;
2010-01-23 19:44:49 +00:00
if ( HaveFilesToRecover ( ) )
{
AutoRecoveryDialog dlg ( * pproj ) ;
int ret = dlg . ShowModal ( ) ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
switch ( ret )
{
case ID_RECOVER_NONE :
return RemoveAllAutoSaveFiles ( ) ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
case ID_RECOVER_ALL :
if ( didRecoverAnything )
* didRecoverAnything = true ;
return RecoverAllProjects ( pproj ) ;
default :
// This includes ID_QUIT_AUDACITY
return false ;
}
} else
{
// Nothing to recover, move along
return true ;
}
}
////////////////////////////////////////////////////////////////////////////
/// Recording recovery handler
RecordingRecoveryHandler : : RecordingRecoveryHandler ( AudacityProject * proj )
{
mProject = proj ;
mChannel = - 1 ;
mNumChannels = - 1 ;
}
bool RecordingRecoveryHandler : : HandleXMLTag ( const wxChar * tag ,
const wxChar * * attrs )
{
if ( wxStrcmp ( tag , wxT ( " simpleblockfile " ) ) = = 0 )
{
// Check if we have a valid channel and numchannels
if ( mChannel < 0 | | mNumChannels < 0 | | mChannel > = mNumChannels )
{
// This should only happen if there is a bug
wxASSERT ( false ) ;
return false ;
}
// We need to find the track and sequence where the blockfile belongs
WaveTrackArray tracks = mProject - > GetTracks ( ) - > GetWaveTrackArray ( false ) ;
2015-04-17 21:42:30 +00:00
size_t index ;
if ( mAutoSaveIdent )
{
for ( index = 0 ; index < tracks . GetCount ( ) ; index + + )
{
if ( tracks [ index ] - > GetAutoSaveIdent ( ) = = mAutoSaveIdent )
{
break ;
}
}
}
else
{
index = tracks . GetCount ( ) - mNumChannels + mChannel ;
}
if ( index < 0 | | index > = tracks . GetCount ( ) )
2010-01-23 19:44:49 +00:00
{
// This should only happen if there is a bug
wxASSERT ( false ) ;
return false ;
}
2015-04-17 21:42:30 +00:00
2010-01-23 19:44:49 +00:00
WaveTrack * track = tracks . Item ( index ) ;
2015-01-04 19:44:54 +00:00
WaveClip * clip = track - > NewestOrNewClip ( ) ;
2010-07-09 16:17:45 +00:00
Sequence * seq = clip - > GetSequence ( ) ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
// Load the blockfile from the XML
BlockFile * blockFile = NULL ;
DirManager * dirManager = mProject - > GetDirManager ( ) ;
dirManager - > SetLoadingFormat ( seq - > GetSampleFormat ( ) ) ;
dirManager - > SetLoadingTarget ( & blockFile ) ;
if ( ! dirManager - > HandleXMLTag ( tag , attrs ) | | ! blockFile )
{
// This should only happen if there is a bug
wxASSERT ( false ) ;
return false ;
}
seq - > AppendBlockFile ( blockFile ) ;
2010-07-09 16:17:45 +00:00
clip - > UpdateEnvelopeTrackLen ( ) ;
2010-01-23 19:44:49 +00:00
} else if ( wxStrcmp ( tag , wxT ( " recordingrecovery " ) ) = = 0 )
{
2015-04-17 21:42:30 +00:00
mAutoSaveIdent = 0 ;
2010-01-23 19:44:49 +00:00
// loop through attrs, which is a null-terminated list of
// attribute-value pairs
long nValue ;
while ( * attrs )
{
const wxChar * attr = * attrs + + ;
const wxChar * value = * attrs + + ;
if ( ! value )
break ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
const wxString strValue = value ;
2010-07-09 16:17:45 +00:00
//this channels value does not correspond to WaveTrack::Left/Right/Mono, but which channel of the recording device
//it came from, and thus we can't use XMLValueChecker::IsValidChannel on it. Rather we compare to the next attribute value.
2010-01-23 19:44:49 +00:00
if ( wxStrcmp ( attr , wxT ( " channel " ) ) = = 0 )
{
2010-07-09 16:17:45 +00:00
if ( ! XMLValueChecker : : IsGoodInt ( strValue ) | | ! strValue . ToLong ( & nValue ) | | nValue < 0 )
2010-01-23 19:44:49 +00:00
return false ;
mChannel = nValue ;
}
else if ( wxStrcmp ( attr , wxT ( " numchannels " ) ) = = 0 )
{
2014-06-03 20:30:19 +00:00
if ( ! XMLValueChecker : : IsGoodInt ( strValue ) | | ! strValue . ToLong ( & nValue ) | |
2010-01-23 19:44:49 +00:00
( nValue < 1 ) )
return false ;
2010-07-09 16:17:45 +00:00
if ( mChannel > = nValue )
2014-06-03 20:30:19 +00:00
return false ;
2010-01-23 19:44:49 +00:00
mNumChannels = nValue ;
}
2015-04-17 21:42:30 +00:00
else if ( wxStrcmp ( attr , wxT ( " id " ) ) = = 0 )
{
if ( ! XMLValueChecker : : IsGoodInt ( strValue ) | | ! strValue . ToLong ( & nValue ) | |
( nValue < 1 ) )
return false ;
mAutoSaveIdent = nValue ;
}
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
}
}
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
return true ;
}
XMLTagHandler * RecordingRecoveryHandler : : HandleXMLChild ( const wxChar * tag )
{
if ( wxStrcmp ( tag , wxT ( " simpleblockfile " ) ) = = 0 )
return this ; // HandleXMLTag also handles <simpleblockfile>
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
return NULL ;
}
2015-04-17 21:42:30 +00:00
///
/// AutoSaveFile class
///
// Simple "binary xml" format used exclusively for autosave files.
//
// It is not intended to transport these files across platform architectures,
// so endianness is not a concern.
//
// It is not intended that the user view or modify the file.
//
// It IS intended that as little work be done during auto save, so numbers
// and strings are written in their native format. They will be converted
// during recovery.
//
// The file has 3 main sections:
//
// ident literal "<?xml autosave>"
// name dictionary dictionary of all names used in the document
// data fields the "encoded" XML document
//
// If a subtree is added, it will be preceeded with FT_Push tell the decoder
// to preserve the active dictionary. The decoder when then restore the
// dictionary when an FT_Pop is encountered. Nesting is unlimited.
//
// To save space, each name (attribute or element) encountered is stored in
// the name dictionary and replaced with the assigned 2-byte identifier.
//
// All strings are in native unicode format, 2-byte or 4-byte.
//
// All "lengths" are 2-byte signed, so are limited to 32767 bytes long/
enum FieldTypes
{
FT_StartTag , // type, ID, name
FT_EndTag , // type, ID, name
FT_String , // type, ID, name, string length, string
FT_Int , // type, ID, value
FT_Bool , // type, ID, value
FT_Long , // type, ID, value
FT_LongLong , // type, ID, value
FT_SizeT , // type, ID, value
FT_Float , // type, ID, value
FT_Double , // type, ID, value
FT_Data , // type, string length, string
FT_Raw , // type, string length, string
FT_Push , // type only
FT_Pop , // type only
FT_Name // type, name length, name
} ;
# include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY ( IdMapArray ) ;
AutoSaveFile : : AutoSaveFile ( size_t allocSize )
{
mAllocSize = allocSize ;
}
AutoSaveFile : : ~ AutoSaveFile ( )
{
}
void AutoSaveFile : : StartTag ( const wxString & name )
{
mBuffer . PutC ( FT_StartTag ) ;
WriteName ( name ) ;
}
void AutoSaveFile : : EndTag ( const wxString & name )
{
mBuffer . PutC ( FT_EndTag ) ;
WriteName ( name ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , const wxChar * value )
{
WriteAttr ( name , wxString ( value ) ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , const wxString & value )
{
mBuffer . PutC ( FT_String ) ;
WriteName ( name ) ;
short len = value . Length ( ) * sizeof ( wxChar ) ;
mBuffer . Write ( & len , sizeof ( len ) ) ;
mBuffer . Write ( value . c_str ( ) , len ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , int value )
{
mBuffer . PutC ( FT_Int ) ;
WriteName ( name ) ;
mBuffer . Write ( & value , sizeof ( value ) ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , bool value )
{
mBuffer . PutC ( FT_Bool ) ;
WriteName ( name ) ;
mBuffer . Write ( & value , sizeof ( value ) ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , long value )
{
mBuffer . PutC ( FT_Long ) ;
WriteName ( name ) ;
mBuffer . Write ( & value , sizeof ( value ) ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , long long value )
{
mBuffer . PutC ( FT_LongLong ) ;
WriteName ( name ) ;
mBuffer . Write ( & value , sizeof ( value ) ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , size_t value )
{
mBuffer . PutC ( FT_SizeT ) ;
WriteName ( name ) ;
mBuffer . Write ( & value , sizeof ( value ) ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , float value , int digits )
{
mBuffer . PutC ( FT_Float ) ;
WriteName ( name ) ;
mBuffer . Write ( & value , sizeof ( value ) ) ;
mBuffer . Write ( & digits , sizeof ( digits ) ) ;
}
void AutoSaveFile : : WriteAttr ( const wxString & name , double value , int digits )
{
mBuffer . PutC ( FT_Double ) ;
WriteName ( name ) ;
mBuffer . Write ( & value , sizeof ( value ) ) ;
mBuffer . Write ( & digits , sizeof ( digits ) ) ;
}
void AutoSaveFile : : WriteData ( const wxString & value )
{
mBuffer . PutC ( FT_Data ) ;
short len = value . Length ( ) * sizeof ( wxChar ) ;
mBuffer . Write ( & len , sizeof ( len ) ) ;
mBuffer . Write ( value . c_str ( ) , len ) ;
}
void AutoSaveFile : : Write ( const wxString & value )
{
mBuffer . PutC ( FT_Raw ) ;
short len = value . Length ( ) * sizeof ( wxChar ) ;
mBuffer . Write ( & len , sizeof ( len ) ) ;
mBuffer . Write ( value . c_str ( ) , len ) ;
}
void AutoSaveFile : : WriteSubTree ( const AutoSaveFile & value )
{
mBuffer . PutC ( FT_Push ) ;
wxStreamBuffer * buf = value . mDict . GetOutputStreamBuffer ( ) ;
mBuffer . Write ( buf - > GetBufferStart ( ) , buf - > GetIntPosition ( ) ) ;
buf = value . mBuffer . GetOutputStreamBuffer ( ) ;
mBuffer . Write ( buf - > GetBufferStart ( ) , buf - > GetIntPosition ( ) ) ;
mBuffer . PutC ( FT_Pop ) ;
}
bool AutoSaveFile : : Write ( wxFFile & file ) const
{
bool success = file . Write ( AutoSaveIdent , strlen ( AutoSaveIdent ) ) = = strlen ( AutoSaveIdent ) ;
if ( success )
{
success = Append ( file ) ;
}
return success ;
}
bool AutoSaveFile : : Append ( wxFFile & file ) const
{
wxStreamBuffer * buf = mDict . GetOutputStreamBuffer ( ) ;
bool success = file . Write ( buf - > GetBufferStart ( ) , buf - > GetIntPosition ( ) ) = = buf - > GetIntPosition ( ) ;
if ( success )
{
buf = mBuffer . GetOutputStreamBuffer ( ) ;
success = file . Write ( buf - > GetBufferStart ( ) , buf - > GetIntPosition ( ) ) = = buf - > GetIntPosition ( ) ;
}
return success ;
}
void AutoSaveFile : : CheckSpace ( wxMemoryOutputStream & os )
{
wxStreamBuffer * buf = os . GetOutputStreamBuffer ( ) ;
size_t left = buf - > GetBytesLeft ( ) ;
if ( left = = 0 )
{
size_t origPos = buf - > GetIntPosition ( ) ;
char * temp = new char [ mAllocSize ] ;
buf - > Write ( temp , mAllocSize ) ;
delete temp ;
buf - > SetIntPosition ( origPos ) ;
}
}
void AutoSaveFile : : WriteName ( const wxString & name )
{
short len = name . Length ( ) * sizeof ( wxChar ) ;
short id ;
if ( mNames . count ( name ) )
{
id = mNames [ name ] ;
}
else
{
id = mNames . size ( ) ;
mNames [ name ] = id ;
CheckSpace ( mDict ) ;
mDict . PutC ( FT_Name ) ;
mDict . Write ( & id , sizeof ( id ) ) ;
mDict . Write ( & len , sizeof ( len ) ) ;
mDict . Write ( name . c_str ( ) , len ) ;
}
CheckSpace ( mBuffer ) ;
mBuffer . Write ( & id , sizeof ( id ) ) ;
}
bool AutoSaveFile : : IsEmpty ( ) const
{
return mBuffer . GetLength ( ) = = 0 ;
}
bool AutoSaveFile : : Decode ( const wxString & fileName )
{
char ident [ sizeof ( AutoSaveIdent ) ] ;
size_t len = strlen ( AutoSaveIdent ) ;
wxFileName fn ( fileName ) ;
wxFFile file ;
if ( ! file . Open ( fn . GetFullPath ( ) , wxT ( " rb " ) ) )
{
return false ;
}
if ( file . Read ( & ident , len ) ! = len | | strncmp ( ident , AutoSaveIdent , len ) ! = 0 )
{
// Not something we recognize. Could be decoded already. Let the caller
// deal with it.
file . Close ( ) ;
return true ;
}
len = file . Length ( ) - len ;
char * buf = new char [ len ] ;
if ( file . Read ( buf , len ) ! = len )
{
delete buf ;
file . Close ( ) ;
return false ;
}
wxMemoryInputStream in ( buf , len ) ;
file . Close ( ) ;
// Decode to a temporary file to preserve the orignal.
wxString tempName = fn . CreateTempFileName ( fn . GetPath ( true ) ) ;
XMLFileWriter out ;
out . Open ( tempName , wxT ( " wb " ) ) ;
if ( ! out . IsOpened ( ) )
{
delete buf ;
wxRemoveFile ( tempName ) ;
return false ;
}
mIds . clear ( ) ;
while ( ! in . Eof ( ) & & ! out . Error ( ) )
{
short id ;
switch ( in . GetC ( ) )
{
case FT_Push :
{
mIdStack . Add ( mIds ) ;
mIds . clear ( ) ;
}
break ;
case FT_Pop :
{
mIds = mIdStack [ mIdStack . GetCount ( ) - 1 ] ;
mIdStack . RemoveAt ( mIdStack . GetCount ( ) - 1 ) ;
}
break ;
case FT_Name :
{
short len ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & len , sizeof ( len ) ) ;
wxChar * name = new wxChar [ len / sizeof ( wxChar ) ] ;
in . Read ( name , len ) ;
mIds [ id ] = wxString ( name , len / sizeof ( wxChar ) ) ;
delete name ;
}
break ;
case FT_StartTag :
{
in . Read ( & id , sizeof ( id ) ) ;
out . StartTag ( mIds [ id ] ) ;
}
break ;
case FT_EndTag :
{
in . Read ( & id , sizeof ( id ) ) ;
out . EndTag ( mIds [ id ] ) ;
}
break ;
case FT_String :
{
short len ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & len , sizeof ( len ) ) ;
wxChar * val = new wxChar [ len / sizeof ( wxChar ) ] ;
in . Read ( val , len ) ;
out . WriteAttr ( mIds [ id ] , wxString ( val , len / sizeof ( wxChar ) ) ) ;
delete val ;
}
break ;
case FT_Float :
{
float val ;
int dig ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & val , sizeof ( val ) ) ;
in . Read ( & dig , sizeof ( dig ) ) ;
out . WriteAttr ( mIds [ id ] , val , dig ) ;
}
break ;
case FT_Double :
{
double val ;
int dig ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & val , sizeof ( val ) ) ;
in . Read ( & dig , sizeof ( dig ) ) ;
out . WriteAttr ( mIds [ id ] , val , dig ) ;
}
break ;
case FT_Int :
{
int val ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & val , sizeof ( val ) ) ;
out . WriteAttr ( mIds [ id ] , val ) ;
}
break ;
case FT_Bool :
{
bool val ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & val , sizeof ( val ) ) ;
out . WriteAttr ( mIds [ id ] , val ) ;
}
break ;
case FT_Long :
{
long val ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & val , sizeof ( val ) ) ;
out . WriteAttr ( mIds [ id ] , val ) ;
}
break ;
case FT_LongLong :
{
long long val ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & val , sizeof ( val ) ) ;
out . WriteAttr ( mIds [ id ] , val ) ;
}
break ;
case FT_SizeT :
{
size_t val ;
in . Read ( & id , sizeof ( id ) ) ;
in . Read ( & val , sizeof ( val ) ) ;
out . WriteAttr ( mIds [ id ] , val ) ;
}
break ;
case FT_Data :
{
short len ;
in . Read ( & len , sizeof ( len ) ) ;
wxChar * val = new wxChar [ len / sizeof ( wxChar ) ] ;
in . Read ( val , len ) ;
out . WriteData ( wxString ( val , len / sizeof ( wxChar ) ) ) ;
delete val ;
}
break ;
case FT_Raw :
{
short len ;
in . Read ( & len , sizeof ( len ) ) ;
wxChar * val = new wxChar [ len / sizeof ( wxChar ) ] ;
in . Read ( val , len ) ;
out . Write ( wxString ( val , len / sizeof ( wxChar ) ) ) ;
delete val ;
}
break ;
default :
wxASSERT ( true ) ;
break ;
}
}
delete buf ;
bool error = out . Error ( ) ;
out . Close ( ) ;
// Bail if decoding failed.
if ( error )
{
// File successfully decoded
wxRemoveFile ( tempName ) ;
return false ;
}
// Decoding was successful, so remove the original file and replace with decoded one.
if ( wxRemoveFile ( fileName ) )
{
if ( ! wxRenameFile ( tempName , fileName ) )
{
return false ;
}
}
return true ;
}