void ReadMetadata (GString line, OsuLoadInfo* Info) { auto Command = line.substr(0, line.find_first_of(":")); // Lines are Information:Content auto Content = line.substr(line.find_first_of(":") + 1, line.length() - line.find_first_of(":")); #ifdef VERBOSE_DEBUG printf("Command found: %s | Contents: %s\n", Command.c_str(), Content.c_str()); #endif Utility::Trim(Content); if (Command == "Title") { Info->OsuSong->SongName = Content; }else if (Command == "Artist") { Info->OsuSong->SongAuthor = Content; }else if (Command == "Version") { Info->Diff->Name = Content; }else if (Command == "TitleUnicode") { if (Content.length() > 1) Info->OsuSong->SongName = Content; }else if (Command == "ArtistUnicode") { if (Content.length() > 1) Info->OsuSong->SongAuthor = Content; } else if (Command == "Creator") { Info->Diff->Author = Content; } }
bool ReadGeneral (GString line, OsuLoadInfo* Info) { GString Command = line.substr(0, line.find_first_of(" ")); // Lines are Information:<space>Content GString Content = line.substr(line.find_first_of(":") + 1); Content = Content.substr(Content.find_first_not_of(" ")); if (Command == "AudioFilename:") { if (Content == "virtual") { Info->Diff->IsVirtual = true; return true; } else { #ifdef VERBOSE_DEBUG printf("Audio filename found: %s\n", Content.c_str()); #endif Utility::Trim(Content); Info->OsuSong->SongFilename = Content; Info->OsuSong->SongPreviewSource = Content; } }else if (Command == "Mode:") { Info->ReadAModeTag = true; if (Content != "3") // It's not a osu!mania chart, so we can't use it. return false; }else if (Command == "SampleSet:") { Utility::ToLower(Content); Utility::Trim(Content); Info->DefaultSampleset = Content; } else if (Command == "PreviewTime:") { if (Content != "-1") { if (Info->OsuSong->PreviewTime == 0) Info->OsuSong->PreviewTime = latof(Content) / 1000; } } else if (Command == "SpecialStyle:") { if (Content == "1") Info->Diff->Data->Turntable = true; } return true; }
GString SP2::GGeneralEventHandler::ReplaceNextPattern(GString in_sSentence, GString in_ReplacingString, GString in_sPattern) const { UINT32 l_iCurrentPosition = 0; UINT32 l_iStartPosition = 0; bool l_bSuccess = false; for(UINT32 i=0; i<in_sSentence.size(); i++) { if(in_sSentence.at(i) == in_sPattern.at(l_iCurrentPosition)) { if(l_iCurrentPosition == 0) l_iStartPosition = i; l_iCurrentPosition++; if(l_iCurrentPosition == in_sPattern.size()) { l_bSuccess = true; break; } } else { if(l_iCurrentPosition > 0) { l_iCurrentPosition = 0; i = l_iStartPosition + 1; } } } if(l_bSuccess) { GString l_Results; l_Results += in_sSentence.substr(0,l_iStartPosition); l_Results += in_ReplacingString; l_Results += in_sSentence.substr(l_iStartPosition+in_sPattern.size(),in_sSentence.size()); return l_Results; } return L""; }
void ReadDifficulty (GString line, OsuLoadInfo* Info) { GString Command = line.substr(0, line.find_first_of(":")); // Lines are Information:Content GString Content = line.substr(line.find_first_of(":") + 1, line.length() - line.find_first_of(":")); Utility::Trim(Content); // We ignore everything but the key count! if (Command == "CircleSize") { Info->Diff->Channels = atoi(Content.c_str()); }else if (Command == "SliderMultiplier") { Info->SliderVelocity = latof(Content.c_str()) * 100; } else if (Command == "HPDrainRate") { Info->TimingInfo->HP = latof(Content.c_str()); } else if (Command == "OverallDifficulty") { Info->TimingInfo->OD = latof(Content.c_str()); } }
bool LoadTracksSM(Song *Out, Difficulty *Diff, GString line) { GString CommandContents = line.substr(line.find_first_of(":") + 1); /* Remove newlines and comments */ CommandContents = RemoveComments(CommandContents); /* Split contents */ auto Mainline = Utility::TokenSplit(CommandContents, ":"); if (Mainline.size() < 6) // No, like HELL I'm loading this. { // The first time I found this it was because a ; was used as a separator instead of a : // Which means a rewrite is what probably should be done to fix that particular case. wprintf(L"Corrupt simfile (%d entries instead of 6)", Mainline.size()); return false; } /* What we'll work with */ GString NoteString = Mainline[5]; int Keys = GetTracksByMode(Mainline[0]); if (!Keys) return false; Diff->Level = atoi(Mainline[3].c_str()); Diff->Channels = Keys; Diff->Name = Mainline[2] + "(" + Mainline[0] + ")"; /* Now we should have our notes within NoteGString. We'll split them by measure using , as a separator.*/ auto MeasureText = Utility::TokenSplit(NoteString); LoadNotesSM(Out, Diff, MeasureText); /* Through here we can make a few assumptions. ->The measures are in order from start to finish ->Each measure has all potential playable tracks, even if that track is empty during that measure. ->Measures are internally ordered */ return true; }
GCallStack::GCallStack(HANDLE hThread, CONTEXT& c) { if (!_bLockInit) // only init the single instance of the CRITICAL_SECTION 1 time for the many instances of GCallStack { InitializeCriticalSection(&_DbgHelpLock); _bLockInit = true; } DWORD imageType = IMAGE_FILE_MACHINE_I386; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); int frameNum = 0; // counts walked frames int MAX_STACK_FRAMES = 7777; // in C# the maximum stack frames imposed by the language is 1000. Arbitrary limit to guarantee no condition of infinate walking in corrupted memory. DWORD offsetFromLine; // tells us line number in the source file #if defined(_LINUX64) || defined(_WIN64) || defined(_IOS) unsigned __int64 offsetFromSymbol; // tells us how far from the symbol we were #else DWORD offsetFromSymbol; // tells us how far from the symbol we were #endif DWORD symOptions; // symbol handler settings IMAGEHLP_SYMBOL *pSym = (IMAGEHLP_SYMBOL *) malloc( IMGSYMLEN + MAXNAMELEN ); GString strStackName(MAXNAMELEN + 512); // undecorated method/function name + Source file and line number IMAGEHLP_MODULE Module; IMAGEHLP_LINE Line; STACKFRAME64 s; // in/out stackframe memset( &s, '\0', sizeof s ); // note: converted code from [std::string symSearchPath] to [GString symSearchPath] so it will compile with the _UNICODE build flag - 8/18/2014 GString symSearchPath; #ifdef _UNICODE wchar_t *tt = 0, *p; tt = new wchar_t[TTBUFLEN]; #else char *tt = 0, *p; tt = new char[TTBUFLEN]; #endif // build symbol search path from: symSearchPath = ""; // current directory if (GetCurrentDirectory(TTBUFLEN, tt)) symSearchPath << tt << "; "; // dir with executable if ( GetModuleFileName( 0, tt, TTBUFLEN ) ) { #ifdef _UNICODE for (p = tt + wcslen(tt) - 1; p >= tt; --p) #else for (p = tt + strlen(tt) - 1; p >= tt; --p) // VC6 does not have a _tcsclen() and we still support VC6 #endif { // locate the rightmost path separator if ( *p == '\\' || *p == '/' || *p == ':' ) break; } // if we found one, p is pointing at it; if not, tt only contains an exe name (no path), and p points before its first byte if ( p != tt ) // path sep found? { if ( *p == ':' ) // we leave colons in place ++ p; *p = '\0'; // eliminate the exe name and last path sep symSearchPath << tt << "; "; } } // environment variable _NT_SYMBOL_PATH GString g("_NT_SYMBOL_PATH"); if (GetEnvironmentVariable(g, tt, TTBUFLEN)) symSearchPath << tt << "; "; // environment variable _NT_ALTERNATE_SYMBOL_PATH g = "_NT_ALTERNATE_SYMBOL_PATH"; if (GetEnvironmentVariable(g, tt, TTBUFLEN)) symSearchPath << tt << "; "; // environment variable SYSTEMROOT g = "SYSTEMROOT"; if (GetEnvironmentVariable(g, tt, TTBUFLEN)) symSearchPath << tt << "; "; if ( symSearchPath.size() > 0 ) // if we added anything, we have a trailing semicolon symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 ); // 8/20/2014 note: In older Windows API's SymInitialize()'s 2nd argument was not defined as "const char *", it was only "char *" // Although "const" was not defined, the API call is "const" in behavior. In newer versions of the Windows API this has been fixed. // In newer versions - SymInitialize's 2nd argument may resolve to either "const char *" OR "const wchar_t *", and in those builds the // GString has a default conversion to the correct string type, however in the older build configurations, GString does not (and should not) // know how to resolve to a "char *" by default, so in that case the preprocessor directive isolates the code needed to convert to "char *" #if defined(_MSC_VER) && _MSC_VER <= 1200 if (!SymInitialize(hProcess, symSearchPath.Buf(), false)) // symSearchPath == (char *) #else if (!SymInitialize(hProcess, symSearchPath, true)) // symSearchPath == (const char *) --OR-- (const wchar_t *) depending on the _UNICODE preprocessor definition #endif { goto tagCleanUp; } symOptions = SymGetOptions(); symOptions |= SYMOPT_LOAD_LINES; symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions ); enumAndLoadModuleSymbols( hProcess, GetCurrentProcessId() ); // init STACKFRAME for first call, definitions found in ImageHlp.h #ifdef _M_IX86 imageType = IMAGE_FILE_MACHINE_I386; s.AddrPC.Offset = c.Eip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Ebp; s.AddrFrame.Mode = AddrModeFlat; s.AddrStack.Offset = c.Esp; s.AddrStack.Mode = AddrModeFlat; #elif _M_X64 imageType = IMAGE_FILE_MACHINE_AMD64; s.AddrPC.Offset = c.Rip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Rsp; s.AddrFrame.Mode = AddrModeFlat; s.AddrStack.Offset = c.Rsp; s.AddrStack.Mode = AddrModeFlat; #elif _M_IA64 imageType = IMAGE_FILE_MACHINE_IA64; s.AddrPC.Offset = c.StIIP; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.IntSp; s.AddrFrame.Mode = AddrModeFlat; s.AddrBStore.Offset = c.RsBSP; s.AddrBStore.Mode = AddrModeFlat; s.AddrStack.Offset = c.IntSp; s.AddrStack.Mode = AddrModeFlat; #endif memset( pSym, '\0', IMGSYMLEN + MAXNAMELEN ); pSym->SizeOfStruct = IMGSYMLEN; pSym->MaxNameLength = MAXNAMELEN; memset( &Line, '\0', sizeof Line ); Line.SizeOfStruct = sizeof Line; memset( &Module, '\0', sizeof Module ); Module.SizeOfStruct = sizeof Module; offsetFromSymbol = 0; // DbgHelp is single threaded, so acquire a lock. EnterCriticalSection(&_DbgHelpLock); while ( frameNum < MAX_STACK_FRAMES ) { // get next stack frame (StackWalk(), SymFunctionTableAccess(), SymGetModuleBase()) // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can // assume that either you are done, or that the stack is so hosed that the next deeper frame could not be found. #ifdef _WIN64 if (!StackWalk64(imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) #else if (!StackWalk(imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL)) #endif break; // Maybe it failed, maybe we have finished walking the stack if ( s.AddrPC.Offset != 0 ) { // Most likely a valid stack rame // show procedure info if ( ! SymGetSymFromAddr64( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) ) { break; } else { // UnDecorateSymbolName() to get the Class::Method or function() name in tyhe callstack strStackName.Empty(); UnDecorateSymbolName(pSym->Name, strStackName._str, MAXNAMELEN, UNDNAME_COMPLETE); strStackName.SetLength(strlen(strStackName._str)); // SymGetLineFromAddr() to get the source.cpp and the line number IMAGEHLP_LINE64 Line; if (SymGetLineFromAddr64(hProcess, s.AddrPC.Offset, &offsetFromLine, &Line) != FALSE) { GString g(Line.FileName); // Line.FileName conains the "c:\Full\Path\TO\Source.cpp" // Builds string "Foo::Bar[Source.cpp]@777" strStackName << "[" << g.StartingAt(g.ReverseFind("\\") + 1) << "]@" << Line.LineNumber; } // add the GString to the GStringList, do not add frame 0 because it will always be GException::GSeception where we divided by 0 if (frameNum > 0) _stk += strStackName; } } else { // base reached SetLastError(0); break; } ++frameNum; } LeaveCriticalSection(&_DbgHelpLock); // de-init symbol handler etc. (SymCleanup()) SymCleanup( hProcess ); free( pSym ); tagCleanUp:; delete [] tt; CloseHandle(hProcess); }
shared_ptr<osb::SpriteList> ReadOSBEvents(std::istream& event_str) { auto list = make_shared<osb::SpriteList>(); int previous_lead = 100; shared_ptr<osb::BGASprite> sprite = nullptr; shared_ptr<osb::Loop> loop = nullptr; bool readingLoop = false; GString line; while (std::getline(event_str, line)) { int lead_spaces; line = line.substr(line.find("//")); // strip comments lead_spaces = line.find_first_not_of("\t _"); line = line.substr(lead_spaces, line.length() - lead_spaces + 1); vector<GString> split_result; boost::split(split_result, line, boost::is_any_of(",")); for (auto &&s : split_result) boost::algorithm::to_lower(s); if (!line.length() || !split_result.size()) continue; if (lead_spaces < previous_lead && !readingLoop) { if (split_result[0] == "sprite") { Vec2 new_position(latof(split_result[3]), latof(split_result[4])); sprite = make_shared<osb::BGASprite>(split_result[1], OriginFromString(split_result[2]), new_position); list->push_back(sprite); } } else { if (!sprite) throw std::runtime_error("OSB command unpaired with sprite."); // If it's a loop, check if we're out of it. // If we're out of it, read a regular event, otherwise, read an event to the loop if (readingLoop) { if (lead_spaces < previous_lead) { readingLoop = false; // We're done reading the loop - unroll it. auto loop_events = loop->Unroll(); for (auto i = 0; i < osb::EVT_COUNT; i++) for (auto evt : (*loop_events)[i]) sprite->AddEvent(evt); } else loop->AddEvent(ParseEvent(split_result)); } // It's not a command on the loop, or we weren't reading a loop in the first place. // Read a regular command. // Not "else" because we do want to execute this if we're no longer reading the loop. if (!readingLoop) { auto ev = ParseEvent(split_result); // A loop began - set that we are reading a loop and set this loop as where to add the following commands. if (ev->GetEventType() == osb::EVT_LOOP) { loop = static_pointer_cast<osb::Loop>(ev); readingLoop = true; }else // add this event, if not a loop to this sprite. It'll be unrolled once outside. sprite->AddEvent(ev); } } previous_lead = lead_spaces; } return list; }
GString RemoveExtension(GString Fn) { return Fn.substr(0, Fn.find_last_of(".")); }
GString RelativeToPath(GString Filename) { return Filename.substr(Filename.find_last_of("/")); }
GString GetExtension(GString Filename) { return Filename.substr(Filename.find_last_of(".")+1); }
void LoadNotes(Song* Out, Difficulty * Diff, GString line) { // get the object GString (all between a colon and a semicolon. GString objectString = line.substr(line.find_first_of(":") + 1); std::vector< GString > splitvec; bool invert = false; Diff->Name = Out->SongName; // todo: change this. Diff->TotalNotes = Diff->TotalHolds = Diff->TotalObjects = 0; // Remove whitespace. Utility::ReplaceAll(objectString, "[\n\r]", ""); splitvec = Utility::TokenSplit(objectString); // Separate measures! for(GString objectlist: splitvec) // for each measure { std::vector< GString > splitobjects; Measure Msr; invert = false; if ( objectlist.length() == 0 ) { Diff->Measures.push_back(Msr); continue; } /* Mirror command. */ if ( objectlist[0] == 'M') { invert = true; Utility::ReplaceAll(objectlist, "M", ""); } splitobjects = Utility::TokenSplit(objectlist, "{}", true); size_t SoSize = 0; size_t CurObj = 0; for(GString object_description: splitobjects) // Count total valid objects { if (object_description.length() != 0) SoSize += 1; } for(GString object_description: splitobjects) // For all objects in measure { std::vector< GString > object_parameters; if (object_description.length() == 0) // we must have at least a plain "0" continue; object_parameters = Utility::TokenSplit(object_description, " :"); if (object_parameters.size() > 0) // We got a position { int32 xpos = 0; float hold_duration = 0; int32 sound = 0; if (object_parameters[0].length() > 0) // does it have length? xpos = latof (object_parameters[0].c_str()); // assign it if (object_parameters.size() > 1) // We got a hold note parameter { if (object_parameters[1].length() > 0) // length? hold_duration = latof (object_parameters[1].c_str()); // load it in if (object_parameters.size() > 2) // We got a sound parameter { if (object_parameters[2].length() > 0) // got a valid sound? sound = latof (object_parameters[2].c_str()); // cast it in } } if (invert) { if (xpos != 0) xpos = PlayfieldWidth - xpos; } GameObject Temp; if (xpos != 0) { Temp.SetPositionX(xpos); Diff->TotalObjects++; if (hold_duration) Diff->TotalHolds++; else Diff->TotalNotes++; } else { /* Position 0 is a special X constant that will make the note invisible as well as making it not emit any kind of judgment in-game. It's filler. */ Temp.SetPositionX(0); } Temp.Assign(hold_duration, Diff->Measures.size(), (double)CurObj / SoSize); Msr.push_back(Temp); } // got a position CurObj++; } // foreach object in measure Diff->Measures.push_back(Msr); } // foreach measure Out->Difficulties.push_back(Diff); }
Song* NoteLoader::LoadObjectsFromFile(GString filename, GString prefix) { std::ifstream filein; filein.open(filename.c_str(), std::ios::in); Song *Out = new Song(); Difficulty *Diff = new Difficulty(); if (!filein.is_open()) { throw std::exception(Utility::Format("Unable to open %s for reading!", filename.c_str()).c_str()); } Out->SongDirectory = prefix; // get lines separating with ; token GString line; while (filein) { std::getline(filein, line, ';'); GString command = line.substr(0, line.find_first_of(":")); #define OnCommand(x) if(command.find(#x)!=GString::npos) GString CommandContents = line.substr(line.find_first_of(":") + 1); // First, metadata. OnCommand(#NAME) { Out->SongName = CommandContents; } OnCommand(#AUTHOR) { Out->SongAuthor = CommandContents; } OnCommand(#MLEN) { std::stringstream str (CommandContents); str >> Out->MeasureLength; } // Then, Timing data. OnCommand(#BPM) { LoadTimingList(Diff->Timing, line); } OnCommand(#OFFSET) { std::stringstream str (CommandContents); str >> Diff->Offset; Diff->Offset += Configuration::GetConfigf("OffsetDC"); } // Then, file info. OnCommand(#SONG) { Out->SongFilename = CommandContents; } OnCommand(#BACKGROUNDIMAGE) { Out->BackgroundFilename = CommandContents; } OnCommand(#LEADIN) { std::stringstream str (CommandContents); str >> Out->LeadInTime; } OnCommand(#SOUNDS) { vector<GString> SoundList; GString CmdLine = CommandContents; // Diff->SoundList = Utility::TokenSplit(CmdLine, ","); } // Then, the charts. OnCommand(#NOTES) // current command is notes? { LoadNotes(Out, Diff, line); Diff = new Difficulty(); }// command == #notes #undef OnCommand } delete Diff; // There will always be an extra copy. // at this point the objects are sorted! by measure and within the measure, by fraction. Out->Process(); return Out; }