diff --git a/Makefile b/Makefile index 7234f88..569c0cf 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ macos-arm64: strip ncmdump win32: - g++ main.cpp cJSON.cpp aes.cpp ncmcrypt.cpp -o ncmdump -ltag -Ltaglib/lib -Itaglib/include -static -O + g++ main.cpp cJSON.cpp aes.cpp ncmcrypt.cpp -o ncmdump -ltag -Ltaglib/lib -Itaglib/include -static -O -municode strip ncmdump.exe clean: diff --git a/main.cpp b/main.cpp index 82ab2aa..6d73704 100644 --- a/main.cpp +++ b/main.cpp @@ -5,27 +5,31 @@ #include #include +#ifdef _WIN32 +#include +#endif + namespace fs = std::filesystem; void displayHelp() { std::cout << "Usage: ncmdump [-d] [-h] file1 file2 ..." << std::endl; std::cout << "Options:" << std::endl; - std::cout << " -d Process files in a folder (requires folder path)" << std::endl; + std::cout << " -d Process files in a folder (requires folder path)" << std::endl; std::cout << " -h, --help Display this help message" << std::endl; } -void processFile(const std::string& filePath) { +void processFile(const fs::path& filePath) { if (fs::exists(filePath) == false) { - std::cerr << "Error: file '" << filePath << "' does not exist." << std::endl; + std::cerr << "Error: file '" << filePath.string() << "' does not exist." << std::endl; return; } try { - NeteaseCrypt crypt(filePath); + NeteaseCrypt crypt(filePath.string()); crypt.Dump(); crypt.FixMetadata(); - std::cout << "Done: " << crypt.dumpFilepath() << std::endl; + std::cout << "Done: '" << crypt.dumpFilepath().string() << "'" << std::endl; } catch (const std::invalid_argument& e) { std::cout << "Exception: '" << filePath << "'" << e.what() << std::endl; } catch (...) { @@ -33,31 +37,51 @@ void processFile(const std::string& filePath) { } } -void processFilesInFolder(const std::string& folderPath) { +void processFilesInFolder(const fs::path& folderPath) { for (const auto& entry : fs::directory_iterator(folderPath)) { if (fs::is_regular_file(entry.status())) { - processFile(entry.path().string()); + processFile(entry.path()); } } } -int main(int argc, char* argv[]) { +#ifdef _WIN32 +int wmain(int argc, wchar_t* argv[]) +#else +int main(int argc, char **argv) +#endif +{ + #ifdef _WIN32 + SetConsoleOutputCP(CP_UTF8); + #endif + if (argc <= 1) { displayHelp(); return 1; } - std::vector files; + std::vector files; bool processFolders = false; + bool folderProvided = false; - for (int i = 1; i < argc; ++i) { - std::string arg = argv[i]; + #ifdef _WIN32 + #define COMPARE_STR(s1, s2) (wcscmp(s1, s2) == 0) + #define HELP_SHORT L"-h" + #define HELP_LONG L"--help" + #define FOLDER L"-d" + #else + #define COMPARE_STR(s1, s2) (strcmp(s1, s2) == 0) + #define HELP_SHORT "-h" + #define HELP_LONG "--help" + #define FOLDER "-d" + #endif - if (arg == "-h" || arg == "--help") { + for (int i = 1; i < argc; ++i) { + if (COMPARE_STR(argv[i], HELP_SHORT) || COMPARE_STR(argv[i], HELP_LONG)) { displayHelp(); return 0; - } else if (arg == "-d") { + } else if (COMPARE_STR(argv[i], FOLDER)) { processFolders = true; if (i + 1 < argc && argv[i + 1][0] != '-') { folderProvided = true; @@ -69,7 +93,15 @@ int main(int argc, char* argv[]) { return 1; } } else { - files.push_back(arg); + #ifdef _WIN32 + int multiByteStrSize = WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, NULL, 0, NULL, NULL); + char *multiByteStr = new char[multiByteStrSize]; + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, multiByteStr, multiByteStrSize, NULL, NULL); + fs::path path(multiByteStr); + #else + fs::path path(arg); + #endif + files.push_back(path); } } diff --git a/ncmcrypt.cpp b/ncmcrypt.cpp index 6896265..cc688a9 100644 --- a/ncmcrypt.cpp +++ b/ncmcrypt.cpp @@ -13,6 +13,8 @@ #include #include +#include + const unsigned char NeteaseCrypt::sCoreKey[17] = {0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57, 0}; const unsigned char NeteaseCrypt::sModifyKey[17] = {0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28, 0}; @@ -52,14 +54,6 @@ static void replace(std::string& str, const std::string& from, const std::string } } -static std::string fileNameWithoutExt(const std::string& str) -{ - size_t lastPath = str.find_last_of("/\\"); - std::string path = str.substr(lastPath+1); - size_t lastExt = path.find_last_of("."); - return path.substr(0, lastExt); -} - NeteaseMusicMetadata::~NeteaseMusicMetadata() { cJSON_Delete(mRaw); } @@ -112,7 +106,7 @@ NeteaseMusicMetadata::NeteaseMusicMetadata(cJSON* raw) { } } -bool NeteaseCrypt::openFile(std::string const& path) { +bool NeteaseCrypt::openFile(std::filesystem::path const& path) { mFile.open(path, std::ios::in | std::ios::binary); if (!mFile.is_open()) { return false; @@ -179,7 +173,7 @@ std::string NeteaseCrypt::mimeType(std::string& data) { } void NeteaseCrypt::FixMetadata() { - if (mDumpFilepath.length() <= 0) { + if (mDumpFilepath.string().length() <= 0) { throw std::invalid_argument("must dump before"); } @@ -243,7 +237,7 @@ void NeteaseCrypt::Dump() { // replace(mDumpFilepath, ">", ">"); // replace(mDumpFilepath, "|", "|"); // } else { - mDumpFilepath = fileNameWithoutExt(mFilepath); + mDumpFilepath = mFilepath; // } n = 0x8000; @@ -265,11 +259,11 @@ void NeteaseCrypt::Dump() { // identify format // ID3 format mp3 if (buffer[0] == 0x49 && buffer[1] == 0x44 && buffer[2] == 0x33) { - mDumpFilepath += ".mp3"; + mDumpFilepath.replace_extension(".mp3"); mFormat = NeteaseCrypt::MP3; } else { - mDumpFilepath += ".flac"; - mFormat = NeteaseCrypt::FLAC; + mDumpFilepath.replace_extension(".flac"); + mFormat = NeteaseCrypt::FLAC; } output.open(mDumpFilepath, output.out | output.binary); @@ -290,7 +284,7 @@ NeteaseCrypt::~NeteaseCrypt() { mFile.close(); } -NeteaseCrypt::NeteaseCrypt(std::string const& path) { +NeteaseCrypt::NeteaseCrypt(std::filesystem::path const& path) { if (!openFile(path)) { throw std::invalid_argument(" can't open file"); } diff --git a/ncmcrypt.h b/ncmcrypt.h index 8765450..a8997a8 100644 --- a/ncmcrypt.h +++ b/ncmcrypt.h @@ -6,6 +6,8 @@ #include #include +#include + class NeteaseMusicMetadata { private: @@ -40,8 +42,8 @@ private: enum NcmFormat { MP3, FLAC }; private: - std::string mFilepath; - std::string mDumpFilepath; + std::filesystem::path mFilepath; + std::filesystem::path mDumpFilepath; NcmFormat mFormat; std::string mImageData; std::ifstream mFile; @@ -50,17 +52,17 @@ private: private: bool isNcmFile(); - bool openFile(std::string const&); + bool openFile(std::filesystem::path const&); int read(char *s, std::streamsize n); void buildKeyBox(unsigned char *key, int keyLen); std::string mimeType(std::string& data); public: - const std::string& filepath() const { return mFilepath; } - const std::string& dumpFilepath() const { return mDumpFilepath; } + const std::filesystem::path& filepath() const { return mFilepath; } + const std::filesystem::path& dumpFilepath() const { return mDumpFilepath; } public: - NeteaseCrypt(std::string const&); + NeteaseCrypt(std::filesystem::path const&); ~NeteaseCrypt(); public: