#include #include #include #include #include #include #include "logging.h" #include "files.h" const char *songsPath = "/sdcard/Songs/"; void split(std::vector &tokens, const std::string &text, const char *sep) { int start = 0, end = 0; while ((end = text.find(sep, start)) != std::string::npos) { tokens.push_back(text.substr(start, end - start)); start = end + 1; } tokens.push_back(text.substr(start)); } // trim from start static inline std::string <rim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(isspace)))); return s; } // trim from end static inline std::string &rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(isspace))).base(), s.end()); return s; } // trim from both ends static inline std::string &trim(std::string &s) { return ltrim(rtrim(s)); } /* Returns a list of directories (except the ones that begin with a dot) */ void GetDirectories(std::vector &out, const char *directory) { #ifdef WINDOWS HANDLE dir; WIN32_FIND_DATA file_data; if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE) return; /* No files found */ do { const string file_name = file_data.cFileName; const string full_file_name = directory + "/" + file_name; const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; if (file_name[0] == '.') continue; if (!is_directory) continue; out.push_back(full_file_name); } while (FindNextFile(dir, &file_data)); FindClose(dir); #else DIR *dir; class dirent *ent; class stat st; dir = opendir(directory); if(dir == NULL) { std::string errmsg = "Cannot open directory "; logstdError("GetDirectories", errmsg + directory); } else { while ((ent = readdir(dir)) != NULL) { const std::string file_name = ent->d_name; std::string full_file_name = directory; full_file_name.append("/" + file_name + "/"); if (file_name[0] == '.') continue; if (stat(full_file_name.c_str(), &st) == -1) continue; if (!S_ISDIR(st.st_mode)) continue; out.push_back(full_file_name); } closedir(dir); if(out.empty()) { std::string errmsg = "Directory empty: "; logstdError("GetDirectories", errmsg + directory); } } #endif } // GetFilesInDirectory /* Returns a list of sm files */ void GetSmFiles(std::vector &out, const std::string directory) { #ifdef WINDOWS HANDLE dir; WIN32_FIND_DATA file_data; if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE) return; /* No files found */ do { const string file_name = file_data.cFileName; const string full_file_name = directory + "/" + file_name; const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; std::vector tokens; split(tokens, file_name, "."); if (strcmp(tokens.back(), "sm")) continue; if (is_directory) continue; out.push_back(full_file_name); } while (FindNextFile(dir, &file_data)); FindClose(dir); #else DIR *dir; class dirent *ent; class stat st; dir = opendir(directory.c_str()); if(dir == NULL) { std::string errmsg = "Cannot open directory "; logstdError("GetDirectories", errmsg + directory); } else { while ((ent = readdir(dir)) != NULL) { const std::string file_name = ent->d_name; std::string full_file_name = directory; full_file_name.append("/" + file_name); std::vector tokens; split(tokens, file_name, "."); if (tokens.back() != "sm") continue; if (stat(full_file_name.c_str(), &st) == -1) continue; const bool is_readable = (st.st_mode & S_IRUSR) != 0; if (!is_readable) continue; out.push_back(file_name); } closedir(dir); if(out.empty()) { std::string errmsg = "Directory empty: "; logstdError("GetDirectories", errmsg + directory); } } #endif } // GetSmFiles int readSongFile(std::string &path, musicfile &songFile) { bool reading_note = false; int current_note_line = 0; std::vector currentNoteData; std::vector> currentLineNoteData; notes currentNotes; std::string line; std::ifstream file; file.open(path.c_str(), std::ifstream::in); if (!file) { std::string msg = "Could not open "; msg.append(path); logstdError("loadFile", msg); return 1; } while(file.good()) { std::getline(file, line); line = trim(line); if(line.length() == 0) continue; else if(line[0] == '/') continue; else if(line[0] == '#') { std::vector tokens; split(tokens, line, ":"); if(tokens[0].compare("#NOTES") == 0) { reading_note = true; continue; } else reading_note = false; if(*tokens[1].rbegin() == ';') tokens[1].pop_back(); if(tokens[0].compare("#TITLE") == 0) { songFile.title = tokens[1]; } else if(tokens[0].compare("#ARTIST") == 0) { songFile.artist = tokens[1]; } else if(tokens[0].compare("#BANNER") == 0) { songFile.banner = tokens[1]; } else if(tokens[0].compare("#BACKGROUND") == 0) { songFile.background = tokens[1]; } else if(tokens[0].compare("#MUSIC") == 0) { songFile.file = tokens[1]; } else if(tokens[0].compare("#OFFSET") == 0) { std::istringstream(tokens[1]) >> songFile.offset; } else if(tokens[0].compare("#BPMS") == 0) { std::vector listBpms; split(listBpms, tokens[1], ","); for(std::vector::iterator bpmData = listBpms.begin(); bpmData != listBpms.end(); ++bpmData) { std::vector bpm; split(bpm, *bpmData, "="); songBpm bpms; std::istringstream(bpm[0]) >> bpms.beat; std::istringstream(bpm[1]) >> bpms.bpm; songFile.bpms.push_back(bpms); } } } else if(reading_note) { std::vector tokens; split(tokens, line, ":"); if((*line.rbegin() == ':') || (tokens.size() > 1)) { switch(current_note_line) { case 0: currentNotes.type = tokens[0]; break; case 1: currentNotes.description = tokens[0]; break; case 2: currentNotes.difficultyClass = tokens[0]; break; case 3: std::istringstream ( tokens[1] ) >> currentNotes.difficultyMeter; break; case 4: currentNotes.radarValues = tokens[0]; break; default: std::string msg = "Too much ':' for #NOTES in "; msg.append(path); logstdError("readSongFile", msg); break; } current_note_line += 1; } else if(line[0] == ',') { currentNotes.noteData.push_back(currentLineNoteData); currentLineNoteData.clear(); } else if(line[0] == ';') { current_note_line = 0; songFile.songNotes.push_back(currentNotes); static const notes tempStruct; currentNotes = tempStruct; } else { for(std::string::iterator c = line.begin(); c != line.end(); ++c) { switch(*c) { case '0': currentNoteData.push_back(None); break; case '1': currentNoteData.push_back(Tap); break; case '2': currentNoteData.push_back(Hold_begin); break; case '3': currentNoteData.push_back(Hold_end); break; case '4': currentNoteData.push_back(Roll); break; case 'M': currentNoteData.push_back(Mine); break; case 'L': currentNoteData.push_back(Lift); break; case 'F': currentNoteData.push_back(Fake); break; } } currentLineNoteData.push_back(currentNoteData); currentNoteData.clear(); } } } if(!file.eof()) { logstdError("readSongFile", "Line cannot be read"); } file.close(); return 0; } std::vector loadSongs() { std::vector directories; std::vector smfiles; std::vector songs; GetDirectories(directories, songsPath); for(std::vector::iterator it = directories.begin(); it != directories.end(); ++it) { GetSmFiles(smfiles, *it); for(std::vector::iterator ite = smfiles.begin(); ite != smfiles.end(); ++ite) { musicfile songData; std::string file = *it + *ite; if(!readSongFile(file, songData)) songData.path = *it; songs.push_back(songData); } } return songs; }