static bool WriteDWINotesTag( RageFile &f, const Steps &out ) { if( out.GetDifficulty() == Difficulty_Edit ) return false; // not supported by DWI LOG->Trace( "Steps::WriteDWINotesTag" ); switch( out.m_StepsType ) { case StepsType_dance_single: f.Write( "#SINGLE:" ); break; case StepsType_dance_couple: f.Write( "#COUPLE:" ); break; case StepsType_dance_double: f.Write( "#DOUBLE:" ); break; case StepsType_dance_solo: f.Write( "#SOLO:" ); break; default: return false; // not a type supported by DWI } switch( out.GetDifficulty() ) { case Difficulty_Beginner: f.Write( "BEGINNER:" ); break; case Difficulty_Easy: f.Write( "BASIC:" ); break; case Difficulty_Medium: f.Write( "ANOTHER:" ); break; case Difficulty_Hard: f.Write( "MANIAC:" ); break; case Difficulty_Challenge: f.Write( "SMANIAC:" ); break; default: ASSERT(0); return false; } f.PutLine( ssprintf("%d:", out.GetMeter()) ); return true; }
static void RageFile_png_write( png_struct *pPng, png_byte *pData, png_size_t iSize ) { RageFile *pFile = (RageFile *) png_get_io_ptr(pPng); int iGot = pFile->Write( pData, iSize ); if( iGot == -1 ) SafePngError( pPng, pFile->GetError() ); }
static void WriteBytes( RageFile &f, RString &sError, const void *buf, int size ) { if( sError.size() != 0 ) return; int ret = f.Write( buf, size ); if( ret == -1 ) sError = f.GetError(); }
static void WriteLineList( RageFile &f, vector<CString> &lines, bool SkipLeadingBlankLines, bool OmitLastNewline ) { for( unsigned i = 0; i < lines.size(); ++i ) { TrimRight( lines[i] ); if( SkipLeadingBlankLines ) { if( lines.size() == 0 ) continue; SkipLeadingBlankLines = false; } f.Write( lines[i] ); if( !OmitLastNewline || i+1 < lines.size() ) f.PutLine( "" ); /* newline */ } }
static bool WriteFile( RString sFile, RString sBuf ) { RageFile output; if( !output.Open(sFile, RageFile::WRITE) ) { LOG->Warn( "WriteFile: opening %s failed: %s", sFile.c_str(), output.GetError().c_str() ); return false; } if( output.Write(sBuf) == -1 || output.Flush() == -1 ) { LOG->Warn( "WriteFile: writing %s failed: %s", sFile.c_str(), output.GetError().c_str() ); output.Close(); FILEMAN->Remove( sFile ); return false; } return true; }
void NotesWriterSM::WriteSMNotesTag( const Steps &in, RageFile &f, bool bSavingCache ) { f.PutLine( "" ); f.PutLine( ssprintf( "//---------------%s - %s----------------", GameManager::StepsTypeToString(in.m_StepsType).c_str(), in.GetDescription().c_str() ) ); f.PutLine( "#NOTES:" ); f.PutLine( ssprintf( " %s:", GameManager::StepsTypeToString(in.m_StepsType).c_str() ) ); f.PutLine( ssprintf( " %s:", in.GetDescription().c_str() ) ); f.PutLine( ssprintf( " %s:", DifficultyToString(in.GetDifficulty()).c_str() ) ); f.PutLine( ssprintf( " %d:", in.GetMeter() ) ); int MaxRadar = bSavingCache? NUM_RADAR_CATEGORIES:5; CStringArray asRadarValues; for( int r=0; r < MaxRadar; r++ ) asRadarValues.push_back( ssprintf("%.3f", in.GetRadarValues()[r]) ); /* Don't append a newline here; it's added in NoteDataUtil::GetSMNoteDataString. * If we add it here, then every time we write unmodified data we'll add an extra * newline and they'll accumulate. */ f.Write( ssprintf( " %s:", join(",",asRadarValues).c_str() ) ); CString sNoteData; CString sAttackData; in.GetSMNoteData( sNoteData, sAttackData ); vector<CString> lines; split( sNoteData, "\n", lines, false ); WriteLineList( f, lines, true, true ); if( sAttackData.empty() ) f.PutLine( ";" ); else { f.PutLine( ":" ); lines.clear(); split( sAttackData, "\n", lines, false ); WriteLineList( f, lines, true, true ); f.PutLine( ";" ); } }
void SanityCheck() { /* Read sanity check. */ do { g_TestFile = "hello"; g_TestFilename = "file"; RageFile test; if( !test.Open("/test/file", RageFile::READ ) ) Fail( "Sanity check Open() failed: %s", test.GetError().c_str() ); RString str; int got = test.GetLine( str ); if( got <= 0 ) Fail( "Sanity check GetLine(): got %i", got ); if( str != "hello" ) Fail( "Sanity check Read(): expected \"hello\", got \"%s\"", str.c_str() ); } while(false); /* Read error sanity check. */ do { g_TestFile = "hello world"; g_TestFilename = "file"; g_BytesUntilError = 5; RageFile test; if( !test.Open("/test/file", RageFile::READ ) ) Fail( "Sanity check 2 Open() failed: %s", test.GetError().c_str() ); RString str; int got = test.Read( str, 5 ); if( got != 5 ) Fail( "Sanity check 2 Read(): got %i", got ); if( str != "hello" ) Fail( "Sanity check 2 Read(): expected \"hello\", got \"%s\"", str.c_str() ); got = test.Read( str, 5 ); if( got != -1 ) Fail( "Sanity check 2 GetLine(): expected -1, got %i", got ); if( test.GetError() != "Fake error" ) Fail( "Sanity check 2 GetError(): expected \"Fake error\", got \"%s\"", test.GetError().c_str() ); } while(false); /* Write error sanity check. */ do { g_TestFilename = "file"; g_BytesUntilError = 5; RageFile test; if( !test.Open("/test/file", RageFile::WRITE ) ) Fail( "Write error check Open() failed: %s", test.GetError().c_str() ); int wrote = test.Write( "test", 4 ); if( wrote != 4 ) Fail( "Write error check Write(): wrote %i", wrote ); wrote = test.Write( "ing", 3 ); if( wrote != -1 ) Fail( "Write error check Write(): expected -1, got %i", wrote ); if( test.GetError() != "Fake error" ) Fail( "Write error check GetError(): expected \"Fake error\", got \"%s\"", test.GetError().c_str() ); } while(false); }
void BackgroundLoader::LoadThread() { while( !m_bShutdownThread ) { /* Wait for a request. It's normal for this to wait for a long time; don't * fail on timeout. */ m_StartSem.Wait(); CString sFile = GetRequest(); if( sFile.empty() ) continue; { /* If the file already exists, short circuit. */ m_Mutex.Lock(); map<CString,int>::iterator it; it = m_FinishedRequests.find( sFile ); if( it != m_FinishedRequests.end() ) { ++it->second; LOG->Trace("XXX: request %s done loading (already done), cnt now %i", sFile.c_str(), m_FinishedRequests[sFile] ); m_Mutex.Unlock(); continue; } m_Mutex.Unlock(); } m_sThreadIsActive = true; LOG->Trace("XXX: reading %s", sFile.c_str()); CString sCachePath = GetCachePath( sFile ); /* Open the file and read it. */ RageFile src; if( src.Open(sFile) ) { /* If we're writing to a file cache ... */ RageFile dst; bool bWriteToCache = g_bWriteToCache; if( bWriteToCache ) bWriteToCache = dst.Open( sCachePath, RageFile::WRITE ); LOG->Trace("XXX: go on '%s' to '%s'", sFile.c_str(), sCachePath.c_str()); char buf[1024*4]; while( !m_sThreadShouldAbort && !src.AtEOF() ) { int got = src.Read( buf, sizeof(buf) ); if( got > 0 && bWriteToCache ) dst.Write( buf, got ); } if( bWriteToCache ) dst.Close(); LOG->Trace("XXX: done"); } src.Close(); m_Mutex.Lock(); if( !m_sThreadShouldAbort ) { ++m_FinishedRequests[sFile]; LOG->Trace("XXX: request %s done loading, cnt now %i", sFile.c_str(), m_FinishedRequests[sFile] ); } else { FILEMAN->Remove( sCachePath ); LOG->Trace("XXX: request %s aborted", sFile.c_str() ); } m_sThreadShouldAbort = false; m_sThreadIsActive = false; m_Mutex.Unlock(); } }
int URLRageFile_write( avcodec::URLContext *h, unsigned char *buf, int size ) { RageFile *f = (RageFile *) h->priv_data; return f->Write( buf, size ); }
bool NotesWriterDWI::Write( RString sPath, const Song &out ) { RageFile f; if( !f.Open( sPath, RageFile::WRITE ) ) { LOG->UserLog( "Song file", sPath, "couldn't be opened for writing: %s", f.GetError().c_str() ); return false; } /* Write transliterations, if we have them, since DWI doesn't support UTF-8. */ f.PutLine( ssprintf("#TITLE:%s;", DwiEscape(out.GetTranslitFullTitle()).c_str()) ); f.PutLine( ssprintf("#ARTIST:%s;", DwiEscape(out.GetTranslitArtist()).c_str()) ); ASSERT( out.m_Timing.m_BPMSegments[0].m_iStartRow == 0 ); f.PutLine( ssprintf("#FILE:%s;", DwiEscape(out.m_sMusicFile).c_str()) ); f.PutLine( ssprintf("#BPM:%.3f;", out.m_Timing.m_BPMSegments[0].GetBPM()) ); f.PutLine( ssprintf("#GAP:%ld;", -lrintf( out.m_Timing.m_fBeat0OffsetInSeconds*1000 )) ); f.PutLine( ssprintf("#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds) ); f.PutLine( ssprintf("#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds) ); if( out.m_sCDTitleFile.size() ) f.PutLine( ssprintf("#CDTITLE:%s;", DwiEscape(out.m_sCDTitleFile).c_str()) ); switch( out.m_DisplayBPMType ) { case Song::DISPLAY_ACTUAL: // write nothing break; case Song::DISPLAY_SPECIFIED: if( out.m_fSpecifiedBPMMin == out.m_fSpecifiedBPMMax ) f.PutLine( ssprintf("#DISPLAYBPM:%i;\n", (int) out.m_fSpecifiedBPMMin) ); else f.PutLine( ssprintf("#DISPLAYBPM:%i..%i;\n", (int) out.m_fSpecifiedBPMMin, (int) out.m_fSpecifiedBPMMax) ); break; case Song::DISPLAY_RANDOM: f.PutLine( "#DISPLAYBPM:*" ); break; } if( !out.m_Timing.m_StopSegments.empty() ) { f.Write( "#FREEZE:" ); for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ ) { const StopSegment &fs = out.m_Timing.m_StopSegments[i]; f.Write( ssprintf("%.3f=%.3f", fs.m_iStartRow * 4.0f / ROWS_PER_BEAT, roundf(fs.m_fStopSeconds*1000)) ); if( i != out.m_Timing.m_StopSegments.size()-1 ) f.Write( "," ); } f.PutLine( ";" ); } if( out.m_Timing.m_BPMSegments.size() > 1) { f.Write( "#CHANGEBPM:" ); for( unsigned i=1; i<out.m_Timing.m_BPMSegments.size(); i++ ) { const BPMSegment &bs = out.m_Timing.m_BPMSegments[i]; f.Write( ssprintf("%.3f=%.3f", bs.m_iStartRow * 4.0f / ROWS_PER_BEAT, bs.GetBPM() ) ); if( i != out.m_Timing.m_BPMSegments.size()-1 ) f.Write( "," ); } f.PutLine( ";" ); } const vector<Steps*>& vpSteps = out.GetAllSteps(); for( unsigned i=0; i<vpSteps.size(); i++ ) { const Steps* pSteps = vpSteps[i]; if( pSteps->IsAutogen() ) continue; // don't save autogen notes if( !WriteDWINotesTag( f, *pSteps )) continue; WriteDWINotesField( f, *pSteps, 0 ); if( pSteps->m_StepsType==StepsType_dance_double || pSteps->m_StepsType==StepsType_dance_couple ) { f.PutLine( ":" ); WriteDWINotesField( f, *pSteps, 4 ); } f.PutLine( ";" ); } return true; }
static void WriteDWINotesField( RageFile &f, const Steps &out, int start ) { NoteData notedata; out.GetNoteData( notedata ); NoteDataUtil::InsertHoldTails( notedata ); const int iLastMeasure = int( notedata.GetLastBeat()/BEATS_PER_MEASURE ); for( int m=0; m<=iLastMeasure; m++ ) // foreach measure { NoteType nt = NoteDataUtil::GetSmallestNoteTypeForMeasure( notedata, m ); double fCurrentIncrementer = 0; switch( nt ) { case NOTE_TYPE_4TH: case NOTE_TYPE_8TH: fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; break; case NOTE_TYPE_12TH: case NOTE_TYPE_24TH: f.Write( "[" ); fCurrentIncrementer = 1.0/24 * BEATS_PER_MEASURE; break; case NOTE_TYPE_16TH: f.Write( "(" ); fCurrentIncrementer = 1.0/16 * BEATS_PER_MEASURE; break; case NOTE_TYPE_32ND: case NOTE_TYPE_64TH: f.Write( "{" ); fCurrentIncrementer = 1.0/64 * BEATS_PER_MEASURE; break; case NOTE_TYPE_48TH: case NOTE_TYPE_192ND: case NoteType_Invalid: // since, for whatever reason, the only way to do // 48ths is through a block of 192nds... f.Write( "`" ); fCurrentIncrementer = 1.0/192 * BEATS_PER_MEASURE; break; default: ASSERT_M(0, ssprintf("nt = %d",nt) ); break; } double fFirstBeatInMeasure = m * BEATS_PER_MEASURE; double fLastBeatInMeasure = (m+1) * BEATS_PER_MEASURE; for( double b=fFirstBeatInMeasure; b<=fLastBeatInMeasure-1/64.0f; b+=fCurrentIncrementer ) // need the -0.0001 to account for rounding errors { int row = BeatToNoteRow( (float)b ); RString str; switch( out.m_StepsType ) { case StepsType_dance_single: case StepsType_dance_couple: case StepsType_dance_double: str = NotesToDWIString( notedata.GetTapNote(start+0, row), notedata.GetTapNote(start+1, row), notedata.GetTapNote(start+2, row), notedata.GetTapNote(start+3, row) ); // Blank out the notes so we don't write them again if the incrementer is small notedata.SetTapNote(start+0, row, TAP_EMPTY); notedata.SetTapNote(start+1, row, TAP_EMPTY); notedata.SetTapNote(start+2, row, TAP_EMPTY); notedata.SetTapNote(start+3, row, TAP_EMPTY); break; case StepsType_dance_solo: str = NotesToDWIString( notedata.GetTapNote(0, row), notedata.GetTapNote(1, row), notedata.GetTapNote(2, row), notedata.GetTapNote(3, row), notedata.GetTapNote(4, row), notedata.GetTapNote(5, row) ); // Blank out the notes so we don't write them again if the incrementer is small notedata.SetTapNote(start+0, row, TAP_EMPTY); notedata.SetTapNote(start+1, row, TAP_EMPTY); notedata.SetTapNote(start+2, row, TAP_EMPTY); notedata.SetTapNote(start+3, row, TAP_EMPTY); notedata.SetTapNote(start+4, row, TAP_EMPTY); notedata.SetTapNote(start+5, row, TAP_EMPTY); break; default: ASSERT(0); // not a type supported by DWI. We shouldn't have called in here if that's the case } f.Write( str ); } switch( nt ) { case NOTE_TYPE_4TH: case NOTE_TYPE_8TH: break; case NOTE_TYPE_12TH: case NOTE_TYPE_24TH: f.Write( "]" ); break; case NOTE_TYPE_16TH: f.Write( ")" ); break; case NOTE_TYPE_32ND: case NOTE_TYPE_64TH: f.Write( "}" ); break; case NOTE_TYPE_48TH: case NOTE_TYPE_192ND: case NoteType_Invalid: f.Write( "'" ); break; default: ASSERT(0); // fall though } f.PutLine( "" ); } }
void NotesWriterSM::WriteGlobalTags( RageFile &f, const Song &out ) { f.PutLine( ssprintf( "#TITLE:%s;", out.m_sMainTitle.c_str() ) ); f.PutLine( ssprintf( "#SUBTITLE:%s;", out.m_sSubTitle.c_str() ) ); f.PutLine( ssprintf( "#ARTIST:%s;", out.m_sArtist.c_str() ) ); f.PutLine( ssprintf( "#TITLETRANSLIT:%s;", out.m_sMainTitleTranslit.c_str() ) ); f.PutLine( ssprintf( "#SUBTITLETRANSLIT:%s;", out.m_sSubTitleTranslit.c_str() ) ); f.PutLine( ssprintf( "#ARTISTTRANSLIT:%s;", out.m_sArtistTranslit.c_str() ) ); f.PutLine( ssprintf( "#CREDIT:%s;", out.m_sCredit.c_str() ) ); f.PutLine( ssprintf( "#BANNER:%s;", out.m_sBannerFile.c_str() ) ); f.PutLine( ssprintf( "#BACKGROUND:%s;", out.m_sBackgroundFile.c_str() ) ); f.PutLine( ssprintf( "#LYRICSPATH:%s;", out.m_sLyricsFile.c_str() ) ); f.PutLine( ssprintf( "#CDTITLE:%s;", out.m_sCDTitleFile.c_str() ) ); f.PutLine( ssprintf( "#MUSIC:%s;", out.m_sMusicFile.c_str() ) ); f.PutLine( ssprintf( "#OFFSET:%.3f;", out.m_Timing.m_fBeat0OffsetInSeconds ) ); f.PutLine( ssprintf( "#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds ) ); f.PutLine( ssprintf( "#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds ) ); f.Write( "#SELECTABLE:" ); switch(out.m_SelectionDisplay) { default: ASSERT(0); /* fallthrough */ case Song::SHOW_ALWAYS: f.Write( "YES" ); break; case Song::SHOW_NEVER: f.Write( "NO" ); break; case Song::SHOW_ROULETTE: f.Write( "ROULETTE" ); break; } f.PutLine( ";" ); switch( out.m_DisplayBPMType ) { case Song::DISPLAY_ACTUAL: // write nothing break; case Song::DISPLAY_SPECIFIED: if( out.m_fSpecifiedBPMMin == out.m_fSpecifiedBPMMax ) f.PutLine( ssprintf( "#DISPLAYBPM:%.3f;", out.m_fSpecifiedBPMMin ) ); else f.PutLine( ssprintf( "#DISPLAYBPM:%.3f:%.3f;", out.m_fSpecifiedBPMMin, out.m_fSpecifiedBPMMax ) ); break; case Song::DISPLAY_RANDOM: f.PutLine( ssprintf( "#DISPLAYBPM:*;" ) ); break; } f.Write( "#BPMS:" ); unsigned i; for( i=0; i<out.m_Timing.m_BPMSegments.size(); i++ ) { const BPMSegment &bs = out.m_Timing.m_BPMSegments[i]; f.Write( ssprintf( "%.3f=%.3f", bs.m_fStartBeat, bs.m_fBPM ) ); if( i != out.m_Timing.m_BPMSegments.size()-1 ) f.Write( "," ); } f.PutLine( ";" ); f.Write( "#STOPS:" ); for( i=0; i<out.m_Timing.m_StopSegments.size(); i++ ) { const StopSegment &fs = out.m_Timing.m_StopSegments[i]; f.PutLine( ssprintf( "%.3f=%.3f", fs.m_fStartBeat, fs.m_fStopSeconds ) ); if( i != out.m_Timing.m_StopSegments.size()-1 ) f.Write( "," ); } f.PutLine( ";" ); f.Write( "#BGCHANGES:" ); for( i=0; i<out.m_BackgroundChanges.size(); i++ ) { const BackgroundChange &seg = out.m_BackgroundChanges[i]; f.PutLine( ssprintf( "%.3f=%s=%.3f=%d=%d=%d,", seg.m_fStartBeat, seg.m_sBGName.c_str(), seg.m_fRate, seg.m_bFadeLast, seg.m_bRewindMovie, seg.m_bLoop ) ); } /* If there's an animation plan at all, add a dummy "-nosongbg-" tag to indicate that * this file doesn't want a song BG entry added at the end. See SMLoader::TidyUpData. * This tag will be removed on load. Add it at a very high beat, so it won't cause * problems if loaded in older versions. */ if( !out.m_BackgroundChanges.empty() ) f.PutLine( "99999=-nosongbg-=1.000=0=0=0 // don't automatically add -songbackground-" ); f.PutLine( ";" ); if( out.m_ForegroundChanges.size() ) { f.Write( "#FGCHANGES:" ); for( i=0; i<out.m_ForegroundChanges.size(); i++ ) { const BackgroundChange &seg = out.m_ForegroundChanges[i]; f.PutLine( ssprintf( "%.3f=%s=%.3f=%d=%d=%d", seg.m_fStartBeat, seg.m_sBGName.c_str(), seg.m_fRate, seg.m_bFadeLast, seg.m_bRewindMovie, seg.m_bLoop ) ); if( i != out.m_ForegroundChanges.size()-1 ) f.Write( "," ); } f.PutLine( ";" ); } }
//======================================================== // Name : GetXML // Desc : convert plain xml text from parsed xml node // Param : // Return : converted plain string //-------------------------------------------------------- // Coder Date Desc // bro 2002-10-29 //======================================================== bool XNode::GetXML( RageFile &f, DISP_OPT *opt /*= &optDefault*/ ) { // tab if( opt && opt->newline ) { if( opt && opt->newline ) if( f.Write("\r\n") == -1 ) return false; if( opt->write_tabs ) for( int i = 0 ; i < opt->tab_base ; i++) if( f.Write("\t") == -1 ) return false; } // <TAG if( f.Write("<" + name) == -1 ) return false; // <TAG Attr1="Val1" if( !attrs.empty() ) if( f.Write(" ") == -1 ) return false; for( unsigned i = 0 ; i < attrs.size(); i++ ) if( !attrs[i]->GetXML(f, opt) ) return false; if( childs.empty() && value.empty() ) { // <TAG Attr1="Val1"/> alone tag if( f.Write("/>") == -1 ) return false; } else { // <TAG Attr1="Val1"> and get child if( f.Write(">") == -1 ) return false; if( opt && opt->newline && !childs.empty() ) { opt->tab_base++; } for( unsigned i = 0 ; i < childs.size(); i++ ) if( !childs[i]->GetXML( f, opt ) ) return false; // Text Value if( value != ("") ) { if( opt && opt->newline && !childs.empty() ) { if( opt && opt->newline ) if( f.Write("\r\n") == -1 ) return false; if( opt->write_tabs ) for( int i = 0 ; i < opt->tab_base ; i++) if( f.Write("\t") == -1 ) return false; } if( f.Write((opt->reference_value&&opt->entitys?opt->entitys->Entity2Ref(value):value)) == -1 ) return false; } // </TAG> CloseTag if( opt && opt->newline && !childs.empty() ) { if( f.Write("\r\n") == -1 ) return false; if( opt->write_tabs ) for( int i = 0 ; i < opt->tab_base-1 ; i++) if( f.Write("\t") == -1 ) return false; } if( f.Write("</" + name + ">") == -1 ) return false; if( opt && opt->newline ) { if( !childs.empty() ) opt->tab_base--; } } return true; }
//======================================================== // Name : GetXML // Desc : convert plain xml text from parsed xml attirbute // Param : // Return : converted plain string //-------------------------------------------------------- // Coder Date Desc // bro 2002-10-29 //======================================================== bool XAttr::GetXML( RageFile &f, DISP_OPT *opt /*= &optDefault*/ ) { return f.Write(name + "='" + (opt->reference_value&&opt->entitys?opt->entitys->Entity2Ref(value):value) + "' ") != -1; }