static bool ReadBMSFile( const RString &sPath, NameToData_t &mapNameToData ) { RageFile file; if( !file.Open(sPath) ) { LOG->UserLog( "Song file", sPath, "couldn't be opened: %s", file.GetError().c_str() ); return false; } while( !file.AtEOF() ) { RString line; if( file.GetLine(line) == -1 ) { LOG->UserLog( "Song file", sPath, "had a read error: %s", file.GetError().c_str() ); return false; } StripCrnl( line ); // BMS value names can be separated by a space or a colon. size_t iIndexOfSeparator = line.find_first_of( ": " ); RString value_name = line.substr( 0, iIndexOfSeparator ); RString value_data; if( iIndexOfSeparator != line.npos ) value_data = line.substr( iIndexOfSeparator+1 ); value_name.MakeLower(); mapNameToData.insert( make_pair(value_name, value_data) ); } return true; }
CString CryptManager::GetMD5( CString fn ) { struct MD5Context md5c; unsigned char digest[16]; int iBytesRead; unsigned char buffer[1024]; RageFile file; if( !file.Open( fn, RageFile::READ ) ) { LOG->Warn( "GetMD5: Failed to open file '%s'", fn.c_str() ); return ""; } MD5Init(&md5c); while( !file.AtEOF() && file.GetError().empty() ) { iBytesRead = file.Read( buffer, sizeof(buffer) ); MD5Update(&md5c, buffer, iBytesRead); } MD5Final(digest, &md5c); return BinaryToHex( digest, sizeof(digest) ); }
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(); } }
void MemoryCardDriverThreaded_Linux::GetUSBStorageDevices( vector<UsbStorageDevice>& vDevicesOut ) { LOG->Trace( "GetUSBStorageDevices" ); vDevicesOut.clear(); { vector<RString> asDevices; RString sBlockDevicePath = "/sys/block/"; GetFileList( sBlockDevicePath, asDevices ); for( unsigned i = 0; i < asDevices.size(); ++i ) { const RString &sDevice = asDevices[i]; if( sDevice == "." || sDevice == ".." ) continue; UsbStorageDevice usbd; RString sPath = sBlockDevicePath + sDevice + "/"; usbd.sSysPath = sPath; /* Ignore non-removable devices. */ RString sBuf; if( !ReadFile( sPath + "removable", sBuf ) ) continue; // already warned if( atoi(sBuf) != 1 ) continue; /* * The kernel isn't exposing all of /sys atomically, so we end up missing * the partition due to it not being shown yet. It won't show up until the * kernel has scanned the partition table, which can take a variable amount * of time, sometimes over a second. Watch for the "queue" sysfs directory, * which is created after this, to tell when partition directories are created. */ RageTimer WaitUntil; WaitUntil += 5; RString sQueueFilePath = usbd.sSysPath + "queue"; while(1) { if( WaitUntil.Ago() >= 0 ) { LOG->Warn( "Timed out waiting for %s", sQueueFilePath.c_str() ); break; } if( access(usbd.sSysPath, F_OK) == -1 ) { LOG->Warn( "Block directory %s went away while we were waiting for %s", usbd.sSysPath.c_str(), sQueueFilePath.c_str() ); break; } if( access(sQueueFilePath, F_OK) != -1 ) break; usleep(10000); } /* Wait for udev to finish handling device node creation */ ExecuteCommand( "udevadm settle" ); /* If the first partition device exists, eg. /sys/block/uba/uba1, use it. */ if( access(usbd.sSysPath + sDevice + "1", F_OK) != -1 ) { LOG->Trace("OK"); usbd.sDevice = "/dev/" + sDevice + "1"; } else { LOG->Trace("error %s", strerror(errno)); usbd.sDevice = "/dev/" + sDevice; } /* * sPath/device should be a symlink to the actual device. For USB * devices, it looks like this: * * device -> ../../devices/pci0000:00/0000:00:02.1/usb2/2-1/2-1:1.0 * * "2-1" is "bus-port". */ char szLink[256]; int iRet = readlink( sPath + "device", szLink, sizeof(szLink) ); if( iRet == -1 ) { LOG->Warn( "readlink(\"%s\"): %s", (sPath + "device").c_str(), strerror(errno) ); } else { /* * The full path looks like * * ../../devices/pci0000:00/0000:00:02.1/usb2/2-2/2-2.1/2-2.1:1.0 * * In newer kernels, it looks like: * * ../../../3-2.1:1.0 * * Each path element refers to a new hop in the chain. * "usb2" = second USB host * 2- second USB host, * -2 port 1 on the host, * .1 port 1 on an attached hub * .2 ... port 2 on the next hub ... * * We want the bus number and the port of the last hop. The level is * the number of hops. */ szLink[iRet] = 0; vector<RString> asBits; split( szLink, "/", asBits ); RString sHostPort = asBits[asBits.size()-1]; if( !sHostPort.empty() ) { /* Strip off the endpoint information after the colon. */ size_t pos = sHostPort.find(':'); if( pos != string::npos ) sHostPort.erase( pos ); /* sHostPort is eg. 2-2.1. */ sHostPort.Replace( "-", "." ); asBits.clear(); split( sHostPort, ".", asBits ); if( asBits.size() > 1 ) { usbd.iBus = atoi( asBits[0] ); usbd.iPort = atoi( asBits[asBits.size()-1] ); usbd.iLevel = asBits.size() - 1; } } } if( ReadFile( sPath + "device/../idVendor", sBuf ) ) sscanf( sBuf, "%x", &usbd.idVendor ); if( ReadFile( sPath + "device/../idProduct", sBuf ) ) sscanf( sBuf, "%x", &usbd.idProduct ); if( ReadFile( sPath + "device/../serial", sBuf ) ) { usbd.sSerial = sBuf; TrimRight( usbd.sSerial ); } if( ReadFile( sPath + "device/../product", sBuf ) ) { usbd.sProduct = sBuf; TrimRight( usbd.sProduct ); } if( ReadFile( sPath + "device/../manufacturer", sBuf ) ) { usbd.sVendor = sBuf; TrimRight( usbd.sVendor ); } vDevicesOut.push_back( usbd ); } } { // Find where each device is mounted. Output looks like: // /dev/sda1 /mnt/flash1 auto noauto,owner 0 0 // /dev/sdb1 /mnt/flash2 auto noauto,owner 0 0 // /dev/sdc1 /mnt/flash3 auto noauto,owner 0 0 RString fn = "/rootfs/etc/fstab"; RageFile f; if( !f.Open(fn) ) { LOG->Warn( "can't open '%s': %s", fn.c_str(), f.GetError().c_str() ); return; } RString sLine; while( !f.AtEOF() ) { switch( f.GetLine(sLine) ) { case 0: continue; /* eof */ case -1: LOG->Warn( "error reading '%s': %s", fn.c_str(), f.GetError().c_str() ); return; } char szScsiDevice[1024]; char szMountPoint[1024]; int iRet = sscanf( sLine, "%s %s", szScsiDevice, szMountPoint ); if( iRet != 2 || szScsiDevice[0] == '#') continue; // don't process this line /* Get the real kernel device name, which should match * the name from /sys/block, by following symlinks in * /dev. This allows us to specify persistent names in * /etc/fstab using things like /dev/device/by-path. */ char szUnderlyingDevice[PATH_MAX]; if( realpath(szScsiDevice, szUnderlyingDevice) == NULL ) { // "No such file or directory" is understandable if (errno != ENOENT) LOG->Warn( "realpath(\"%s\"): %s", szScsiDevice, strerror(errno) ); continue; } RString sMountPoint = szMountPoint; TrimLeft( sMountPoint ); TrimRight( sMountPoint ); // search for the mountpoint corresponding to the device for( unsigned i=0; i<vDevicesOut.size(); i++ ) { UsbStorageDevice& usbd = vDevicesOut[i]; if( usbd.sDevice == szUnderlyingDevice ) // found our match { // Use the device entry from fstab so the mount command works usbd.sDevice = szScsiDevice; usbd.sOsMountDir = sMountPoint; break; // stop looking for a match } } } } for( unsigned i=0; i<vDevicesOut.size(); i++ ) { UsbStorageDevice& usbd = vDevicesOut[i]; LOG->Trace( " sDevice: %s, iBus: %d, iLevel: %d, iPort: %d, id: %04X:%04X, Vendor: '%s', Product: '%s', sSerial: \"%s\", sOsMountDir: %s", usbd.sDevice.c_str(), usbd.iBus, usbd.iLevel, usbd.iPort, usbd.idVendor, usbd.idProduct, usbd.sVendor.c_str(), usbd.sProduct.c_str(), usbd.sSerial.c_str(), usbd.sOsMountDir.c_str() ); } /* Remove any devices that we couldn't find a mountpoint for. */ for( unsigned i=0; i<vDevicesOut.size(); i++ ) { UsbStorageDevice& usbd = vDevicesOut[i]; if( usbd.sOsMountDir.empty() ) { LOG->Trace( "Ignoring %s (couldn't find in /etc/fstab)", usbd.sDevice.c_str() ); vDevicesOut.erase( vDevicesOut.begin()+i ); --i; } } LOG->Trace( "Done with GetUSBStorageDevices" ); }
void TitleSubst::Load(const CString &filename, const CString §ion) { RageFile f; if( !f.Open(filename) ) { LOG->Trace("Error opening %s: %s", filename.c_str(), f.GetError().c_str() ); return; } CString CurrentSection; TitleTrans tr; while (!f.AtEOF()) { CString line; int ret = f.GetLine( line ); if( ret == 0 ) break; if( ret < 0 ) { LOG->Trace("Error reading %s: %s", filename.c_str(), f.GetError().c_str() ); break; } if(line.size() > 0 && utf8_get_char(line.c_str()) == 0xFEFF) { /* Annoying header that Windows puts on UTF-8 plaintext * files; remove it. */ line.erase(0, utf8_get_char_len(line[0])); } TrimLeft(line); TrimRight(line); if(line.size() == 0) continue; /* blank */ if(line[0] == '#') continue; /* comment */ if(!line.CompareNoCase("DontTransliterate")) { tr.translit = false; continue; } size_t pos = line.find_first_of(':'); if(pos != string::npos) { /* x: y */ CString id = line.substr(0, pos); CString txt = line.substr(pos+1); TrimLeft(txt); /* Surround each regex with ^(...)$, to force all comparisons to default * to being a full-line match. (Add ".*" manually if this isn't wanted.) */ if(!id.CompareNoCase("TitleFrom")) tr.TitleFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("ArtistFrom")) tr.ArtistFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("SubtitleFrom")) tr.SubFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("TitleTo")) tr.Dest.Title = txt; else if(!id.CompareNoCase("ArtistTo")) tr.Dest.Artist = txt; else if(!id.CompareNoCase("SubtitleTo")) tr.Dest.Subtitle = txt; else if(!id.CompareNoCase("TitleTransTo")) tr.Dest.TitleTranslit = txt; else if(!id.CompareNoCase("ArtistTransTo")) tr.Dest.ArtistTranslit = txt; else if(!id.CompareNoCase("SubtitleTransTo")) tr.Dest.SubtitleTranslit = txt; else LOG->Warn( "Unknown TitleSubst tag: \"%s\"", id.c_str() ); } /* Add the translation if this is a terminator (*) or section * marker ([foo]). */ if(line[0] == '*' || line[0] == '[') { if(!CurrentSection.CompareNoCase(section)) AddTrans(tr); /* Reset. */ tr = TitleTrans(); } if(line[0] == '[' && line[line.size()-1] == ']') { CurrentSection = line.substr(1, line.size()-2); } } }
void ConditionalBGA::Load(const CString &szScreenName) { RageFile file; CString szConditionalBGAFile = THEME->GetCurThemeDir() + szScreenName + " ConditionalBGA.ini"; // char filepath[512]; // strcpy(filepath,""); // empty the path first // strcpy(filepath,szConditionalBGAFile.c_str()); LOG->Trace("ConditionalBGA Load:%s",szConditionalBGAFile.c_str()); bool loaded = file.Open(szConditionalBGAFile,RageFile::READ); // FILE* fp = NULL; // fp = fopen(filepath,"r"); if(!loaded) { LOG->Trace("ConditionalBGA File Not Found"); return; } else { CString currentline; int bgano=0; while(!file.AtEOF()) { file.GetLine(currentline); // get the current line // kill any possible comments CStringArray asKillComments; asKillComments.clear(); // get rid of anything in there split(currentline, "#",asKillComments); // A comment starting with # if(!asKillComments.empty()) { currentline = asKillComments[0]; // there was some commentstuff here, take the first bit to be the actual data } asKillComments.clear(); // get rid of anything in there split(currentline, "/",asKillComments); // A comment starting with // or /* if(!asKillComments.empty()) { currentline = asKillComments[0]; // there was some commentstuff here, take the first bit to be the actual data } TrimRight(currentline); // nuke trailing whitespace // start parsing the data if(currentline.c_str()[0] == '[') // we found a new bganimation { if(!m_bgainfo.empty()) // last one wasnt empty { CheckBgaRequirements(m_bgainfo[bgano]); bgano++; } BgaCondInfo temp; m_bgainfo.push_back(temp); ClearINFO(bgano); // wipe out the old info structure. CStringArray asSplitLine; split(currentline,"[",asSplitLine); split(asSplitLine[0],"]",asSplitLine); if(!asSplitLine.empty() && asSplitLine.size() >= 1) m_bgainfo[bgano].bganame = asSplitLine[asSplitLine.size() - 1]; } else { CStringArray asSplitLine; split(currentline,":",asSplitLine); if(asSplitLine.empty()) continue; if(!asSplitLine[0].CompareNoCase("clear") && asSplitLine.size() > 1) { if(!asSplitLine[1].CompareNoCase("true") || !asSplitLine[1].CompareNoCase("cleared") || !asSplitLine[1].CompareNoCase("clear")) // true / clear (any clear condition) m_bgainfo[bgano].cleared = CBGA_CSCLEARED; else if(!asSplitLine[1].CompareNoCase("false") || !asSplitLine[1].CompareNoCase("failed")) // false / failed m_bgainfo[bgano].cleared = CBGA_CSFAILED; else if(!asSplitLine[1].CompareNoCase("maxcombo") || !asSplitLine[1].CompareNoCase("fullcombo")) // passed with maxcombo m_bgainfo[bgano].cleared = CBGA_CSMAXCOMBO; else if(!asSplitLine[1].CompareNoCase("brokencombo")) // passed with a broken combo m_bgainfo[bgano].cleared = CBGA_CSBROKECOMBO; // LOG->Trace("Clear Conditon: %d",info.cleared); } if(!asSplitLine[0].CompareNoCase("songtitle") && asSplitLine.size() > 1) { m_bgainfo[bgano].songtitle = asSplitLine[1]; // LOG->Trace("SongTitle: %s",info.songtitle.c_str()); } if(!asSplitLine[0].CompareNoCase("songartist") && asSplitLine.size() > 1) { m_bgainfo[bgano].songartist = asSplitLine[1]; // LOG->Trace("SongArtist: %s",info.songartist.c_str()); } if(!asSplitLine[0].CompareNoCase("songday") && asSplitLine.size() > 1) { CStringArray asDays; split( asSplitLine[1], ",", asDays ); for( unsigned d=0; d<asDays.size(); d++ ) { int dn = atoi(asDays[d].c_str()); if(!(dn < 1 || dn > 32)) // ignore if date is out of range { m_bgainfo[bgano].songdays.push_back(dn); } } // for(d=0; d<info.songdays.size(); d++) // { // LOG->Trace("SongDay: %d",info.songdays[d]); // } } if(!asSplitLine[0].CompareNoCase("songmonth") && asSplitLine.size() > 1) { CStringArray asMonths; split( asSplitLine[1], ",", asMonths ); for( unsigned d=0; d<asMonths.size(); d++ ) { int dn = atoi(asMonths[d].c_str()); if(!(dn < 1 || dn > 12)) // ignore if date is out of range { m_bgainfo[bgano].songmonths.push_back(dn); } } // for(d=0; d<info.songmonths.size(); d++) // { // LOG->Trace("SongMonth: %d",info.songmonths[d]); // } } // foot meter ratings if(!asSplitLine[0].CompareNoCase("songdifficulty") && asSplitLine.size() > 1) { CStringArray asDifficulties; split( asSplitLine[1], ",", asDifficulties ); for(unsigned d=0;d<asDifficulties.size();d++) { // check to see if the last character is a + bool bHandled = false; if(asDifficulties[d].c_str()[strlen(asDifficulties[d].c_str())-1] == '+') { bHandled = true; CStringArray asVal; split(asDifficulties[d],"+",asVal); int temp=0; temp = 0 - atoi(asVal[0].c_str()); // negative numbers will indicate 'greater than' for this system m_bgainfo[bgano].songmeters.push_back(temp); } if(!bHandled) // didnt find the + (gt) so find a - (range) { bool isarange=false; for(unsigned b=0; b<strlen(asDifficulties[d].c_str());b++) { if(asDifficulties[d].c_str()[b] == '-') { bHandled = isarange = true; break; } } if(isarange) { CStringArray asVal; split(asDifficulties[d],"-",asVal); int imin=0,imax=0,itmp=0; imin=atoi(asVal[0].c_str()); imax=atoi(asVal[1].c_str()); itmp=imin; while(itmp<=imax) // fill in the values between the min and max range inclusive { m_bgainfo[bgano].songmeters.push_back(itmp); itmp++; } } } if(!bHandled) // its not a range so must be a value on its own { int tmp = atoi(asDifficulties[d].c_str()); m_bgainfo[bgano].songmeters.push_back(tmp); } } } // mods that mustn't be present if(!asSplitLine[0].CompareNoCase("moddisallow") && asSplitLine.size() > 1) { m_bgainfo[bgano].dpoused = true; m_bgainfo[bgano].disallowedpo.FromString(asSplitLine[1]); } // heavy, light e.t.c. if(!asSplitLine[0].CompareNoCase("songrating") && asSplitLine.size() > 1) { CStringArray asDifficulties; split( asSplitLine[1], ",", asDifficulties ); for( unsigned d=0; d<asDifficulties.size(); d++ ) { m_bgainfo[bgano].difficulties.push_back(StringToDifficulty(asDifficulties[d])); } // for(d=0; d<info.difficulties.size(); d++) // { // LOG->Trace("Difficulty: %d",info.difficulties[d]); // } } if(!asSplitLine[0].CompareNoCase("grade") && asSplitLine.size() > 1) { CStringArray asGrades; split( asSplitLine[1], ",", asGrades ); for( unsigned d=0; d<asGrades.size(); d++ ) { m_bgainfo[bgano].grades.push_back(StringToGrade(asGrades[d])); } } if(!asSplitLine[0].CompareNoCase("style") && asSplitLine.size() > 1) { LOG->Info("Comparing Styles"); CStringArray asStyles; split( asSplitLine[1], ",", asStyles ); for( unsigned d=0; d<asStyles.size(); d++ ) { LOG->Info( "Style:%s", asStyles[d].c_str() ); m_bgainfo[bgano].styles.push_back(GAMEMAN->GameAndStringToStyle(GAMESTATE->m_pCurGame,asStyles[d])); } } } } if(bganimtouse.CompareNoCase("")!=0) { LOG->Info("Best Match BGA Was: %s",bganimtouse.c_str()); bganim.LoadFromAniDir( THEME->GetPathToB(bganimtouse) ); } } file.Close(); }