f.PutLine( ssprintf("%f", fWrite) );
}
-// a flag that can be used to interrupt a current copy operation
-bool g_bInterruptCopy = false;
-
-void InterruptCopy()
-{
- g_bInterruptCopy = true;
-}
-
-/* workarounds for some pre-existing calls... */
-bool FileCopy( const CString &sSrcFile, const CString &sDstFile, void(*OnUpdate)(unsigned long, unsigned long) )
-{
- CString sError;
- return FileCopy( sSrcFile, sDstFile, sError, OnUpdate );
-}
-
-bool FileCopy( RageFileBasic &in, RageFileBasic &out, void (*OnUpdate)(unsigned long, unsigned long), bool *bReadError )
+bool FileCopy( const CString &sSrcFile, const CString &sDstFile, FileCopyFn CopyFn )
{
- CString sError;
- return FileCopy( in, out, sError, OnUpdate, bReadError );
+ CString sThrowAway;
+ return FileCopy( sSrcFile, sDstFile, sThrowAway, CopyFn );
}
-bool FileCopy( const CString &sSrcFile, const CString &sDstFile, CString &sError, void(*OnUpdate)(unsigned long, unsigned long) )
+bool FileCopy( const CString &sSrcFile, const CString &sDstFile, CString &sError, FileCopyFn CopyFn )
{
if( !sSrcFile.CompareNoCase(sDstFile) )
{
if( !out.Open(sDstFile, RageFile::WRITE) )
return false;
- if( !FileCopy(in, out, sError, OnUpdate) )
+ if( !FileCopy(in, out, sError, NULL, CopyFn) )
{
LOG->Warn( "FileCopy(%s,%s): %s",
sSrcFile.c_str(), sDstFile.c_str(), sError.c_str() );
return true;
}
-bool FileCopy( RageFileBasic &in, RageFileBasic &out, CString &sError, void(*OnUpdate)(unsigned long, unsigned long), bool *bReadError )
+bool FileCopy( RageFileBasic &in, RageFileBasic &out, CString &sError, bool *bReadError, FileCopyFn CopyFn )
{
- g_bInterruptCopy = false;
+#define SAFE_SET(boolptr, val) if( boolptr ) { *boolptr = val; }
- /* for reporting file progress */
- unsigned long read = 0;
- unsigned long total = in.GetFileSize();
+ CString data;
+ uint64_t iBytesRead = 0, iBytesTotal = in.GetFileSize();
+ bool bContinue = true;
- while( !g_bInterruptCopy )
+ while( bContinue )
{
- CString data;
if( in.Read(data, 1024*32) == -1 )
{
sError = ssprintf( "read error: %s", in.GetError().c_str() );
- if( bReadError != NULL )
- *bReadError = true;
+ SAFE_SET( bReadError, true );
return false;
}
+
if( data.empty() )
break;
- read += data.size();
+ iBytesRead += data.size();
- int i = out.Write(data);
- if( i == -1 )
+ if( out.Write(data) == -1 )
{
sError = ssprintf( "write error: %s", out.GetError().c_str() );
- if( bReadError != NULL )
- *bReadError = false;
+ SAFE_SET( bReadError, false );
return false;
}
- /* if we have a function pointer, calculate percentage. */
- if( OnUpdate != NULL )
- OnUpdate( read, total );
+ /* Report our progress if we were given a callback. CopyFn's
+ * return value determines whether we continue copying: if it
+ * cancels the transfer, report that as a unique error. */
+ if( CopyFn )
+ {
+ /* Continue unless the callback tells us to stop. */
+ if( (bContinue = CopyFn(iBytesRead, iBytesTotal)) )
+ continue;
+
+ sError = CString( "cancelled manually" );
+
+ LOG->Warn( "FileCopy(%s, %s) cancelled at %llu/%llu bytes",
+ in.GetDisplayPath().c_str(),
+ out.GetDisplayPath().c_str(),
+ iBytesRead, iBytesTotal );
+
+ SAFE_SET( bReadError, false );
+ return false;
+ }
}
if( out.Flush() == -1 )
{
sError = ssprintf( "write error: %s", out.GetError().c_str() );
- if( bReadError != NULL )
- *bReadError = false;
- return false;
- }
-
- /* handle any interrupts if they occurred. */
- if( g_bInterruptCopy )
- {
- sError = "Cancelled by user";
- LOG->Warn( "Copying interrupted (%lu/%lu).", read, total );
- g_bInterruptCopy = false;
-
+ SAFE_SET( bReadError, false );
return false;
}
return true;
+#undef SAFE_SET
}
/*
* Copyright (c) 2001-2004 Chris Danford, Glenn Maynard
- * Copyright (c) 2008 BoXoRRoXoRs
+ * Copyright (c) 2008-2012 BoXoRRoXoRs
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
void FileWrite(RageFileBasic& f, size_t uWrite);
void FileWrite(RageFileBasic& f, float fWrite);
-// stops a currently-running copy operation
-void InterruptCopy();
-
-/* if OnUpdate() is defined, that function is called after each out.Write(). */
-bool FileCopy( const CString &sSrcFile, const CString &sDstFile, CString &sError, void(*OnUpdate)(unsigned long, unsigned long) = NULL );
-bool FileCopy( RageFileBasic &in, RageFileBasic &out, CString &sError, void(*OnUpdate)(unsigned long, unsigned long) = NULL, bool *bReadError = NULL );
-
-/* versions without an error message argument, for compatibility */
-bool FileCopy( const CString &sSrcFile, const CString &sDstFile, void(*OnUpdate)(unsigned long, unsigned long) = NULL );
-bool FileCopy( RageFileBasic &in, RageFileBasic &out, void(*OnUpdate)(unsigned long, unsigned long) = NULL, bool *bReadError = NULL );
-
+/* FileCopy callback, called with the progress of the running copy in
+ * terms of copied bytes. If this returns false, we stop the file copy. */
+typedef bool (*FileCopyFn)( uint64_t iBytesCur, uint64_t iBytesTotal );
+
+/* FileCopy(): copies sSrcFile to sDstFile. */
+bool FileCopy( const CString &sSrcFile, const CString &sDstFile, FileCopyFn fn = NULL );
+bool FileCopy( const CString &sSrcFile, const CString &sDstFile, CString &sError, FileCopyFn fn = NULL );
+bool FileCopy( RageFileBasic &in, RageFileBasic &out, CString &sError, bool *bReadError = NULL, FileCopyFn fn = NULL );
// a few bitwise operators that may come in handy.
// all operations are 0-31, i.e. zero-indexed.
return true;
}
-static void UpdateProgress( unsigned long iCurrent, unsigned long iTotal )
+bool UpdateProgress( uint64_t iCurrent, uint64_t iTotal )
{
float fPercent = iCurrent / (iTotal/100);
CString sProgress = ssprintf( "Copying patch (%.0f%%)\n\n"
"Please do not remove the USB Card.", fPercent );
PATCH_TEXT( sProgress );
+ return true;
}
/* helper functions to get the actual file paths for CHMODing. */
}
CString sError;
- if( FileCopy( patch, *m_PatchFile, sError, &UpdateProgress) )
+ if( FileCopy( patch, *m_PatchFile, sError, NULL, UpdateProgress) )
{
STATE_TEXT( "Patch copied! Checking..." );
PATCH_TEXT( "" );
RageFile fCopyTo;
fCopyTo.Open( TEMP_PATCH_DIR + sCleanPath, RageFile::WRITE );
- if( !FileCopy(*fCopyFrom, fCopyTo) )
+ if( !FileCopy(*fCopyFrom, fCopyTo, sError) )
{
- PATCH_TEXT( ssprintf("Could not copy \"%s\":\n" "%s", sCleanPath.c_str(),sError.c_str()) );
+ PATCH_TEXT( ssprintf("Could not copy \"%s\":\n" "%s", sCleanPath.c_str(), sError.c_str()) );
m_State = PATCH_ERROR;
SAFE_DELETE( fCopyFrom );
// XXX: custom song loading. remove these if we can.\r
#include "RageFileDriverTimeout.h"\r
\r
-// Draw every 1/6 second, approx. one per 10 minutes\r
-static RageTimer DrawTimer;\r
-const float DRAW_UPDATE_TIME = 0.1666667;\r
-\r
const int NUM_SCORE_DIGITS = 9;\r
\r
#define NEXT_SCREEN THEME->GetMetric (m_sName,"NextScreen")\r
Screen::HandleScreenMessage( SM );\r
}\r
\r
-// XXX: lots of ctors/dtors and redundant calls. How can we best fix this?\r
-void UpdateLoadProgress( unsigned long iCurrent, unsigned long iTotal )\r
+/* Helper functions for custom song handling.\r
+ * XXX: we should find a better place for these. -- vyhd */\r
+namespace\r
{\r
- // UGLY: send a manual update to INPUTFILTER to force input buffering\r
- INPUTFILTER->Update( 0 );\r
+ /* Returns true if either player's button presses triggered\r
+ * a loading interrupt. */\r
+ bool IsInterrupted()\r
+ {\r
+ /* HACK: if we're not running threaded I/O, manually poke\r
+ * INPUTFILTER for events in order to force an input poll. */\r
+ if( DiagnosticsUtil::GetInputType().empty() )\r
+ INPUTFILTER->Update( 0 );\r
\r
- bool bInterrupt = false;\r
+ bool bInterrupt = false;\r
\r
- // if a player presses Select or ML+MR, stop loading the song.\r
- FOREACH_EnabledPlayer( pn )\r
- {\r
- bInterrupt |= INPUTMAPPER->IsButtonDown( MenuInput(pn, MENU_BUTTON_SELECT) );\r
- \r
- bInterrupt |= INPUTMAPPER->IsButtonDown(MenuInput(pn, MENU_BUTTON_LEFT)) &&\r
- INPUTMAPPER->IsButtonDown(MenuInput(pn, MENU_BUTTON_RIGHT));\r
+ FOREACH_EnabledPlayer( pn )\r
+ {\r
+ /* Is this player pressing 'Select'? */\r
+ bInterrupt |= INPUTMAPPER->IsButtonDown( MenuInput(pn, MENU_BUTTON_SELECT) );\r
+\r
+ /* Is this player pressing 'MenuLeft'+'MenuRight'? */\r
+ bInterrupt |= INPUTMAPPER->IsButtonDown(MenuInput(pn, MENU_BUTTON_LEFT)) &&\r
+ INPUTMAPPER->IsButtonDown(MenuInput(pn, MENU_BUTTON_RIGHT));\r
+ }\r
+\r
+ return bInterrupt;\r
}\r
\r
- if( bInterrupt )\r
+ /* Draw() is expensive and slows down file copying;\r
+ * only draw roughly six times a second. */\r
+ RageTimer g_DrawTimer( RageZeroTimer );\r
+ const float DRAW_UPDATE_TIME = 0.1666667f;\r
+\r
+ bool CopyCustomSong( uint64_t iBytesRead, uint64_t iBytesTotal )\r
{\r
- InterruptCopy();\r
- LOG->Warn( "Custom song load interrupted." );\r
+ // if a player presses Select or ML+MR, stop loading the song.\r
+ if( IsInterrupted() )\r
+ {\r
+ LOG->Warn( "Custom song load interrupted." );\r
\r
- // TRICKY DISCO: discard all input events recorded since update.\r
- // otherwise, we'll get all the pressed buttons at once.\r
- InputEventArray throwaway;\r
- INPUTFILTER->GetInputEvents( throwaway );\r
- }\r
+ /* TRICKY DISCO: discard all recorded input events, or\r
+ * we'll process all button presses in the next frame. */\r
+ InputEventArray throwaway;\r
+ INPUTFILTER->GetInputEvents( throwaway );\r
\r
- /* only Draw() occasionally, since this is expensive. */\r
- if( DrawTimer.Ago() < DRAW_UPDATE_TIME )\r
- return;\r
+ return false;\r
+ }\r
\r
- unsigned long iPercent = iCurrent / (iTotal/100);\r
+ /* Don't Draw() yet, but keep copying. */\r
+ if( g_DrawTimer.Ago() < DRAW_UPDATE_TIME )\r
+ return true;\r
\r
- // XXX: kind of voodoo\r
- CString sMessage = ssprintf( "\n\n%s\n%lu%%\n%s",\r
- CUSTOM_SONG_WAIT_TEXT.GetValue().c_str(), \r
- iPercent,\r
- CUSTOM_SONG_CANCEL_TEXT.GetValue().c_str() );\r
+ float fPercent = float(iBytesRead) / float(iBytesTotal/100);\r
\r
- SCREENMAN->OverlayMessage( sMessage );\r
- SCREENMAN->Draw();\r
+ // XXX: kind of voodoo\r
+ SCREENMAN->OverlayMessage( ssprintf("\n\n%s\n%02.1f%%\n%s",\r
+ CUSTOM_SONG_WAIT_TEXT.GetValue().c_str(),\r
+ fPercent,\r
+ CUSTOM_SONG_CANCEL_TEXT.GetValue().c_str()\r
+ ) );\r
\r
- DrawTimer.Touch();\r
+ SCREENMAN->Draw();\r
+ g_DrawTimer.Touch();\r
+\r
+ return true;\r
+ }\r
}\r
\r
// run a few basic tests to be sure we aren't breaking any limits...\r
\r
// we can copy the music. destination is determined with\r
// "m_sGameplayMusic" so we can change that from one place\r
- bCopied = FileCopy( GAMESTATE->m_pCurSong->GetMusicPath(), \r
- GAMESTATE->m_pCurSong->m_sGameplayMusic, sError, &UpdateLoadProgress );\r
+ bCopied = FileCopy( GAMESTATE->m_pCurSong->GetMusicPath(),\r
+ GAMESTATE->m_pCurSong->m_sGameplayMusic, sError, CopyCustomSong );\r
\r
// failed, most likely a permissions error\r
if( !bCopied && !sError.empty() )\r
\r
bError = !pSong->CheckCustomSong( sError );\r
// TODO: give custom song for course xfer its own progress function\r
- if (!bError) bError = !FileCopy( pSong->GetMusicPath(), sNewPath, &UpdateLoadProgress );\r
+ if (!bError) bError = !FileCopy( pSong->GetMusicPath(), sNewPath, CopyCustomSong );\r
#ifndef WIN32\r
MEMCARDMAN->UnmountCard( pSong->m_SongOwner );\r
#endif\r
CString g_CurXferFile;
CString g_CurSelection;
-unsigned long g_iLastCurrentBytes;
+uint64_t g_iLastCurrentBytes;
RageTimer g_UpdateDuration;
-void UpdateXferProgress( unsigned long iBytesCurrent, unsigned long iBytesTotal )
+bool UpdateXferProgress( uint64_t iBytesCurrent, uint64_t iBytesTotal )
{
bool bInterrupt = false;
if ( bInterrupt )
{
- InterruptCopy();
-
InputEventArray throwaway;
INPUTFILTER->GetInputEvents( throwaway );
+ return false;
}
// Draw() is very expensive: only do it on occasion.
if( DrawTimer.Ago() < DRAW_UPDATE_TIME )
- return;
+ return true;
/* this truncates to int, but that's okay for our purposes */
float iTransferRate = iBytesCurrent / g_UpdateDuration.Ago();
SCREENMAN->Draw();
DrawTimer.Touch();
+ return true;
}
void ScreenUserPacks::HandleScreenMessage( const ScreenMessage SM )
{
+#if 0
+ /* Not compatible with FileCopy callback system; was this ever used? -- vyhd */
if ( SM == SM_CancelTransfer )
{
Dialog::OK("SM_CancelTransfer");
LOG->Warn("Cancelled Transfer of user pack.");
}
+#endif
if ( SM == SM_LinkedMenuChange )
{
m_pCurLOM = m_pCurLOM->SwitchToNextMenu();
return true;
}
-bool UserPackManager::TransferPack( const CString &sPack, const CString &sDestPack, void(*OnUpdate)(unsigned long, unsigned long), CString &sError )
+bool UserPackManager::TransferPack( const CString &sPack, const CString &sDestPack, FileCopyFn CopyFn, CString &sError )
{
- bool bSuccess = FileCopy( sPack, USER_PACK_SAVE_PATH + "/" + sDestPack, sError, OnUpdate );
+ bool bSuccess = FileCopy( sPack, USER_PACK_SAVE_PATH + "/" + sDestPack, sError, CopyFn );
if (!bSuccess)
{
FILEMAN->FlushDirCache( USER_PACK_SAVE_PATH );
class UserPackManager
{
public:
- void GetUserPacks( CStringArray &sAddTo );
+ void GetUserPacks( vector<CString> &sAddTo );
void MountAll();
bool IsPackMountable( const CString &sPack, CString &sError );
bool IsPackTransferable( const CString &sPack, const CString &sPath, CString &sError );
- bool TransferPack( const CString &sPack, const CString &sDest, void(*OnUpdate)(unsigned long, unsigned long), CString &sError );
+ /* XXX: duped from RageUtil so we don't pull in that header. */
+ bool TransferPack( const CString &sPack, const CString &sDest,
+ bool (*CopyFn)(uint64_t, uint64_t), CString &sError );
bool Remove( const CString &sPack );
protected: