| ... | ... |
@@ -17,9 +17,6 @@ |
| 17 | 17 |
#include "XSFCommon.h" |
| 18 | 18 |
#include "XSFFile.h" |
| 19 | 19 |
#include "convert.h" |
| 20 |
-#if defined(_WIN32) && !defined(_MSC_VER) |
|
| 21 |
-# include "fstream_wfopen.h" |
|
| 22 |
-#endif |
|
| 23 | 20 |
#include "zlib.h" |
| 24 | 21 |
|
| 25 | 22 |
static inline void Set32BitsLE(std::uint32_t input, std::uint8_t *output) |
| ... | ... |
@@ -61,65 +58,33 @@ static inline std::string TrimWhitespace(const std::string &orig) |
| 61 | 58 |
return LeftTrimWhitespace(RightTrimWhitespace(orig)); |
| 62 | 59 |
} |
| 63 | 60 |
|
| 64 |
-XSFFile::XSFFile() : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName("")
|
|
| 61 |
+XSFFile::XSFFile() : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), filePath() |
|
| 65 | 62 |
{
|
| 66 | 63 |
} |
| 67 | 64 |
|
| 68 |
-XSFFile::XSFFile(const std::string &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 65 |
+XSFFile::XSFFile(const std::filesystem::path &path) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), filePath(path) |
|
| 69 | 66 |
{
|
| 70 |
- this->ReadXSF(filename, 0, 0, true); |
|
| 67 |
+ this->ReadXSF(path, 0, 0, true); |
|
| 71 | 68 |
} |
| 72 | 69 |
|
| 73 |
-XSFFile::XSFFile(const std::string &filename, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 70 |
+XSFFile::XSFFile(const std::filesystem::path &path, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), filePath(path) |
|
| 74 | 71 |
{
|
| 75 |
- this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
|
| 72 |
+ this->ReadXSF(path, programSizeOffset, programHeaderSize); |
|
| 76 | 73 |
} |
| 77 | 74 |
|
| 78 |
-#ifdef _WIN32 |
|
| 79 |
-XSFFile::XSFFile(const std::wstring &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(ConvertFuncs::WStringToString(filename)) |
|
| 75 |
+void XSFFile::ReadXSF(const std::filesystem::path &path, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize, bool readTagsOnly) |
|
| 80 | 76 |
{
|
| 81 |
- this->ReadXSF(filename, 0, 0, true); |
|
| 82 |
-} |
|
| 83 |
- |
|
| 84 |
-XSFFile::XSFFile(const std::wstring &filename, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(ConvertFuncs::WStringToString(filename)) |
|
| 85 |
-{
|
|
| 86 |
- this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
|
| 87 |
-} |
|
| 88 |
-#endif |
|
| 89 |
- |
|
| 90 |
-void XSFFile::ReadXSF(const std::string &filename, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize, bool readTagsOnly) |
|
| 91 |
-{
|
|
| 92 |
- if (!std::filesystem::is_regular_file(filename)) |
|
| 93 |
- throw std::logic_error("File " + filename + " does not exist.");
|
|
| 94 |
- |
|
| 95 |
- std::ifstream xSF; |
|
| 96 |
- xSF.exceptions(std::ifstream::failbit | std::ifstream::badbit); |
|
| 97 |
- xSF.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); |
|
| 98 |
- |
|
| 99 |
- this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly); |
|
| 100 |
- |
|
| 101 |
- xSF.close(); |
|
| 102 |
-} |
|
| 103 |
- |
|
| 104 |
-#ifdef _WIN32 |
|
| 105 |
-void XSFFile::ReadXSF(const std::wstring &filename, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize, bool readTagsOnly) |
|
| 106 |
-{
|
|
| 107 |
- if (!std::filesystem::is_regular_file(filename)) |
|
| 108 |
- throw std::logic_error("File " + ConvertFuncs::WStringToString(filename) + " does not exist.");
|
|
| 77 |
+ if (!std::filesystem::is_regular_file(path)) |
|
| 78 |
+ throw std::logic_error("File " + path.string() + " does not exist.");
|
|
| 109 | 79 |
|
| 110 |
-#if defined(_WIN32) && !defined(_MSC_VER) |
|
| 111 |
- ifstream_wfopen xSF; |
|
| 112 |
-#else |
|
| 113 | 80 |
std::ifstream xSF; |
| 114 |
-#endif |
|
| 115 | 81 |
xSF.exceptions(std::ifstream::failbit | std::ifstream::badbit); |
| 116 |
- xSF.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); |
|
| 82 |
+ xSF.open(path, std::ifstream::in | std::ifstream::binary); |
|
| 117 | 83 |
|
| 118 | 84 |
this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly); |
| 119 | 85 |
|
| 120 | 86 |
xSF.close(); |
| 121 | 87 |
} |
| 122 |
-#endif |
|
| 123 | 88 |
|
| 124 | 89 |
void XSFFile::ReadXSF(std::ifstream &xSF, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize, bool readTagsOnly) |
| 125 | 90 |
{
|
| ... | ... |
@@ -462,29 +427,21 @@ std::string XSFFile::GetFormattedTitle(const std::string &format) const |
| 462 | 427 |
return formattedTitle; |
| 463 | 428 |
} |
| 464 | 429 |
|
| 465 |
-std::string XSFFile::GetFilename() const |
|
| 430 |
+std::filesystem::path XSFFile::GetFilepath() const |
|
| 466 | 431 |
{
|
| 467 |
- return this->fileName; |
|
| 432 |
+ return this->filePath; |
|
| 468 | 433 |
} |
| 469 | 434 |
|
| 470 |
-std::string XSFFile::GetFilenameWithoutPath() const |
|
| 435 |
+std::filesystem::path XSFFile::GetFilenameWithoutPath() const |
|
| 471 | 436 |
{
|
| 472 |
- return std::filesystem::path(this->fileName).filename().string(); |
|
| 437 |
+ return this->filePath.filename(); |
|
| 473 | 438 |
} |
| 474 | 439 |
|
| 475 | 440 |
void XSFFile::SaveFile() const |
| 476 | 441 |
{
|
| 477 |
-#if defined(_WIN32) && !defined(_MSC_VER) |
|
| 478 |
- ofstream_wfopen xSF; |
|
| 479 |
-#else |
|
| 480 | 442 |
std::ofstream xSF; |
| 481 |
-#endif |
|
| 482 | 443 |
xSF.exceptions(std::ofstream::failbit); |
| 483 |
-#ifdef _WIN32 |
|
| 484 |
- xSF.open(ConvertFuncs::StringToWString(this->fileName).c_str(), std::ofstream::out | std::ofstream::binary); |
|
| 485 |
-#else |
|
| 486 |
- xSF.open(this->fileName.c_str(), std::ofstream::out | std::ofstream::binary); |
|
| 487 |
-#endif |
|
| 444 |
+ xSF.open(this->filePath, std::ofstream::out | std::ofstream::binary); |
|
| 488 | 445 |
|
| 489 | 446 |
xSF.write(reinterpret_cast<const char *>(&this->rawData[0]), this->rawData.size()); |
| 490 | 447 |
|
* Use enum class instead of enum (except for the enums for the resource IDs, not really necessary there).
* For NCSF specifically, included a function to convert an enum class to its underlying integral type (as this is needed for use with the std::bitset class).
* Cleanup headers so all the ones needed in a file are explicitly included even if they may possibly be included in another header.
* Used forward declarations in a few spots.
* Explicitly namespaced all (u)int*_t uses (this might seem like overkill, but it helps me see when the standard types are being used with a simple search for std::).
* Made sure it all builds with MinGW-w64 as well (both gcc and clang).
* Removed some std::move from DialogBuilder.cpp based on clang's warnings for that.
* Replaced use of std::copy_n on strings in DialogBuilder.cpp with my CopyToString functions that use wcscpy.
* Replaced CHAR_MIN/CHAR_MAX in eqstr.h and ltstr.h with std::numeric_limits<char>::min/max().
| ... | ... |
@@ -7,17 +7,22 @@ |
| 7 | 7 |
|
| 8 | 8 |
#include <algorithm> |
| 9 | 9 |
#include <filesystem> |
| 10 |
-#include <functional> |
|
| 10 |
+#include <fstream> |
|
| 11 | 11 |
#include <stdexcept> |
| 12 |
+#include <string> |
|
| 13 |
+#include <vector> |
|
| 14 |
+#include <cmath> |
|
| 15 |
+#include <cstddef> |
|
| 16 |
+#include <cstdint> |
|
| 17 |
+#include "XSFCommon.h" |
|
| 18 |
+#include "XSFFile.h" |
|
| 19 |
+#include "convert.h" |
|
| 12 | 20 |
#if defined(_WIN32) && !defined(_MSC_VER) |
| 13 | 21 |
# include "fstream_wfopen.h" |
| 14 | 22 |
#endif |
| 15 | 23 |
#include "zlib.h" |
| 16 |
-#include "XSFFile.h" |
|
| 17 |
-#include "XSFCommon.h" |
|
| 18 |
-#include "convert.h" |
|
| 19 | 24 |
|
| 20 |
-static inline void Set32BitsLE(uint32_t input, uint8_t *output) |
|
| 25 |
+static inline void Set32BitsLE(std::uint32_t input, std::uint8_t *output) |
|
| 21 | 26 |
{
|
| 22 | 27 |
output[0] = input & 0xFF; |
| 23 | 28 |
output[1] = (input >> 8) & 0xFF; |
| ... | ... |
@@ -65,7 +70,7 @@ XSFFile::XSFFile(const std::string &filename) : xSFType(0), hasFile(false), rawD |
| 65 | 70 |
this->ReadXSF(filename, 0, 0, true); |
| 66 | 71 |
} |
| 67 | 72 |
|
| 68 |
-XSFFile::XSFFile(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 73 |
+XSFFile::XSFFile(const std::string &filename, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 69 | 74 |
{
|
| 70 | 75 |
this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
| 71 | 76 |
} |
| ... | ... |
@@ -76,13 +81,13 @@ XSFFile::XSFFile(const std::wstring &filename) : xSFType(0), hasFile(false), raw |
| 76 | 81 |
this->ReadXSF(filename, 0, 0, true); |
| 77 | 82 |
} |
| 78 | 83 |
|
| 79 |
-XSFFile::XSFFile(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(ConvertFuncs::WStringToString(filename)) |
|
| 84 |
+XSFFile::XSFFile(const std::wstring &filename, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(ConvertFuncs::WStringToString(filename)) |
|
| 80 | 85 |
{
|
| 81 | 86 |
this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
| 82 | 87 |
} |
| 83 | 88 |
#endif |
| 84 | 89 |
|
| 85 |
-void XSFFile::ReadXSF(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
|
| 90 |
+void XSFFile::ReadXSF(const std::string &filename, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize, bool readTagsOnly) |
|
| 86 | 91 |
{
|
| 87 | 92 |
if (!std::filesystem::is_regular_file(filename)) |
| 88 | 93 |
throw std::logic_error("File " + filename + " does not exist.");
|
| ... | ... |
@@ -97,7 +102,7 @@ void XSFFile::ReadXSF(const std::string &filename, uint32_t programSizeOffset, u |
| 97 | 102 |
} |
| 98 | 103 |
|
| 99 | 104 |
#ifdef _WIN32 |
| 100 |
-void XSFFile::ReadXSF(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
|
| 105 |
+void XSFFile::ReadXSF(const std::wstring &filename, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize, bool readTagsOnly) |
|
| 101 | 106 |
{
|
| 102 | 107 |
if (!std::filesystem::is_regular_file(filename)) |
| 103 | 108 |
throw std::logic_error("File " + ConvertFuncs::WStringToString(filename) + " does not exist.");
|
| ... | ... |
@@ -116,7 +121,7 @@ void XSFFile::ReadXSF(const std::wstring &filename, uint32_t programSizeOffset, |
| 116 | 121 |
} |
| 117 | 122 |
#endif |
| 118 | 123 |
|
| 119 |
-void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
|
| 124 |
+void XSFFile::ReadXSF(std::ifstream &xSF, std::uint32_t programSizeOffset, std::uint32_t programHeaderSize, bool readTagsOnly) |
|
| 120 | 125 |
{
|
| 121 | 126 |
xSF.seekg(0, std::ifstream::end); |
| 122 | 127 |
auto filesize = xSF.tellg(); |
| ... | ... |
@@ -139,7 +144,7 @@ void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t p |
| 139 | 144 |
if (filesize < 16) |
| 140 | 145 |
throw std::runtime_error("File is too small.");
|
| 141 | 146 |
|
| 142 |
- uint32_t reservedSize = Get32BitsLE(xSF), programCompressedSize = Get32BitsLE(xSF); |
|
| 147 |
+ std::uint32_t reservedSize = Get32BitsLE(xSF), programCompressedSize = Get32BitsLE(xSF); |
|
| 143 | 148 |
this->rawData.resize(reservedSize + programCompressedSize + 16); |
| 144 | 149 |
Set32BitsLE(reservedSize, &this->rawData[4]); |
| 145 | 150 |
Set32BitsLE(programCompressedSize, &this->rawData[8]); |
| ... | ... |
@@ -169,11 +174,11 @@ void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t p |
| 169 | 174 |
xSF.read(reinterpret_cast<char *>(&this->rawData[reservedSize + 16]), programCompressedSize); |
| 170 | 175 |
else |
| 171 | 176 |
{
|
| 172 |
- auto programSectionCompressed = std::vector<uint8_t>(programCompressedSize); |
|
| 177 |
+ auto programSectionCompressed = std::vector<std::uint8_t>(programCompressedSize); |
|
| 173 | 178 |
xSF.read(reinterpret_cast<char *>(&programSectionCompressed[0]), programCompressedSize); |
| 174 | 179 |
std::copy_n(&programSectionCompressed[0], programCompressedSize, &this->rawData[reservedSize + 16]); |
| 175 | 180 |
|
| 176 |
- auto programSectionUncompressed = std::vector<uint8_t>(programHeaderSize); |
|
| 181 |
+ auto programSectionUncompressed = std::vector<std::uint8_t>(programHeaderSize); |
|
| 177 | 182 |
unsigned long programUncompressedSize = programHeaderSize; |
| 178 | 183 |
uncompress(&programSectionUncompressed[0], &programUncompressedSize, &programSectionCompressed[0], programCompressedSize); |
| 179 | 184 |
programUncompressedSize = Get32BitsLE(&programSectionUncompressed[programSizeOffset]) + programHeaderSize; |
| ... | ... |
@@ -231,7 +236,7 @@ void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t p |
| 231 | 236 |
this->hasFile = true; |
| 232 | 237 |
} |
| 233 | 238 |
|
| 234 |
-bool XSFFile::IsValidType(uint8_t type) const |
|
| 239 |
+bool XSFFile::IsValidType(std::uint8_t type) const |
|
| 235 | 240 |
{
|
| 236 | 241 |
return this->xSFType == type; |
| 237 | 242 |
} |
| ... | ... |
@@ -250,22 +255,22 @@ bool XSFFile::HasFile() const |
| 250 | 255 |
return this->hasFile; |
| 251 | 256 |
} |
| 252 | 257 |
|
| 253 |
-std::vector<uint8_t> &XSFFile::GetReservedSection() |
|
| 258 |
+std::vector<std::uint8_t> &XSFFile::GetReservedSection() |
|
| 254 | 259 |
{
|
| 255 | 260 |
return this->reservedSection; |
| 256 | 261 |
} |
| 257 | 262 |
|
| 258 |
-std::vector<uint8_t> XSFFile::GetReservedSection() const |
|
| 263 |
+std::vector<std::uint8_t> XSFFile::GetReservedSection() const |
|
| 259 | 264 |
{
|
| 260 | 265 |
return this->reservedSection; |
| 261 | 266 |
} |
| 262 | 267 |
|
| 263 |
-std::vector<uint8_t> &XSFFile::GetProgramSection() |
|
| 268 |
+std::vector<std::uint8_t> &XSFFile::GetProgramSection() |
|
| 264 | 269 |
{
|
| 265 | 270 |
return this->programSection; |
| 266 | 271 |
} |
| 267 | 272 |
|
| 268 |
-std::vector<uint8_t> XSFFile::GetProgramSection() const |
|
| 273 |
+std::vector<std::uint8_t> XSFFile::GetProgramSection() const |
|
| 269 | 274 |
{
|
| 270 | 275 |
return this->programSection; |
| 271 | 276 |
} |
| ... | ... |
@@ -322,19 +327,19 @@ unsigned long XSFFile::GetFadeMS(unsigned long defaultFade) const |
| 322 | 327 |
|
| 323 | 328 |
double XSFFile::GetVolume(VolumeType preferredVolumeType, PeakType preferredPeakType) const |
| 324 | 329 |
{
|
| 325 |
- if (preferredVolumeType == VOLUMETYPE_NONE) |
|
| 330 |
+ if (preferredVolumeType == VolumeType::None) |
|
| 326 | 331 |
return 1.0; |
| 327 | 332 |
std::string replaygain_album_gain = this->GetTagValue("replaygain_album_gain"), replaygain_album_peak = this->GetTagValue("replaygain_album_peak");
|
| 328 | 333 |
std::string replaygain_track_gain = this->GetTagValue("replaygain_track_gain"), replaygain_track_peak = this->GetTagValue("replaygain_track_peak");
|
| 329 | 334 |
std::string volume = this->GetTagValue("volume");
|
| 330 | 335 |
double gain = 0.0; |
| 331 | 336 |
bool hadReplayGain = false; |
| 332 |
- if (preferredVolumeType == VOLUMETYPE_REPLAYGAIN_ALBUM && !replaygain_album_gain.empty()) |
|
| 337 |
+ if (preferredVolumeType == VolumeType::ReplayGainAlbum && !replaygain_album_gain.empty()) |
|
| 333 | 338 |
{
|
| 334 | 339 |
gain = convertTo<double>(replaygain_album_gain); |
| 335 | 340 |
hadReplayGain = true; |
| 336 | 341 |
} |
| 337 |
- if (!hadReplayGain && preferredVolumeType != VOLUMETYPE_VOLUME && !replaygain_track_gain.empty()) |
|
| 342 |
+ if (!hadReplayGain && preferredVolumeType != VolumeType::Volume && !replaygain_track_gain.empty()) |
|
| 338 | 343 |
{
|
| 339 | 344 |
gain = convertTo<double>(replaygain_track_gain); |
| 340 | 345 |
hadReplayGain = true; |
| ... | ... |
@@ -342,9 +347,9 @@ double XSFFile::GetVolume(VolumeType preferredVolumeType, PeakType preferredPeak |
| 342 | 347 |
if (hadReplayGain) |
| 343 | 348 |
{
|
| 344 | 349 |
double vol = std::pow(10.0, gain / 20.0), peak = 1.0; |
| 345 |
- if (preferredPeakType == PEAKTYPE_REPLAYGAIN_ALBUM && !replaygain_album_peak.empty()) |
|
| 350 |
+ if (preferredPeakType == PeakType::ReplayGainAlbum && !replaygain_album_peak.empty()) |
|
| 346 | 351 |
peak = convertTo<double>(replaygain_album_peak); |
| 347 |
- else if (preferredPeakType != PEAKTYPE_NONE && !replaygain_track_peak.empty()) |
|
| 352 |
+ else if (preferredPeakType != PeakType::None && !replaygain_track_peak.empty()) |
|
| 348 | 353 |
peak = convertTo<double>(replaygain_track_peak); |
| 349 | 354 |
return !fEqual(peak, 1.0) ? std::min(vol, 1.0 / peak) : vol; |
| 350 | 355 |
} |
| ... | ... |
@@ -354,12 +359,12 @@ double XSFFile::GetVolume(VolumeType preferredVolumeType, PeakType preferredPeak |
| 354 | 359 |
std::string XSFFile::FormattedTitleOptionalBlock(const std::string &block, bool &hadReplacement, unsigned level) const |
| 355 | 360 |
{
|
| 356 | 361 |
std::string formattedBlock; |
| 357 |
- for (size_t x = 0, len = block.length(); x < len; ++x) |
|
| 362 |
+ for (std::size_t x = 0, len = block.length(); x < len; ++x) |
|
| 358 | 363 |
{
|
| 359 | 364 |
char c = block[x]; |
| 360 | 365 |
if (c == '%') |
| 361 | 366 |
{
|
| 362 |
- size_t origX = x; |
|
| 367 |
+ std::size_t origX = x; |
|
| 363 | 368 |
for (++x; x < len; ++x) |
| 364 | 369 |
if (block[x] == '%') |
| 365 | 370 |
break; |
| ... | ... |
@@ -377,7 +382,7 @@ std::string XSFFile::FormattedTitleOptionalBlock(const std::string &block, bool |
| 377 | 382 |
} |
| 378 | 383 |
if (c == '[' && level + 1 < 10) |
| 379 | 384 |
{
|
| 380 |
- size_t origX = x; |
|
| 385 |
+ std::size_t origX = x; |
|
| 381 | 386 |
unsigned nests = 0; |
| 382 | 387 |
for (++x; x < len; ++x) |
| 383 | 388 |
{
|
| ... | ... |
@@ -408,12 +413,12 @@ std::string XSFFile::FormattedTitleOptionalBlock(const std::string &block, bool |
| 408 | 413 |
std::string XSFFile::GetFormattedTitle(const std::string &format) const |
| 409 | 414 |
{
|
| 410 | 415 |
std::string formattedTitle; |
| 411 |
- for (size_t x = 0, len = format.length(); x < len; ++x) |
|
| 416 |
+ for (std::size_t x = 0, len = format.length(); x < len; ++x) |
|
| 412 | 417 |
{
|
| 413 | 418 |
char c = format[x]; |
| 414 | 419 |
if (c == '%') |
| 415 | 420 |
{
|
| 416 |
- size_t origX = x; |
|
| 421 |
+ std::size_t origX = x; |
|
| 417 | 422 |
for (++x; x < len; ++x) |
| 418 | 423 |
if (format[x] == '%') |
| 419 | 424 |
break; |
| ... | ... |
@@ -429,7 +434,7 @@ std::string XSFFile::GetFormattedTitle(const std::string &format) const |
| 429 | 434 |
} |
| 430 | 435 |
else if (c == '[') |
| 431 | 436 |
{
|
| 432 |
- size_t origX = x; |
|
| 437 |
+ std::size_t origX = x; |
|
| 433 | 438 |
unsigned nests = 0; |
| 434 | 439 |
for (++x; x < len; ++x) |
| 435 | 440 |
{
|
| ... | ... |
@@ -6,8 +6,12 @@ |
| 6 | 6 |
*/ |
| 7 | 7 |
|
| 8 | 8 |
#include <algorithm> |
| 9 |
+#include <filesystem> |
|
| 9 | 10 |
#include <functional> |
| 10 | 11 |
#include <stdexcept> |
| 12 |
+#if defined(_WIN32) && !defined(_MSC_VER) |
|
| 13 |
+# include "fstream_wfopen.h" |
|
| 14 |
+#endif |
|
| 11 | 15 |
#include "zlib.h" |
| 12 | 16 |
#include "XSFFile.h" |
| 13 | 17 |
#include "XSFCommon.h" |
| ... | ... |
@@ -80,7 +84,7 @@ XSFFile::XSFFile(const std::wstring &filename, uint32_t programSizeOffset, uint3 |
| 80 | 84 |
|
| 81 | 85 |
void XSFFile::ReadXSF(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
| 82 | 86 |
{
|
| 83 |
- if (!FileExists(filename)) |
|
| 87 |
+ if (!std::filesystem::is_regular_file(filename)) |
|
| 84 | 88 |
throw std::logic_error("File " + filename + " does not exist.");
|
| 85 | 89 |
|
| 86 | 90 |
std::ifstream xSF; |
| ... | ... |
@@ -95,7 +99,7 @@ void XSFFile::ReadXSF(const std::string &filename, uint32_t programSizeOffset, u |
| 95 | 99 |
#ifdef _WIN32 |
| 96 | 100 |
void XSFFile::ReadXSF(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
| 97 | 101 |
{
|
| 98 |
- if (!FileExists(filename)) |
|
| 102 |
+ if (!std::filesystem::is_regular_file(filename)) |
|
| 99 | 103 |
throw std::logic_error("File " + ConvertFuncs::WStringToString(filename) + " does not exist.");
|
| 100 | 104 |
|
| 101 | 105 |
#if defined(_WIN32) && !defined(_MSC_VER) |
| ... | ... |
@@ -460,7 +464,7 @@ std::string XSFFile::GetFilename() const |
| 460 | 464 |
|
| 461 | 465 |
std::string XSFFile::GetFilenameWithoutPath() const |
| 462 | 466 |
{
|
| 463 |
- return ExtractFilenameFromPath(this->fileName); |
|
| 467 |
+ return std::filesystem::path(this->fileName).filename().string(); |
|
| 464 | 468 |
} |
| 465 | 469 |
|
| 466 | 470 |
void XSFFile::SaveFile() const |
| ... | ... |
@@ -24,24 +24,26 @@ static inline void Set32BitsLE(uint32_t input, uint8_t *output) |
| 24 | 24 |
// The whitespace trimming was modified from the following answer on Stack Overflow: |
| 25 | 25 |
// http://stackoverflow.com/a/217605 |
| 26 | 26 |
|
| 27 |
-struct IsWhitespace |
|
| 27 |
+bool IsWhitespace(const char &x) |
|
| 28 | 28 |
{
|
| 29 |
- using argument_type = char;; |
|
| 30 |
- bool operator()(const char &x) const |
|
| 31 |
- {
|
|
| 32 |
- return x >= 0x01 && x <= 0x20; |
|
| 33 |
- } |
|
| 34 |
-}; |
|
| 29 |
+ return x >= 0x01 && x <= 0x20; |
|
| 30 |
+} |
|
| 35 | 31 |
|
| 36 | 32 |
static inline std::string LeftTrimWhitespace(const std::string &orig) |
| 37 | 33 |
{
|
| 38 |
- auto first_non_space = std::find_if(orig.begin(), orig.end(), std::not1(IsWhitespace())); |
|
| 34 |
+ auto first_non_space = std::find_if(orig.begin(), orig.end(), [](const char &x) |
|
| 35 |
+ {
|
|
| 36 |
+ return !IsWhitespace(x); |
|
| 37 |
+ }); |
|
| 39 | 38 |
return std::string(first_non_space, orig.end()); |
| 40 | 39 |
} |
| 41 | 40 |
|
| 42 | 41 |
static inline std::string RightTrimWhitespace(const std::string &orig) |
| 43 | 42 |
{
|
| 44 |
- auto last_non_space = std::find_if(orig.rbegin(), orig.rend(), std::not1(IsWhitespace())).base(); |
|
| 43 |
+ auto last_non_space = std::find_if(orig.rbegin(), orig.rend(), [](const char &x) |
|
| 44 |
+ {
|
|
| 45 |
+ return !IsWhitespace(x); |
|
| 46 |
+ }).base(); |
|
| 45 | 47 |
return std::string(orig.begin(), last_non_space); |
| 46 | 48 |
} |
| 47 | 49 |
|
| ... | ... |
@@ -128,7 +128,7 @@ void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t p |
| 128 | 128 |
this->xSFType = PSFHeader[3]; |
| 129 | 129 |
|
| 130 | 130 |
this->rawData.resize(4); |
| 131 |
- memcpy(&this->rawData[0], PSFHeader, 4); |
|
| 131 |
+ std::copy_n(PSFHeader, 4, &this->rawData[0]); |
|
| 132 | 132 |
|
| 133 | 133 |
if (filesize < 16) |
| 134 | 134 |
throw std::runtime_error("File is too small.");
|
| ... | ... |
@@ -150,7 +150,7 @@ void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t p |
| 150 | 150 |
{
|
| 151 | 151 |
this->reservedSection.resize(reservedSize); |
| 152 | 152 |
xSF.read(reinterpret_cast<char *>(&this->reservedSection[0]), reservedSize); |
| 153 |
- memcpy(&this->rawData[16], &this->reservedSection[0], reservedSize); |
|
| 153 |
+ std::copy_n(&this->reservedSection[0], reservedSize, &this->rawData[16]); |
|
| 154 | 154 |
} |
| 155 | 155 |
} |
| 156 | 156 |
|
| ... | ... |
@@ -165,7 +165,7 @@ void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t p |
| 165 | 165 |
{
|
| 166 | 166 |
auto programSectionCompressed = std::vector<uint8_t>(programCompressedSize); |
| 167 | 167 |
xSF.read(reinterpret_cast<char *>(&programSectionCompressed[0]), programCompressedSize); |
| 168 |
- memcpy(&this->rawData[reservedSize + 16], &programSectionCompressed[0], programCompressedSize); |
|
| 168 |
+ std::copy_n(&programSectionCompressed[0], programCompressedSize, &this->rawData[reservedSize + 16]); |
|
| 169 | 169 |
|
| 170 | 170 |
auto programSectionUncompressed = std::vector<uint8_t>(programHeaderSize); |
| 171 | 171 |
unsigned long programUncompressedSize = programHeaderSize; |
* Replace the (w)stringify functions with the standard std::to_(w)string functions.
* Replace convertTo with versions that use type_traits to determine which standard string conversion function to call, as well as handle enums specically.
| ... | ... |
@@ -325,24 +325,24 @@ double XSFFile::GetVolume(VolumeType preferredVolumeType, PeakType preferredPeak |
| 325 | 325 |
bool hadReplayGain = false; |
| 326 | 326 |
if (preferredVolumeType == VOLUMETYPE_REPLAYGAIN_ALBUM && !replaygain_album_gain.empty()) |
| 327 | 327 |
{
|
| 328 |
- gain = convertTo<double>(replaygain_album_gain, false); |
|
| 328 |
+ gain = convertTo<double>(replaygain_album_gain); |
|
| 329 | 329 |
hadReplayGain = true; |
| 330 | 330 |
} |
| 331 | 331 |
if (!hadReplayGain && preferredVolumeType != VOLUMETYPE_VOLUME && !replaygain_track_gain.empty()) |
| 332 | 332 |
{
|
| 333 |
- gain = convertTo<double>(replaygain_track_gain, false); |
|
| 333 |
+ gain = convertTo<double>(replaygain_track_gain); |
|
| 334 | 334 |
hadReplayGain = true; |
| 335 | 335 |
} |
| 336 | 336 |
if (hadReplayGain) |
| 337 | 337 |
{
|
| 338 | 338 |
double vol = std::pow(10.0, gain / 20.0), peak = 1.0; |
| 339 | 339 |
if (preferredPeakType == PEAKTYPE_REPLAYGAIN_ALBUM && !replaygain_album_peak.empty()) |
| 340 |
- peak = convertTo<double>(replaygain_album_peak, false); |
|
| 340 |
+ peak = convertTo<double>(replaygain_album_peak); |
|
| 341 | 341 |
else if (preferredPeakType != PEAKTYPE_NONE && !replaygain_track_peak.empty()) |
| 342 |
- peak = convertTo<double>(replaygain_track_peak, false); |
|
| 342 |
+ peak = convertTo<double>(replaygain_track_peak); |
|
| 343 | 343 |
return !fEqual(peak, 1.0) ? std::min(vol, 1.0 / peak) : vol; |
| 344 | 344 |
} |
| 345 |
- return volume.empty() ? 1.0 : convertTo<double>(volume, false); |
|
| 345 |
+ return volume.empty() ? 1.0 : convertTo<double>(volume); |
|
| 346 | 346 |
} |
| 347 | 347 |
|
| 348 | 348 |
std::string XSFFile::FormattedTitleOptionalBlock(const std::string &block, bool &hadReplacement, unsigned level) const |
(I never remember to update these and besides, GitHub history can show when they were last modified.)
| ... | ... |
@@ -9,7 +9,7 @@ |
| 9 | 9 |
#include <algorithm> |
| 10 | 10 |
#include <functional> |
| 11 | 11 |
#include <stdexcept> |
| 12 |
-#include <zlib.h> |
|
| 12 |
+#include "zlib.h" |
|
| 13 | 13 |
#include "XSFFile.h" |
| 14 | 14 |
#include "XSFCommon.h" |
| 15 | 15 |
#include "convert.h" |
| ... | ... |
@@ -25,8 +25,9 @@ static inline void Set32BitsLE(uint32_t input, uint8_t *output) |
| 25 | 25 |
// The whitespace trimming was modified from the following answer on Stack Overflow: |
| 26 | 26 |
// http://stackoverflow.com/a/217605 |
| 27 | 27 |
|
| 28 |
-struct IsWhitespace : std::unary_function<char, bool> |
|
| 28 |
+struct IsWhitespace |
|
| 29 | 29 |
{
|
| 30 |
+ using argument_type = char;; |
|
| 30 | 31 |
bool operator()(const char &x) const |
| 31 | 32 |
{
|
| 32 | 33 |
return x >= 0x01 && x <= 0x20; |
* Removed my custom String class, as well as removed the really old
Unicode ConvertUTF, the UTF Converter, and the UTF Encode/Decode
functions.
* Replaced the above with using standard C++ std::wstring_convert and
std::codecvt_utf8.
* Added headers adapted from llvm's libc++ project for allowing the
above C++ classes to exist with GCC and Clang when libc++ isn't being
used.
* Used std::string over std::wstring whenever possible.
* Added header adapted from llvm's libc++ project to create special
versions of the ifstream and ofstream classes that would utilize _wfopen
on non-MSVC Windows compilers, so those compilers could access files on
Windows that use characters outside the current codepage.
* Removed the -static-libgcc and -static-libstdc++ flags from the
Makefile for non-MSVC builds. The generated DLLs will require extra DLLs
from either Cygwin or MinGW (whichever is used to compile), I've only
tested with MinGW and for some reason they crash Winamp on exit, I have
no idea why.
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* xSF - File structure |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2014-09-17 |
|
| 4 |
+ * Last modification on 2014-09-24 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Partially based on the vio*sf framework |
| 7 | 7 |
*/ |
| ... | ... |
@@ -64,13 +64,13 @@ XSFFile::XSFFile(const std::string &filename, uint32_t programSizeOffset, uint32 |
| 64 | 64 |
this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
| 65 | 65 |
} |
| 66 | 66 |
|
| 67 |
-#ifdef _MSC_VER |
|
| 68 |
-XSFFile::XSFFile(const std::wstring &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 67 |
+#ifdef _WIN32 |
|
| 68 |
+XSFFile::XSFFile(const std::wstring &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(ConvertFuncs::WStringToString(filename)) |
|
| 69 | 69 |
{
|
| 70 | 70 |
this->ReadXSF(filename, 0, 0, true); |
| 71 | 71 |
} |
| 72 | 72 |
|
| 73 |
-XSFFile::XSFFile(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 73 |
+XSFFile::XSFFile(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(ConvertFuncs::WStringToString(filename)) |
|
| 74 | 74 |
{
|
| 75 | 75 |
this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
| 76 | 76 |
} |
| ... | ... |
@@ -86,19 +86,27 @@ void XSFFile::ReadXSF(const std::string &filename, uint32_t programSizeOffset, u |
| 86 | 86 |
xSF.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); |
| 87 | 87 |
|
| 88 | 88 |
this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly); |
| 89 |
+ |
|
| 90 |
+ xSF.close(); |
|
| 89 | 91 |
} |
| 90 | 92 |
|
| 91 |
-#ifdef _MSC_VER |
|
| 93 |
+#ifdef _WIN32 |
|
| 92 | 94 |
void XSFFile::ReadXSF(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
| 93 | 95 |
{
|
| 94 | 96 |
if (!FileExists(filename)) |
| 95 |
- throw std::logic_error("File " + String(filename).GetAnsi() + " does not exist.");
|
|
| 97 |
+ throw std::logic_error("File " + ConvertFuncs::WStringToString(filename) + " does not exist.");
|
|
| 96 | 98 |
|
| 99 |
+#if defined(_WIN32) && !defined(_MSC_VER) |
|
| 100 |
+ ifstream_wfopen xSF; |
|
| 101 |
+#else |
|
| 97 | 102 |
std::ifstream xSF; |
| 103 |
+#endif |
|
| 98 | 104 |
xSF.exceptions(std::ifstream::failbit | std::ifstream::badbit); |
| 99 | 105 |
xSF.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); |
| 100 | 106 |
|
| 101 | 107 |
this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly); |
| 108 |
+ |
|
| 109 |
+ xSF.close(); |
|
| 102 | 110 |
} |
| 103 | 111 |
#endif |
| 104 | 112 |
|
| ... | ... |
@@ -214,8 +222,6 @@ void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t p |
| 214 | 222 |
} |
| 215 | 223 |
} |
| 216 | 224 |
|
| 217 |
- xSF.close(); |
|
| 218 |
- |
|
| 219 | 225 |
this->hasFile = true; |
| 220 | 226 |
} |
| 221 | 227 |
|
| ... | ... |
@@ -268,9 +274,14 @@ void XSFFile::SetAllTags(const TagList &newTags) |
| 268 | 274 |
this->tags = newTags; |
| 269 | 275 |
} |
| 270 | 276 |
|
| 271 |
-void XSFFile::SetTag(const std::string &name, const String &value) |
|
| 277 |
+void XSFFile::SetTag(const std::string &name, const std::string &value) |
|
| 278 |
+{
|
|
| 279 |
+ this->tags[name] = value; |
|
| 280 |
+} |
|
| 281 |
+ |
|
| 282 |
+void XSFFile::SetTag(const std::string &name, const std::wstring &value) |
|
| 272 | 283 |
{
|
| 273 |
- this->tags[name] = value.GetStr(); |
|
| 284 |
+ this->tags[name] = ConvertFuncs::WStringToString(value); |
|
| 274 | 285 |
} |
| 275 | 286 |
|
| 276 | 287 |
bool XSFFile::GetTagExists(const std::string &name) const |
| ... | ... |
@@ -278,17 +289,17 @@ bool XSFFile::GetTagExists(const std::string &name) const |
| 278 | 289 |
return this->tags.Exists(name); |
| 279 | 290 |
} |
| 280 | 291 |
|
| 281 |
-String XSFFile::GetTagValue(const std::string &name) const |
|
| 292 |
+std::string XSFFile::GetTagValue(const std::string &name) const |
|
| 282 | 293 |
{
|
| 283 |
- return String(this->GetTagExists(name) ? this->tags[name] : "", this->GetTagExists("utf8"));
|
|
| 294 |
+ return this->GetTagExists(name) ? this->tags[name] : ""; |
|
| 284 | 295 |
} |
| 285 | 296 |
|
| 286 | 297 |
unsigned long XSFFile::GetLengthMS(unsigned long defaultLength) const |
| 287 | 298 |
{
|
| 288 | 299 |
unsigned long length = 0; |
| 289 |
- String value = this->GetTagValue("length");
|
|
| 300 |
+ std::string value = this->GetTagValue("length");
|
|
| 290 | 301 |
if (!value.empty()) |
| 291 |
- length = ConvertFuncs::StringToMS(value.GetAnsi()); |
|
| 302 |
+ length = ConvertFuncs::StringToMS(value); |
|
| 292 | 303 |
if (!length) |
| 293 | 304 |
length = defaultLength; |
| 294 | 305 |
return length; |
| ... | ... |
@@ -297,9 +308,9 @@ unsigned long XSFFile::GetLengthMS(unsigned long defaultLength) const |
| 297 | 308 |
unsigned long XSFFile::GetFadeMS(unsigned long defaultFade) const |
| 298 | 309 |
{
|
| 299 | 310 |
unsigned long fade = defaultFade; |
| 300 |
- String value = this->GetTagValue("fade");
|
|
| 311 |
+ std::string value = this->GetTagValue("fade");
|
|
| 301 | 312 |
if (!value.empty()) |
| 302 |
- fade = ConvertFuncs::StringToMS(value.GetAnsi()); |
|
| 313 |
+ fade = ConvertFuncs::StringToMS(value); |
|
| 303 | 314 |
return fade; |
| 304 | 315 |
} |
| 305 | 316 |
|
| ... | ... |
@@ -307,49 +318,49 @@ double XSFFile::GetVolume(VolumeType preferredVolumeType, PeakType preferredPeak |
| 307 | 318 |
{
|
| 308 | 319 |
if (preferredVolumeType == VOLUMETYPE_NONE) |
| 309 | 320 |
return 1.0; |
| 310 |
- String replaygain_album_gain = this->GetTagValue("replaygain_album_gain"), replaygain_album_peak = this->GetTagValue("replaygain_album_peak");
|
|
| 311 |
- String replaygain_track_gain = this->GetTagValue("replaygain_track_gain"), replaygain_track_peak = this->GetTagValue("replaygain_track_peak");
|
|
| 312 |
- String volume = this->GetTagValue("volume");
|
|
| 321 |
+ std::string replaygain_album_gain = this->GetTagValue("replaygain_album_gain"), replaygain_album_peak = this->GetTagValue("replaygain_album_peak");
|
|
| 322 |
+ std::string replaygain_track_gain = this->GetTagValue("replaygain_track_gain"), replaygain_track_peak = this->GetTagValue("replaygain_track_peak");
|
|
| 323 |
+ std::string volume = this->GetTagValue("volume");
|
|
| 313 | 324 |
double gain = 0.0; |
| 314 | 325 |
bool hadReplayGain = false; |
| 315 | 326 |
if (preferredVolumeType == VOLUMETYPE_REPLAYGAIN_ALBUM && !replaygain_album_gain.empty()) |
| 316 | 327 |
{
|
| 317 |
- gain = convertTo<double>(replaygain_album_gain.GetAnsi(), false); |
|
| 328 |
+ gain = convertTo<double>(replaygain_album_gain, false); |
|
| 318 | 329 |
hadReplayGain = true; |
| 319 | 330 |
} |
| 320 | 331 |
if (!hadReplayGain && preferredVolumeType != VOLUMETYPE_VOLUME && !replaygain_track_gain.empty()) |
| 321 | 332 |
{
|
| 322 |
- gain = convertTo<double>(replaygain_track_gain.GetAnsi(), false); |
|
| 333 |
+ gain = convertTo<double>(replaygain_track_gain, false); |
|
| 323 | 334 |
hadReplayGain = true; |
| 324 | 335 |
} |
| 325 | 336 |
if (hadReplayGain) |
| 326 | 337 |
{
|
| 327 | 338 |
double vol = std::pow(10.0, gain / 20.0), peak = 1.0; |
| 328 | 339 |
if (preferredPeakType == PEAKTYPE_REPLAYGAIN_ALBUM && !replaygain_album_peak.empty()) |
| 329 |
- peak = convertTo<double>(replaygain_album_peak.GetAnsi(), false); |
|
| 340 |
+ peak = convertTo<double>(replaygain_album_peak, false); |
|
| 330 | 341 |
else if (preferredPeakType != PEAKTYPE_NONE && !replaygain_track_peak.empty()) |
| 331 |
- peak = convertTo<double>(replaygain_track_peak.GetAnsi(), false); |
|
| 342 |
+ peak = convertTo<double>(replaygain_track_peak, false); |
|
| 332 | 343 |
return !fEqual(peak, 1.0) ? std::min(vol, 1.0 / peak) : vol; |
| 333 | 344 |
} |
| 334 |
- return volume.empty() ? 1.0 : convertTo<double>(volume.GetAnsi(), false); |
|
| 345 |
+ return volume.empty() ? 1.0 : convertTo<double>(volume, false); |
|
| 335 | 346 |
} |
| 336 | 347 |
|
| 337 |
-String XSFFile::FormattedTitleOptionalBlock(const std::wstring &block, bool &hadReplacement, unsigned level) const |
|
| 348 |
+std::string XSFFile::FormattedTitleOptionalBlock(const std::string &block, bool &hadReplacement, unsigned level) const |
|
| 338 | 349 |
{
|
| 339 |
- String formattedBlock; |
|
| 350 |
+ std::string formattedBlock; |
|
| 340 | 351 |
for (size_t x = 0, len = block.length(); x < len; ++x) |
| 341 | 352 |
{
|
| 342 |
- wchar_t c = block[x]; |
|
| 343 |
- if (c == L'%') |
|
| 353 |
+ char c = block[x]; |
|
| 354 |
+ if (c == '%') |
|
| 344 | 355 |
{
|
| 345 | 356 |
size_t origX = x; |
| 346 | 357 |
for (++x; x < len; ++x) |
| 347 |
- if (block[x] == L'%') |
|
| 358 |
+ if (block[x] == '%') |
|
| 348 | 359 |
break; |
| 349 | 360 |
if (x != len) |
| 350 | 361 |
{
|
| 351 |
- std::wstring tagname = block.substr(origX + 1, x - origX - 1); |
|
| 352 |
- String value = this->GetTagValue(String(tagname).GetAnsi()); |
|
| 362 |
+ std::string tagname = block.substr(origX + 1, x - origX - 1); |
|
| 363 |
+ std::string value = this->GetTagValue(tagname); |
|
| 353 | 364 |
if (!value.empty()) |
| 354 | 365 |
{
|
| 355 | 366 |
formattedBlock += value; |
| ... | ... |
@@ -358,15 +369,15 @@ String XSFFile::FormattedTitleOptionalBlock(const std::wstring &block, bool &had |
| 358 | 369 |
} |
| 359 | 370 |
continue; |
| 360 | 371 |
} |
| 361 |
- if (c == L'[' && level + 1 < 10) |
|
| 372 |
+ if (c == '[' && level + 1 < 10) |
|
| 362 | 373 |
{
|
| 363 | 374 |
size_t origX = x; |
| 364 | 375 |
unsigned nests = 0; |
| 365 | 376 |
for (++x; x < len; ++x) |
| 366 | 377 |
{
|
| 367 |
- if (block[x] == L'[') |
|
| 378 |
+ if (block[x] == '[') |
|
| 368 | 379 |
++nests; |
| 369 |
- else if (block[x] == L']') |
|
| 380 |
+ else if (block[x] == ']') |
|
| 370 | 381 |
{
|
| 371 | 382 |
if (!nests) |
| 372 | 383 |
break; |
| ... | ... |
@@ -375,9 +386,9 @@ String XSFFile::FormattedTitleOptionalBlock(const std::wstring &block, bool &had |
| 375 | 386 |
} |
| 376 | 387 |
if (x != len) |
| 377 | 388 |
{
|
| 378 |
- std::wstring innerBlock = block.substr(origX + 1, x - origX - 1); |
|
| 389 |
+ std::string innerBlock = block.substr(origX + 1, x - origX - 1); |
|
| 379 | 390 |
bool hadInnerReplacement = false; |
| 380 |
- String replacedBlock = this->FormattedTitleOptionalBlock(innerBlock, hadInnerReplacement, level + 1); |
|
| 391 |
+ std::string replacedBlock = this->FormattedTitleOptionalBlock(innerBlock, hadInnerReplacement, level + 1); |
|
| 381 | 392 |
if (hadInnerReplacement) |
| 382 | 393 |
formattedBlock += replacedBlock; |
| 383 | 394 |
} |
| ... | ... |
@@ -388,37 +399,37 @@ String XSFFile::FormattedTitleOptionalBlock(const std::wstring &block, bool &had |
| 388 | 399 |
return formattedBlock; |
| 389 | 400 |
} |
| 390 | 401 |
|
| 391 |
-String XSFFile::GetFormattedTitle(const std::wstring &format) const |
|
| 402 |
+std::string XSFFile::GetFormattedTitle(const std::string &format) const |
|
| 392 | 403 |
{
|
| 393 |
- String formattedTitle; |
|
| 404 |
+ std::string formattedTitle; |
|
| 394 | 405 |
for (size_t x = 0, len = format.length(); x < len; ++x) |
| 395 | 406 |
{
|
| 396 |
- wchar_t c = format[x]; |
|
| 397 |
- if (c == L'%') |
|
| 407 |
+ char c = format[x]; |
|
| 408 |
+ if (c == '%') |
|
| 398 | 409 |
{
|
| 399 | 410 |
size_t origX = x; |
| 400 | 411 |
for (++x; x < len; ++x) |
| 401 |
- if (format[x] == L'%') |
|
| 412 |
+ if (format[x] == '%') |
|
| 402 | 413 |
break; |
| 403 | 414 |
if (x != len) |
| 404 | 415 |
{
|
| 405 |
- std::wstring tagname = format.substr(origX + 1, x - origX - 1); |
|
| 406 |
- String value = this->GetTagValue(String(tagname).GetAnsi()); |
|
| 416 |
+ std::string tagname = format.substr(origX + 1, x - origX - 1); |
|
| 417 |
+ std::string value = this->GetTagValue(tagname); |
|
| 407 | 418 |
if (value.empty()) |
| 408 | 419 |
formattedTitle += "???"; |
| 409 | 420 |
else |
| 410 | 421 |
formattedTitle += value; |
| 411 | 422 |
} |
| 412 | 423 |
} |
| 413 |
- else if (c == L'[') |
|
| 424 |
+ else if (c == '[') |
|
| 414 | 425 |
{
|
| 415 | 426 |
size_t origX = x; |
| 416 | 427 |
unsigned nests = 0; |
| 417 | 428 |
for (++x; x < len; ++x) |
| 418 | 429 |
{
|
| 419 |
- if (format[x] == L'[') |
|
| 430 |
+ if (format[x] == '[') |
|
| 420 | 431 |
++nests; |
| 421 |
- else if (format[x] == L']') |
|
| 432 |
+ else if (format[x] == ']') |
|
| 422 | 433 |
{
|
| 423 | 434 |
if (!nests) |
| 424 | 435 |
break; |
| ... | ... |
@@ -427,9 +438,9 @@ String XSFFile::GetFormattedTitle(const std::wstring &format) const |
| 427 | 438 |
} |
| 428 | 439 |
if (x != len) |
| 429 | 440 |
{
|
| 430 |
- std::wstring block = format.substr(origX + 1, x - origX - 1); |
|
| 441 |
+ std::string block = format.substr(origX + 1, x - origX - 1); |
|
| 431 | 442 |
bool hadReplacement = false; |
| 432 |
- String replacedBlock = this->FormattedTitleOptionalBlock(block, hadReplacement, 1); |
|
| 443 |
+ std::string replacedBlock = this->FormattedTitleOptionalBlock(block, hadReplacement, 1); |
|
| 433 | 444 |
if (hadReplacement) |
| 434 | 445 |
formattedTitle += replacedBlock; |
| 435 | 446 |
} |
| ... | ... |
@@ -440,24 +451,28 @@ String XSFFile::GetFormattedTitle(const std::wstring &format) const |
| 440 | 451 |
return formattedTitle; |
| 441 | 452 |
} |
| 442 | 453 |
|
| 443 |
-String XSFFile::GetFilename() const |
|
| 454 |
+std::string XSFFile::GetFilename() const |
|
| 444 | 455 |
{
|
| 445 | 456 |
return this->fileName; |
| 446 | 457 |
} |
| 447 | 458 |
|
| 448 |
-String XSFFile::GetFilenameWithoutPath() const |
|
| 459 |
+std::string XSFFile::GetFilenameWithoutPath() const |
|
| 449 | 460 |
{
|
| 450 |
- return ExtractFilenameFromPath(this->fileName.GetStr()); |
|
| 461 |
+ return ExtractFilenameFromPath(this->fileName); |
|
| 451 | 462 |
} |
| 452 | 463 |
|
| 453 | 464 |
void XSFFile::SaveFile() const |
| 454 | 465 |
{
|
| 466 |
+#if defined(_WIN32) && !defined(_MSC_VER) |
|
| 467 |
+ ofstream_wfopen xSF; |
|
| 468 |
+#else |
|
| 455 | 469 |
std::ofstream xSF; |
| 470 |
+#endif |
|
| 456 | 471 |
xSF.exceptions(std::ofstream::failbit); |
| 457 |
-#ifdef _MSC_VER |
|
| 458 |
- xSF.open(this->fileName.GetWStrC(), std::ofstream::out | std::ofstream::binary); |
|
| 472 |
+#ifdef _WIN32 |
|
| 473 |
+ xSF.open(ConvertFuncs::StringToWString(this->fileName).c_str(), std::ofstream::out | std::ofstream::binary); |
|
| 459 | 474 |
#else |
| 460 |
- xSF.open(this->fileName.GetStrC(), std::ofstream::out | std::ofstream::binary); |
|
| 475 |
+ xSF.open(this->fileName.c_str(), std::ofstream::out | std::ofstream::binary); |
|
| 461 | 476 |
#endif |
| 462 | 477 |
|
| 463 | 478 |
xSF.write(reinterpret_cast<const char *>(&this->rawData[0]), this->rawData.size()); |
* [2SF] Used more up-to-date asmjit, despite the ugly looking code.
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* xSF - File structure |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-03-30 |
|
| 4 |
+ * Last modification on 2014-09-17 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Partially based on the vio*sf framework |
| 7 | 7 |
*/ |
| ... | ... |
@@ -64,7 +64,7 @@ XSFFile::XSFFile(const std::string &filename, uint32_t programSizeOffset, uint32 |
| 64 | 64 |
this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
| 65 | 65 |
} |
| 66 | 66 |
|
| 67 |
-#ifdef _WIN32 |
|
| 67 |
+#ifdef _MSC_VER |
|
| 68 | 68 |
XSFFile::XSFFile(const std::wstring &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
| 69 | 69 |
{
|
| 70 | 70 |
this->ReadXSF(filename, 0, 0, true); |
| ... | ... |
@@ -88,7 +88,7 @@ void XSFFile::ReadXSF(const std::string &filename, uint32_t programSizeOffset, u |
| 88 | 88 |
this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly); |
| 89 | 89 |
} |
| 90 | 90 |
|
| 91 |
-#ifdef _WIN32 |
|
| 91 |
+#ifdef _MSC_VER |
|
| 92 | 92 |
void XSFFile::ReadXSF(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
| 93 | 93 |
{
|
| 94 | 94 |
if (!FileExists(filename)) |
| ... | ... |
@@ -454,7 +454,7 @@ void XSFFile::SaveFile() const |
| 454 | 454 |
{
|
| 455 | 455 |
std::ofstream xSF; |
| 456 | 456 |
xSF.exceptions(std::ofstream::failbit); |
| 457 |
-#ifdef _WIN32 |
|
| 457 |
+#ifdef _MSC_VER |
|
| 458 | 458 |
xSF.open(this->fileName.GetWStrC(), std::ofstream::out | std::ofstream::binary); |
| 459 | 459 |
#else |
| 460 | 460 |
xSF.open(this->fileName.GetStrC(), std::ofstream::out | std::ofstream::binary); |
| ... | ... |
@@ -466,10 +466,10 @@ void XSFFile::SaveFile() const |
| 466 | 466 |
if (!allTags.empty()) |
| 467 | 467 |
{
|
| 468 | 468 |
xSF.write("[TAG]", 5);
|
| 469 |
- for (auto curr = allTags.begin(), end = allTags.end(); curr != end; ++curr) |
|
| 469 |
+ std::for_each(allTags.begin(), allTags.end(), [&](const std::string &tag) |
|
| 470 | 470 |
{
|
| 471 |
- xSF.write(curr->c_str(), curr->length()); |
|
| 471 |
+ xSF.write(tag.c_str(), tag.length()); |
|
| 472 | 472 |
xSF.write("\n", 1);
|
| 473 |
- } |
|
| 473 |
+ }); |
|
| 474 | 474 |
} |
| 475 | 475 |
} |
| ... | ... |
@@ -447,7 +447,7 @@ String XSFFile::GetFilename() const |
| 447 | 447 |
|
| 448 | 448 |
String XSFFile::GetFilenameWithoutPath() const |
| 449 | 449 |
{
|
| 450 |
- return ExtractDirectoryFromPath(this->fileName.GetStr()); |
|
| 450 |
+ return ExtractFilenameFromPath(this->fileName.GetStr()); |
|
| 451 | 451 |
} |
| 452 | 452 |
|
| 453 | 453 |
void XSFFile::SaveFile() const |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,475 @@ |
| 1 |
+/* |
|
| 2 |
+ * xSF - File structure |
|
| 3 |
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
|
| 4 |
+ * Last modification on 2013-03-25 |
|
| 5 |
+ * |
|
| 6 |
+ * Partially based on the vio*sf framework |
|
| 7 |
+ */ |
|
| 8 |
+ |
|
| 9 |
+#include <algorithm> |
|
| 10 |
+#include <functional> |
|
| 11 |
+#include <stdexcept> |
|
| 12 |
+#include <zlib.h> |
|
| 13 |
+#include "XSFFile.h" |
|
| 14 |
+#include "XSFCommon.h" |
|
| 15 |
+#include "convert.h" |
|
| 16 |
+ |
|
| 17 |
+static inline void Set32BitsLE(uint32_t input, uint8_t *output) |
|
| 18 |
+{
|
|
| 19 |
+ output[0] = input & 0xFF; |
|
| 20 |
+ output[1] = (input >> 8) & 0xFF; |
|
| 21 |
+ output[2] = (input >> 16) & 0xFF; |
|
| 22 |
+ output[3] = (input >> 24) & 0xFF; |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+// The whitespace trimming was modified from the following answer on Stack Overflow: |
|
| 26 |
+// http://stackoverflow.com/a/217605 |
|
| 27 |
+ |
|
| 28 |
+struct IsWhitespace : std::unary_function<char, bool> |
|
| 29 |
+{
|
|
| 30 |
+ bool operator()(const char &x) const |
|
| 31 |
+ {
|
|
| 32 |
+ return x >= 0x01 && x <= 0x20; |
|
| 33 |
+ } |
|
| 34 |
+}; |
|
| 35 |
+ |
|
| 36 |
+static inline std::string LeftTrimWhitespace(const std::string &orig) |
|
| 37 |
+{
|
|
| 38 |
+ auto first_non_space = std::find_if(orig.begin(), orig.end(), std::not1(IsWhitespace())); |
|
| 39 |
+ return std::string(first_non_space, orig.end()); |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+static inline std::string RightTrimWhitespace(const std::string &orig) |
|
| 43 |
+{
|
|
| 44 |
+ auto last_non_space = std::find_if(orig.rbegin(), orig.rend(), std::not1(IsWhitespace())).base(); |
|
| 45 |
+ return std::string(orig.begin(), last_non_space); |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+static inline std::string TrimWhitespace(const std::string &orig) |
|
| 49 |
+{
|
|
| 50 |
+ return LeftTrimWhitespace(RightTrimWhitespace(orig)); |
|
| 51 |
+} |
|
| 52 |
+ |
|
| 53 |
+XSFFile::XSFFile() : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName("")
|
|
| 54 |
+{
|
|
| 55 |
+} |
|
| 56 |
+ |
|
| 57 |
+XSFFile::XSFFile(const std::string &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 58 |
+{
|
|
| 59 |
+ this->ReadXSF(filename, 0, 0, true); |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+XSFFile::XSFFile(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 63 |
+{
|
|
| 64 |
+ this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+#ifdef _WIN32 |
|
| 68 |
+XSFFile::XSFFile(const std::wstring &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 69 |
+{
|
|
| 70 |
+ this->ReadXSF(filename, 0, 0, true); |
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+XSFFile::XSFFile(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename) |
|
| 74 |
+{
|
|
| 75 |
+ this->ReadXSF(filename, programSizeOffset, programHeaderSize); |
|
| 76 |
+} |
|
| 77 |
+#endif |
|
| 78 |
+ |
|
| 79 |
+void XSFFile::ReadXSF(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
|
| 80 |
+{
|
|
| 81 |
+ if (!FileExists(filename)) |
|
| 82 |
+ throw std::logic_error("File " + filename + " does not exist.");
|
|
| 83 |
+ |
|
| 84 |
+ std::ifstream xSF; |
|
| 85 |
+ xSF.exceptions(std::ifstream::failbit | std::ifstream::badbit); |
|
| 86 |
+ xSF.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); |
|
| 87 |
+ |
|
| 88 |
+ this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly); |
|
| 89 |
+} |
|
| 90 |
+ |
|
| 91 |
+#ifdef _WIN32 |
|
| 92 |
+void XSFFile::ReadXSF(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
|
| 93 |
+{
|
|
| 94 |
+ if (!FileExists(filename)) |
|
| 95 |
+ throw std::logic_error("File " + String(filename).GetAnsi() + " does not exist.");
|
|
| 96 |
+ |
|
| 97 |
+ std::ifstream xSF; |
|
| 98 |
+ xSF.exceptions(std::ifstream::failbit | std::ifstream::badbit); |
|
| 99 |
+ xSF.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); |
|
| 100 |
+ |
|
| 101 |
+ this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly); |
|
| 102 |
+} |
|
| 103 |
+#endif |
|
| 104 |
+ |
|
| 105 |
+void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly) |
|
| 106 |
+{
|
|
| 107 |
+ xSF.seekg(0, std::ifstream::end); |
|
| 108 |
+ auto filesize = xSF.tellg(); |
|
| 109 |
+ xSF.seekg(0, std::ifstream::beg); |
|
| 110 |
+ |
|
| 111 |
+ if (filesize < 4) |
|
| 112 |
+ throw std::runtime_error("File is too small.");
|
|
| 113 |
+ |
|
| 114 |
+ char PSFHeader[4]; |
|
| 115 |
+ xSF.read(PSFHeader, 4); |
|
| 116 |
+ |
|
| 117 |
+ if (PSFHeader[0] != 'P' || PSFHeader[1] != 'S' || PSFHeader[2] != 'F') |
|
| 118 |
+ throw std::runtime_error("Not a PSF file.");
|
|
| 119 |
+ |
|
| 120 |
+ this->xSFType = PSFHeader[3]; |
|
| 121 |
+ |
|
| 122 |
+ this->rawData.resize(4); |
|
| 123 |
+ memcpy(&this->rawData[0], PSFHeader, 4); |
|
| 124 |
+ |
|
| 125 |
+ if (filesize < 16) |
|
| 126 |
+ throw std::runtime_error("File is too small.");
|
|
| 127 |
+ |
|
| 128 |
+ uint32_t reservedSize = Get32BitsLE(xSF), programCompressedSize = Get32BitsLE(xSF); |
|
| 129 |
+ this->rawData.resize(reservedSize + programCompressedSize + 16); |
|
| 130 |
+ Set32BitsLE(reservedSize, &this->rawData[4]); |
|
| 131 |
+ Set32BitsLE(programCompressedSize, &this->rawData[8]); |
|
| 132 |
+ xSF.read(reinterpret_cast<char *>(&this->rawData[12]), 4); |
|
| 133 |
+ |
|
| 134 |
+ if (reservedSize) |
|
| 135 |
+ {
|
|
| 136 |
+ if (filesize < reservedSize + 16) |
|
| 137 |
+ throw std::runtime_error("File is too small.");
|
|
| 138 |
+ |
|
| 139 |
+ if (readTagsOnly) |
|
| 140 |
+ xSF.read(reinterpret_cast<char *>(&this->rawData[16]), reservedSize); |
|
| 141 |
+ else |
|
| 142 |
+ {
|
|
| 143 |
+ this->reservedSection.resize(reservedSize); |
|
| 144 |
+ xSF.read(reinterpret_cast<char *>(&this->reservedSection[0]), reservedSize); |
|
| 145 |
+ memcpy(&this->rawData[16], &this->reservedSection[0], reservedSize); |
|
| 146 |
+ } |
|
| 147 |
+ } |
|
| 148 |
+ |
|
| 149 |
+ if (programCompressedSize) |
|
| 150 |
+ {
|
|
| 151 |
+ if (filesize < reservedSize + programCompressedSize + 16) |
|
| 152 |
+ throw std::runtime_error("File is too small.");
|
|
| 153 |
+ |
|
| 154 |
+ if (readTagsOnly) |
|
| 155 |
+ xSF.read(reinterpret_cast<char *>(&this->rawData[reservedSize + 16]), programCompressedSize); |
|
| 156 |
+ else |
|
| 157 |
+ {
|
|
| 158 |
+ auto programSectionCompressed = std::vector<uint8_t>(programCompressedSize); |
|
| 159 |
+ xSF.read(reinterpret_cast<char *>(&programSectionCompressed[0]), programCompressedSize); |
|
| 160 |
+ memcpy(&this->rawData[reservedSize + 16], &programSectionCompressed[0], programCompressedSize); |
|
| 161 |
+ |
|
| 162 |
+ auto programSectionUncompressed = std::vector<uint8_t>(programHeaderSize); |
|
| 163 |
+ unsigned long programUncompressedSize = programHeaderSize; |
|
| 164 |
+ uncompress(&programSectionUncompressed[0], &programUncompressedSize, &programSectionCompressed[0], programCompressedSize); |
|
| 165 |
+ programUncompressedSize = Get32BitsLE(&programSectionUncompressed[programSizeOffset]) + programHeaderSize; |
|
| 166 |
+ this->programSection.resize(programUncompressedSize); |
|
| 167 |
+ uncompress(&this->programSection[0], &programUncompressedSize, &programSectionCompressed[0], programCompressedSize); |
|
| 168 |
+ } |
|
| 169 |
+ } |
|
| 170 |
+ |
|
| 171 |
+ if (xSF.tellg() != filesize && filesize >= reservedSize + programCompressedSize + 21) |
|
| 172 |
+ {
|
|
| 173 |
+ char tagheader[6] = ""; |
|
| 174 |
+ xSF.read(tagheader, 5); |
|
| 175 |
+ if (std::string(tagheader) == "[TAG]") |
|
| 176 |
+ {
|
|
| 177 |
+ auto startOfTags = xSF.tellg(); |
|
| 178 |
+ unsigned lengthOfTags = static_cast<unsigned>(filesize - startOfTags); |
|
| 179 |
+ if (lengthOfTags) |
|
| 180 |
+ {
|
|
| 181 |
+ auto rawtags = std::vector<char>(lengthOfTags); |
|
| 182 |
+ xSF.read(&rawtags[0], lengthOfTags); |
|
| 183 |
+ std::string name, value; |
|
| 184 |
+ bool onName = true; |
|
| 185 |
+ for (unsigned x = 0; x < lengthOfTags; ++x) |
|
| 186 |
+ {
|
|
| 187 |
+ char curr = rawtags[x]; |
|
| 188 |
+ if (curr == 0x0A) |
|
| 189 |
+ {
|
|
| 190 |
+ if (!name.empty() && !value.empty()) |
|
| 191 |
+ {
|
|
| 192 |
+ name = TrimWhitespace(name); |
|
| 193 |
+ value = TrimWhitespace(value); |
|
| 194 |
+ if (this->tags.Exists(name)) |
|
| 195 |
+ this->tags[name] += "\n" + value; |
|
| 196 |
+ else |
|
| 197 |
+ this->tags[name] = value; |
|
| 198 |
+ } |
|
| 199 |
+ name = value = ""; |
|
| 200 |
+ onName = true; |
|
| 201 |
+ continue; |
|
| 202 |
+ } |
|
| 203 |
+ if (curr == '=') |
|
| 204 |
+ {
|
|
| 205 |
+ onName = false; |
|
| 206 |
+ continue; |
|
| 207 |
+ } |
|
| 208 |
+ if (onName) |
|
| 209 |
+ name += curr; |
|
| 210 |
+ else |
|
| 211 |
+ value += curr; |
|
| 212 |
+ } |
|
| 213 |
+ } |
|
| 214 |
+ } |
|
| 215 |
+ } |
|
| 216 |
+ |
|
| 217 |
+ xSF.close(); |
|
| 218 |
+ |
|
| 219 |
+ this->hasFile = true; |
|
| 220 |
+} |
|
| 221 |
+ |
|
| 222 |
+bool XSFFile::IsValidType(uint8_t type) const |
|
| 223 |
+{
|
|
| 224 |
+ return this->xSFType == type; |
|
| 225 |
+} |
|
| 226 |
+ |
|
| 227 |
+void XSFFile::Clear() |
|
| 228 |
+{
|
|
| 229 |
+ this->xSFType = 0; |
|
| 230 |
+ this->hasFile = false; |
|
| 231 |
+ this->reservedSection.clear(); |
|
| 232 |
+ this->programSection.clear(); |
|
| 233 |
+ this->tags.Clear(); |
|
| 234 |
+} |
|
| 235 |
+ |
|
| 236 |
+bool XSFFile::HasFile() const |
|
| 237 |
+{
|
|
| 238 |
+ return this->hasFile; |
|
| 239 |
+} |
|
| 240 |
+ |
|
| 241 |
+std::vector<uint8_t> &XSFFile::GetReservedSection() |
|
| 242 |
+{
|
|
| 243 |
+ return this->reservedSection; |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 246 |
+std::vector<uint8_t> XSFFile::GetReservedSection() const |
|
| 247 |
+{
|
|
| 248 |
+ return this->reservedSection; |
|
| 249 |
+} |
|
| 250 |
+ |
|
| 251 |
+std::vector<uint8_t> &XSFFile::GetProgramSection() |
|
| 252 |
+{
|
|
| 253 |
+ return this->programSection; |
|
| 254 |
+} |
|
| 255 |
+ |
|
| 256 |
+std::vector<uint8_t> XSFFile::GetProgramSection() const |
|
| 257 |
+{
|
|
| 258 |
+ return this->programSection; |
|
| 259 |
+} |
|
| 260 |
+ |
|
| 261 |
+const TagList &XSFFile::GetAllTags() const |
|
| 262 |
+{
|
|
| 263 |
+ return this->tags; |
|
| 264 |
+} |
|
| 265 |
+ |
|
| 266 |
+void XSFFile::SetAllTags(const TagList &newTags) |
|
| 267 |
+{
|
|
| 268 |
+ this->tags = newTags; |
|
| 269 |
+} |
|
| 270 |
+ |
|
| 271 |
+void XSFFile::SetTag(const std::string &name, const String &value) |
|
| 272 |
+{
|
|
| 273 |
+ this->tags[name] = value.GetStr(); |
|
| 274 |
+} |
|
| 275 |
+ |
|
| 276 |
+bool XSFFile::GetTagExists(const std::string &name) const |
|
| 277 |
+{
|
|
| 278 |
+ return this->tags.Exists(name); |
|
| 279 |
+} |
|
| 280 |
+ |
|
| 281 |
+String XSFFile::GetTagValue(const std::string &name) const |
|
| 282 |
+{
|
|
| 283 |
+ return String(this->GetTagExists(name) ? this->tags[name] : "", this->GetTagExists("utf8"));
|
|
| 284 |
+} |
|
| 285 |
+ |
|
| 286 |
+unsigned long XSFFile::GetLengthMS(unsigned long defaultLength) const |
|
| 287 |
+{
|
|
| 288 |
+ unsigned long length = 0; |
|
| 289 |
+ String value = this->GetTagValue("length");
|
|
| 290 |
+ if (!value.empty()) |
|
| 291 |
+ length = ConvertFuncs::StringToMS(value.GetAnsi()); |
|
| 292 |
+ if (!length) |
|
| 293 |
+ length = defaultLength; |
|
| 294 |
+ return length; |
|
| 295 |
+} |
|
| 296 |
+ |
|
| 297 |
+unsigned long XSFFile::GetFadeMS(unsigned long defaultFade) const |
|
| 298 |
+{
|
|
| 299 |
+ unsigned long fade = defaultFade; |
|
| 300 |
+ String value = this->GetTagValue("fade");
|
|
| 301 |
+ if (!value.empty()) |
|
| 302 |
+ fade = ConvertFuncs::StringToMS(value.GetAnsi()); |
|
| 303 |
+ return fade; |
|
| 304 |
+} |
|
| 305 |
+ |
|
| 306 |
+double XSFFile::GetVolume(VolumeType preferredVolumeType, PeakType preferredPeakType) const |
|
| 307 |
+{
|
|
| 308 |
+ if (preferredVolumeType == VOLUMETYPE_NONE) |
|
| 309 |
+ return 1.0; |
|
| 310 |
+ String replaygain_album_gain = this->GetTagValue("replaygain_album_gain"), replaygain_album_peak = this->GetTagValue("replaygain_album_peak");
|
|
| 311 |
+ String replaygain_track_gain = this->GetTagValue("replaygain_track_gain"), replaygain_track_peak = this->GetTagValue("replaygain_track_peak");
|
|
| 312 |
+ String volume = this->GetTagValue("volume");
|
|
| 313 |
+ double gain = 0.0; |
|
| 314 |
+ bool hadReplayGain = false; |
|
| 315 |
+ if (preferredVolumeType == VOLUMETYPE_REPLAYGAIN_ALBUM && !replaygain_album_gain.empty()) |
|
| 316 |
+ {
|
|
| 317 |
+ gain = convertTo<double>(replaygain_album_gain.GetAnsi(), false); |
|
| 318 |
+ hadReplayGain = true; |
|
| 319 |
+ } |
|
| 320 |
+ if (!hadReplayGain && preferredVolumeType != VOLUMETYPE_VOLUME && !replaygain_track_gain.empty()) |
|
| 321 |
+ {
|
|
| 322 |
+ gain = convertTo<double>(replaygain_track_gain.GetAnsi(), false); |
|
| 323 |
+ hadReplayGain = true; |
|
| 324 |
+ } |
|
| 325 |
+ if (hadReplayGain) |
|
| 326 |
+ {
|
|
| 327 |
+ double vol = std::pow(10.0, gain / 20.0), peak = 1.0; |
|
| 328 |
+ if (preferredPeakType == PEAKTYPE_REPLAYGAIN_ALBUM && !replaygain_album_peak.empty()) |
|
| 329 |
+ peak = convertTo<double>(replaygain_album_peak.GetAnsi(), false); |
|
| 330 |
+ else if (preferredPeakType != PEAKTYPE_NONE && !replaygain_track_peak.empty()) |
|
| 331 |
+ peak = convertTo<double>(replaygain_track_peak.GetAnsi(), false); |
|
| 332 |
+ return !fEqual(peak, 1.0) ? std::min(vol, 1.0 / peak) : vol; |
|
| 333 |
+ } |
|
| 334 |
+ return volume.empty() ? 1.0 : convertTo<double>(volume.GetAnsi(), false); |
|
| 335 |
+} |
|
| 336 |
+ |
|
| 337 |
+String XSFFile::FormattedTitleOptionalBlock(const std::wstring &block, bool &hadReplacement, unsigned level) const |
|
| 338 |
+{
|
|
| 339 |
+ String formattedBlock; |
|
| 340 |
+ for (size_t x = 0, len = block.length(); x < len; ++x) |
|
| 341 |
+ {
|
|
| 342 |
+ wchar_t c = block[x]; |
|
| 343 |
+ if (c == L'%') |
|
| 344 |
+ {
|
|
| 345 |
+ size_t origX = x; |
|
| 346 |
+ for (++x; x < len; ++x) |
|
| 347 |
+ if (block[x] == L'%') |
|
| 348 |
+ break; |
|
| 349 |
+ if (x != len) |
|
| 350 |
+ {
|
|
| 351 |
+ std::wstring tagname = block.substr(origX + 1, x - origX - 1); |
|
| 352 |
+ String value = this->GetTagValue(String(tagname).GetAnsi()); |
|
| 353 |
+ if (!value.empty()) |
|
| 354 |
+ {
|
|
| 355 |
+ formattedBlock += value; |
|
| 356 |
+ hadReplacement = true; |
|
| 357 |
+ } |
|
| 358 |
+ } |
|
| 359 |
+ continue; |
|
| 360 |
+ } |
|
| 361 |
+ if (c == L'[' && level + 1 < 10) |
|
| 362 |
+ {
|
|
| 363 |
+ size_t origX = x; |
|
| 364 |
+ unsigned nests = 0; |
|
| 365 |
+ for (++x; x < len; ++x) |
|
| 366 |
+ {
|
|
| 367 |
+ if (block[x] == L'[') |
|
| 368 |
+ ++nests; |
|
| 369 |
+ else if (block[x] == L']') |
|
| 370 |
+ {
|
|
| 371 |
+ if (!nests) |
|
| 372 |
+ break; |
|
| 373 |
+ --nests; |
|
| 374 |
+ } |
|
| 375 |
+ } |
|
| 376 |
+ if (x != len) |
|
| 377 |
+ {
|
|
| 378 |
+ std::wstring innerBlock = block.substr(origX + 1, x - origX - 1); |
|
| 379 |
+ bool hadInnerReplacement = false; |
|
| 380 |
+ String replacedBlock = this->FormattedTitleOptionalBlock(innerBlock, hadInnerReplacement, level + 1); |
|
| 381 |
+ if (hadInnerReplacement) |
|
| 382 |
+ formattedBlock += replacedBlock; |
|
| 383 |
+ } |
|
| 384 |
+ continue; |
|
| 385 |
+ } |
|
| 386 |
+ formattedBlock += c; |
|
| 387 |
+ } |
|
| 388 |
+ return formattedBlock; |
|
| 389 |
+} |
|
| 390 |
+ |
|
| 391 |
+String XSFFile::GetFormattedTitle(const std::wstring &format) const |
|
| 392 |
+{
|
|
| 393 |
+ String formattedTitle; |
|
| 394 |
+ for (size_t x = 0, len = format.length(); x < len; ++x) |
|
| 395 |
+ {
|
|
| 396 |
+ wchar_t c = format[x]; |
|
| 397 |
+ if (c == L'%') |
|
| 398 |
+ {
|
|
| 399 |
+ size_t origX = x; |
|
| 400 |
+ for (++x; x < len; ++x) |
|
| 401 |
+ if (format[x] == L'%') |
|
| 402 |
+ break; |
|
| 403 |
+ if (x != len) |
|
| 404 |
+ {
|
|
| 405 |
+ std::wstring tagname = format.substr(origX + 1, x - origX - 1); |
|
| 406 |
+ String value = this->GetTagValue(String(tagname).GetAnsi()); |
|
| 407 |
+ if (value.empty()) |
|
| 408 |
+ formattedTitle += "???"; |
|
| 409 |
+ else |
|
| 410 |
+ formattedTitle += value; |
|
| 411 |
+ } |
|
| 412 |
+ } |
|
| 413 |
+ else if (c == L'[') |
|
| 414 |
+ {
|
|
| 415 |
+ size_t origX = x; |
|
| 416 |
+ unsigned nests = 0; |
|
| 417 |
+ for (++x; x < len; ++x) |
|
| 418 |
+ {
|
|
| 419 |
+ if (format[x] == L'[') |
|
| 420 |
+ ++nests; |
|
| 421 |
+ else if (format[x] == L']') |
|
| 422 |
+ {
|
|
| 423 |
+ if (!nests) |
|
| 424 |
+ break; |
|
| 425 |
+ --nests; |
|
| 426 |
+ } |
|
| 427 |
+ } |
|
| 428 |
+ if (x != len) |
|
| 429 |
+ {
|
|
| 430 |
+ std::wstring block = format.substr(origX + 1, x - origX - 1); |
|
| 431 |
+ bool hadReplacement = false; |
|
| 432 |
+ String replacedBlock = this->FormattedTitleOptionalBlock(block, hadReplacement, 1); |
|
| 433 |
+ if (hadReplacement) |
|
| 434 |
+ formattedTitle += replacedBlock; |
|
| 435 |
+ } |
|
| 436 |
+ } |
|
| 437 |
+ else |
|
| 438 |
+ formattedTitle += c; |
|
| 439 |
+ } |
|
| 440 |
+ return formattedTitle; |
|
| 441 |
+} |
|
| 442 |
+ |
|
| 443 |
+String XSFFile::GetFilename() const |
|
| 444 |
+{
|
|
| 445 |
+ return this->fileName; |
|
| 446 |
+} |
|
| 447 |
+ |
|
| 448 |
+String XSFFile::GetFilenameWithoutPath() const |
|
| 449 |
+{
|
|
| 450 |
+ return ExtractDirectoryFromPath(this->fileName.GetStr()); |
|
| 451 |
+} |
|
| 452 |
+ |
|
| 453 |
+void XSFFile::SaveFile() const |
|
| 454 |
+{
|
|
| 455 |
+ std::ofstream xSF; |
|
| 456 |
+ xSF.exceptions(std::ofstream::failbit); |
|
| 457 |
+#ifdef _WIN32 |
|
| 458 |
+ xSF.open(this->fileName.GetWStrC(), std::ofstream::out | std::ofstream::binary); |
|
| 459 |
+#else |
|
| 460 |
+ xSF.open(this->fileName.GetStrC(), std::ofstream::out | std::ofstream::binary); |
|
| 461 |
+#endif |
|
| 462 |
+ |
|
| 463 |
+ xSF.write(reinterpret_cast<const char *>(&this->rawData[0]), this->rawData.size()); |
|
| 464 |
+ |
|
| 465 |
+ auto allTags = this->tags.GetTags(); |
|
| 466 |
+ if (!allTags.empty()) |
|
| 467 |
+ {
|
|
| 468 |
+ xSF.write("[TAG]", 5);
|
|
| 469 |
+ for (auto curr = allTags.begin(), end = allTags.end(); curr != end; ++curr) |
|
| 470 |
+ {
|
|
| 471 |
+ xSF.write(curr->c_str(), curr->length()); |
|
| 472 |
+ xSF.write("\n", 1);
|
|
| 473 |
+ } |
|
| 474 |
+ } |
|
| 475 |
+} |