replace kludgy global flag with less kludgy callbacks; this code is untested, since...
authorMark Cannon <vyhdycokio@gmail.com>
Mon, 13 Feb 2012 19:38:33 +0000 (14:38 -0500)
committerMark Cannon <vyhdycokio@gmail.com>
Mon, 13 Feb 2012 19:38:33 +0000 (14:38 -0500)
src/RageUtil.cpp
src/RageUtil.h
src/ScreenArcadePatch.cpp
src/ScreenSelectMusic.cpp
src/ScreenUserPacks.cpp
src/UserPackManager.cpp
src/UserPackManager.h

index 546027c..b6a963d 100755 (executable)
@@ -1804,28 +1804,13 @@ void FileWrite(RageFileBasic& f, float fWrite)
        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) )
        {
@@ -1841,7 +1826,7 @@ bool FileCopy( const CString &sSrcFile, const CString &sDstFile, CString &sError
        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() );
@@ -1851,67 +1836,70 @@ bool FileCopy( const CString &sSrcFile, const CString &sDstFile, CString &sError
        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
index a5a566e..0b410d9 100755 (executable)
@@ -478,17 +478,14 @@ void FileWrite(RageFileBasic& f, int iWrite);
 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.
index d5408ce..9ce6e1d 100644 (file)
@@ -331,13 +331,14 @@ bool ScreenArcadePatch::GetXMLData( RageFileDriverZip *fZip, CString &sGame, CSt
        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. */
@@ -471,7 +472,7 @@ void ScreenArcadePatch::PatchMain()
        }
 
        CString sError;
-       if( FileCopy( patch, *m_PatchFile, sError, &UpdateProgress) )
+       if( FileCopy( patch, *m_PatchFile, sError, NULL, UpdateProgress) )
        {
                STATE_TEXT( "Patch copied! Checking..." );
                PATCH_TEXT( "" );
@@ -585,9 +586,9 @@ void ScreenArcadePatch::PatchMain()
                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 );
index 146a4d2..d65b8f1 100755 (executable)
 // 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
@@ -1327,50 +1323,72 @@ void ScreenSelectMusic::HandleScreenMessage( const ScreenMessage SM )
        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
@@ -1415,8 +1433,8 @@ bool ScreenSelectMusic::ValidateCustomSong( Song* pSong )
 \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
@@ -1552,7 +1570,7 @@ void ScreenSelectMusic::MenuStart( PlayerNumber pn )
 \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
index f5388dc..d7e8b8d 100644 (file)
@@ -242,10 +242,10 @@ void ScreenUserPacks::Input( const DeviceInput& DeviceI, const InputEventType ty
 
 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;
 
@@ -259,15 +259,14 @@ void UpdateXferProgress( unsigned long iBytesCurrent, unsigned long iBytesTotal
 
        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();
@@ -287,10 +286,13 @@ void UpdateXferProgress( unsigned long iBytesCurrent, unsigned long iBytesTotal
 
        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");
@@ -302,6 +304,7 @@ void ScreenUserPacks::HandleScreenMessage( const ScreenMessage SM )
 
                LOG->Warn("Cancelled Transfer of user pack.");
        }
+#endif
        if ( SM == SM_LinkedMenuChange )
        {
                m_pCurLOM = m_pCurLOM->SwitchToNextMenu();
index 3b89c55..33c3d8f 100644 (file)
@@ -143,9 +143,9 @@ bool UserPackManager::IsPackTransferable( const CString &sPack, const CString &s
        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 );
index 52094f8..6987c98 100644 (file)
@@ -11,13 +11,15 @@ static const CString USER_PACK_SAVE_PATH = "UserPacks/";
 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: