diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/BigSString.h b/Frameworks/SSEQPlayer/SSEQPlayer/BigSString.h deleted file mode 100644 index d40ce8b58..000000000 --- a/Frameworks/SSEQPlayer/SSEQPlayer/BigSString.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * String class in ANSI (or rather, current Windows code page), UTF-8, and UTF-16 - * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-25 - */ - -#ifndef BIGSSTRING_H -#define BIGSSTRING_H - -#include -#include -#include -#include "UtfConverter.h" -#include "UTFEncodeDecode.h" - -class String -{ -public: - String(const std::locale &L = std::locale::classic()) : ansi(""), utf8(""), utf16(L""), loc(L) { } - String(const char *new_str, bool is_utf8 = false, const std::locale &L = std::locale::classic()) : ansi(is_utf8 ? DecodeFromUTF8(new_str, L) : new_str), utf8(is_utf8 ? new_str : EncodeToUTF8(new_str, L)), - utf16(UtfConverter::FromUtf8(utf8)), loc(L) { } - String(const std::string &new_str, bool is_utf8 = false, const std::locale &L = std::locale::classic()) : ansi(is_utf8 ? DecodeFromUTF8(new_str, L) : new_str), utf8(is_utf8 ? new_str : EncodeToUTF8(new_str, L)), - utf16(UtfConverter::FromUtf8(utf8)), loc(L) { } - String(const wchar_t *new_wstr, const std::locale &L = std::locale::classic()) : ansi(DecodeFromUTF8(UtfConverter::ToUtf8(new_wstr), L)), utf8(UtfConverter::ToUtf8(new_wstr)), utf16(new_wstr), loc(L) { } - String(const std::wstring &new_wstr, const std::locale &L = std::locale::classic()) : ansi(DecodeFromUTF8(UtfConverter::ToUtf8(new_wstr), L)), utf8(UtfConverter::ToUtf8(new_wstr)), utf16(new_wstr), loc(L) { } - bool empty() const { return this->utf8.empty(); } - std::string GetAnsi() const { return this->ansi; } - const char *GetAnsiC() const { return this->ansi.c_str(); } - std::string GetStr() const { return this->utf8; } - const char *GetStrC() const { return this->utf8.c_str(); } - std::wstring GetWStr() const { return this->utf16; } - const wchar_t *GetWStrC() const { return this->utf16.c_str(); } - bool operator==(const String &str2) const - { - return this->utf8 == str2.utf8; - } - String &operator=(const std::string &new_str) - { - this->ansi = DecodeFromUTF8(new_str, this->loc); - this->utf8 = new_str; - this->utf16 = UtfConverter::FromUtf8(new_str); - return *this; - } - String &operator=(const std::wstring &new_wstr) - { - this->utf8 = UtfConverter::ToUtf8(new_wstr); - this->ansi = DecodeFromUTF8(this->utf8, this->loc); - this->utf16 = new_wstr; - return *this; - } - String &operator=(const String &new_string) - { - if (this != &new_string) - { - this->ansi = new_string.ansi; - this->utf8 = new_string.utf8; - this->utf16 = new_string.utf16; - } - return *this; - } - String &SetISO8859_1(const std::string &new_str) - { - this->ansi = new_str; - this->utf8 = EncodeToUTF8(new_str, this->loc); - this->utf16 = UtfConverter::FromUtf8(this->utf8); - return *this; - } - String operator+(const String &str2) const - { - String new_string = String(*this); - new_string.ansi.append(str2.ansi); - new_string.utf8.append(str2.utf8); - new_string.utf16.append(str2.utf16); - return new_string; - } - String operator+(char chr) const - { - String new_string = String(*this); - char str2[] = { chr, 0 }; - new_string.ansi.append(str2); - std::string new_utf8 = EncodeToUTF8(str2, this->loc); - new_string.utf8.append(new_utf8); - new_string.utf16.append(UtfConverter::FromUtf8(new_utf8)); - return new_string; - } - String operator+(wchar_t wchr) const - { - String new_string = String(*this); - wchar_t wstr2[] = { wchr, 0 }; - std::string new_utf8 = UtfConverter::ToUtf8(wstr2); - new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc)); - new_string.utf8.append(new_utf8); - new_string.utf16.append(wstr2); - return new_string; - } - String operator+(const char *str2) const - { - String new_string = String(*this); - new_string.ansi.append(DecodeFromUTF8(str2, this->loc)); - new_string.utf8.append(str2); - new_string.utf16.append(UtfConverter::FromUtf8(str2)); - return new_string; - } - String operator+(const std::string &str2) const - { - String new_string = String(*this); - new_string.ansi.append(DecodeFromUTF8(str2, this->loc)); - new_string.utf8.append(str2); - new_string.utf16.append(UtfConverter::FromUtf8(str2)); - return new_string; - } - String operator+(const wchar_t *wstr2) const - { - String new_string = String(*this); - std::string new_utf8 = UtfConverter::ToUtf8(wstr2); - new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc)); - new_string.utf8.append(new_utf8); - new_string.utf16.append(wstr2); - return new_string; - } - String operator+(const std::wstring &wstr2) const - { - String new_string = String(*this); - std::string new_utf8 = UtfConverter::ToUtf8(wstr2); - new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc)); - new_string.utf8.append(new_utf8); - new_string.utf16.append(wstr2); - return new_string; - } - String &operator+=(const String &str2) - { - if (this != &str2) - { - this->ansi.append(str2.ansi); - this->utf8.append(str2.utf8); - this->utf16.append(str2.utf16); - } - return *this; - } - String &operator+=(char chr) - { - char str2[] = { chr, 0 }; - this->ansi.append(str2); - std::string new_utf8 = EncodeToUTF8(str2, this->loc); - this->utf8.append(new_utf8); - this->utf16.append(UtfConverter::FromUtf8(new_utf8)); - return *this; - } - String &operator+=(wchar_t wchr) - { - wchar_t wstr2[] = { wchr, 0 }; - std::string new_utf8 = UtfConverter::ToUtf8(wstr2); - this->ansi.append(DecodeFromUTF8(new_utf8, this->loc)); - this->utf8.append(new_utf8); - this->utf16.append(wstr2); - return *this; - } - String &operator+=(const char *str2) - { - this->ansi.append(DecodeFromUTF8(str2, this->loc)); - this->utf8.append(str2); - this->utf16.append(UtfConverter::FromUtf8(str2)); - return *this; - } - String &operator+=(const std::string &str2) - { - this->ansi.append(DecodeFromUTF8(str2, this->loc)); - this->utf8.append(str2); - this->utf16.append(UtfConverter::FromUtf8(str2)); - return *this; - } - String &operator+=(const wchar_t *wstr2) - { - std::string new_utf8 = UtfConverter::ToUtf8(wstr2); - this->ansi.append(DecodeFromUTF8(new_utf8, this->loc)); - this->utf8.append(new_utf8); - this->utf16.append(wstr2); - return *this; - } - String &operator+=(const std::wstring &wstr2) - { - std::string new_utf8 = UtfConverter::ToUtf8(wstr2); - this->ansi.append(DecodeFromUTF8(new_utf8, this->loc)); - this->utf8.append(new_utf8); - this->utf16.append(wstr2); - return *this; - } - String &AppendISO8859_1(const std::string &str2) - { - this->ansi.append(str2); - std::string new_utf8 = EncodeToUTF8(str2, this->loc); - this->utf8.append(new_utf8); - this->utf16.append(UtfConverter::FromUtf8(new_utf8)); - return *this; - } - String Substring(size_t pos = 0, size_t n = std::string::npos) const - { - String new_string = String(*this); - new_string.ansi.substr(pos, n); - new_string.utf8.substr(pos, n); - if (n == std::string::npos) - n = std::wstring::npos; - new_string.utf16.substr(pos, n); - return new_string; - } - void CopyToString(wchar_t *str, bool = false) const - { - wcscpy(str, utf16.c_str()); - } - void CopyToString(char *str, bool use_utf8 = false) const - { - strcpy(str, (use_utf8 ? utf8 : ansi).c_str()); - } -protected: - std::string ansi, utf8; - std::wstring utf16; - std::locale loc; -}; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/Channel.cpp b/Frameworks/SSEQPlayer/SSEQPlayer/Channel.cpp index d9ecb6dcb..3ad291fbe 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/Channel.cpp +++ b/Frameworks/SSEQPlayer/SSEQPlayer/Channel.cpp @@ -1,7 +1,7 @@ /* * SSEQ Player - Channel structures * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-23 + * Last modification on 2014-10-23 * * Adapted from source code of FeOS Sound System * By fincs @@ -12,7 +12,6 @@ */ #define _USE_MATH_DEFINES -#include #include #include #include "Channel.h" @@ -46,8 +45,8 @@ TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LE } bool Channel::initializedLUTs = false; -double Channel::cosine_lut[Channel::COSINE_RESOLUTION]; -double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES + 1]; +double Channel::sinc_lut[Channel::SINC_SAMPLES + 1]; +double Channel::window_lut[Channel::SINC_SAMPLES + 1]; #ifndef M_PI static const double M_PI = 3.14159265358979323846; @@ -73,18 +72,22 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), this->clearHistory(); if (!this->initializedLUTs) { - for (unsigned i = 0; i < COSINE_RESOLUTION; ++i) - this->cosine_lut[i] = (1.0 - std::cos((static_cast(i) / COSINE_RESOLUTION) * M_PI)) * 0.5; - double dx = static_cast(LANCZOS_WIDTH) / LANCZOS_SAMPLES, x = 0.0; - for (unsigned i = 0; i <= LANCZOS_SAMPLES; ++i, x += dx) - this->lanczos_lut[i] = std::abs(x) < LANCZOS_WIDTH ? sinc(x) * sinc(x / LANCZOS_WIDTH) : 0.0; + double dx = static_cast(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; + for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx) + { + double y = x / SINC_WIDTH; + this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) : 0.0; + this->window_lut[i] = (0.40897 + 0.5 * std::cos(M_PI * y) + 0.09103 * std::cos(2 * M_PI * y)); + } this->initializedLUTs = true; } } +// Original FSS Function: Chn_UpdateVol void Channel::UpdateVol(const Track &trk) { int finalVol = trk.ply->masterVol; + finalVol += trk.ply->sseqVol; finalVol += Cnv_Sust(trk.vol); finalVol += Cnv_Sust(trk.expr); if (finalVol < -AMPL_K) @@ -92,11 +95,13 @@ void Channel::UpdateVol(const Track &trk) this->extAmpl = finalVol; } +// Original FSS Function: Chn_UpdatePan void Channel::UpdatePan(const Track &trk) { this->extPan = trk.pan; } +// Original FSS Function: Chn_UpdateTune void Channel::UpdateTune(const Track &trk) { int tune = (static_cast(this->key) - static_cast(this->orgKey)) * 64; @@ -104,6 +109,7 @@ void Channel::UpdateTune(const Track &trk) this->extTune = tune; } +// Original FSS Function: Chn_UpdateMod void Channel::UpdateMod(const Track &trk) { this->modType = trk.modType; @@ -113,6 +119,7 @@ void Channel::UpdateMod(const Track &trk) this->modDelay = trk.modDelay; } +// Original FSS Function: Chn_UpdatePorta void Channel::UpdatePorta(const Track &trk) { this->manualSweep = false; @@ -135,11 +142,12 @@ void Channel::UpdatePorta(const Track &trk) else { int sq_time = static_cast(trk.portaTime) * static_cast(trk.portaTime); - long abs_sp = std::abs((long)this->sweepPitch); - this->sweepLen = (uint32_t)((abs_sp * sq_time) >> 11); + int abs_sp = std::abs(this->sweepPitch); + this->sweepLen = (abs_sp * sq_time) >> 11; } } +// Original FSS Function: Chn_Release void Channel::Release() { this->noteLength = -1; @@ -147,6 +155,7 @@ void Channel::Release() this->state = CS_RELEASE; } +// Original FSS Function: Chn_Kill void Channel::Kill() { this->state = CS_NONE; @@ -173,6 +182,7 @@ static inline int getModFlag(int type) } } +// Original FSS Function: Chn_UpdateTracks void Channel::UpdateTrack() { if (!this->ply) @@ -182,11 +192,11 @@ void Channel::UpdateTrack() if (trkn == -1) return; - auto &trackFlags = this->ply->tracks[trkn].updateFlags; + auto &trk = this->ply->tracks[trkn]; + auto &trackFlags = trk.updateFlags; if (trackFlags.none()) return; - auto &trk = this->ply->tracks[trkn]; if (trackFlags[TUF_LEN]) { int st = this->state; @@ -405,7 +415,7 @@ static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch) tmr <<= shift; } else - return 0x10; + return 0xFFFF; if (tmr < 0x10) return 0x10; @@ -425,6 +435,7 @@ static inline int calcVolDivShift(int x) return 4; } +// Original FSS Function: Snd_UpdChannel void Channel::Update() { // Kill active channels that aren't physically active @@ -457,10 +468,17 @@ void Channel::Update() this->state = CS_ATTACK; // Fall down case CS_ATTACK: - this->ampl = (static_cast(this->ampl) * static_cast(this->attackLvl)) / 255; + { + int newAmpl = this->ampl; + int oldAmpl = this->ampl >> 7; + do + newAmpl = (newAmpl * static_cast(this->attackLvl)) / 256; + while ((newAmpl >> 7) == oldAmpl); + this->ampl = newAmpl; if (!this->ampl) this->state = CS_DECAY; break; + } case CS_DECAY: { this->ampl -= static_cast(this->decayRate); @@ -474,10 +492,11 @@ void Channel::Update() } case CS_RELEASE: this->ampl -= static_cast(this->releaseRate); - if (this->ampl > AMPL_THRESHOLD) - break; - this->Kill(); - return; + if (this->ampl <= AMPL_THRESHOLD) + { + this->Kill(); + return; + } } if (bModulation && this->modDelayCnt < this->modDelay) @@ -504,7 +523,7 @@ void Channel::Update() modParam = Cnv_Sine(this->modCounter >> 8) * this->modRange * this->modDepth; if (!this->modType) - modParam = static_cast(static_cast(modParam * 60) >> 14); + modParam = static_cast(modParam * 60) >> 14; else // This ugly formula whose exact meaning and workings I cannot figure out is used for volume/pan modulation. modParam = ((modParam & ~0xFC000000) >> 8) | ((((modParam < 0 ? -1 : 0) << 6) | (static_cast(modParam) >> 26)) << 18); @@ -555,8 +574,7 @@ void Channel::Update() if (bModulation && this->modType == 1) totalVol += modParam; totalVol += AMPL_K; - if (totalVol < 0) - totalVol = 0; + clamp(totalVol, 0, AMPL_K); cr &= ~(SOUND_VOL(0x7F) | SOUND_VOLDIV(3)); cr |= SOUND_VOL(static_cast(getvoltbl[totalVol])); @@ -580,10 +598,7 @@ void Channel::Update() if (bModulation && this->modType == 2) realPan += modParam; realPan += 64; - if (realPan < 0) - realPan = 0; - else if (realPan > 127) - realPan = 127; + clamp(realPan, 0, 127); cr &= ~SOUND_PAN(0x7F); cr |= SOUND_PAN(realPan); @@ -607,8 +622,8 @@ static const int16_t wavedutytbl[8][8] = { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF } }; -// Linear and Cosine interpolation code originally from DeSmuME -// B-spline and Osculating come from Olli Niemitalo: +// Linear interpolation code originally from DeSmuME +// Legrange comes from Olli Niemitalo: // http://www.student.oulu.fi/~oniemita/dsp/deip.pdf int32_t Channel::Interpolate() { @@ -617,68 +632,51 @@ int32_t Channel::Interpolate() const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 16]; - if (this->ply->interpolation == INTERPOLATION_LANCZOS) + if (this->ply->interpolation == INTERPOLATION_SINC) { - double kernel[LANCZOS_WIDTH * 2], kernel_sum = 0.0; - int i = LANCZOS_WIDTH, shift = static_cast(std::floor(ratio * LANCZOS_RESOLUTION)); - int step = this->reg.sampleIncrease > 1.0 ? static_cast((1.0 / this->reg.sampleIncrease) * LANCZOS_RESOLUTION) : LANCZOS_RESOLUTION; - long shift_adj = shift * step / LANCZOS_RESOLUTION; - for (; i >= -static_cast(LANCZOS_WIDTH - 1); --i) + double kernel[SINC_WIDTH * 2], kernel_sum = 0.0; + int i = SINC_WIDTH, shift = static_cast(std::floor(ratio * SINC_RESOLUTION)); + int step = this->reg.sampleIncrease > 1.0 ? static_cast(SINC_RESOLUTION / this->reg.sampleIncrease) : SINC_RESOLUTION; + int shift_adj = shift * step / SINC_RESOLUTION; + const int window_step = SINC_RESOLUTION; + for (; i >= -static_cast(SINC_WIDTH - 1); --i) { - long pos = i * step; - kernel_sum += kernel[i + LANCZOS_WIDTH - 1] = this->lanczos_lut[std::abs(shift_adj - pos)]; + int pos = i * step; + int window_pos = i * window_step; + kernel_sum += kernel[i + SINC_WIDTH - 1] = this->sinc_lut[std::abs(shift_adj - pos)] * this->window_lut[std::abs(shift - window_pos)]; } double sum = 0.0; - for (i = 0; i < static_cast(LANCZOS_WIDTH * 2); ++i) - sum += data[i - static_cast(LANCZOS_WIDTH) + 1] * kernel[i]; + for (i = 0; i < static_cast(SINC_WIDTH * 2); ++i) + sum += data[i - static_cast(SINC_WIDTH) + 1] * kernel[i]; return static_cast(sum / kernel_sum); } - else if (this->ply->interpolation > INTERPOLATION_COSINE) + else if (this->ply->interpolation > INTERPOLATION_LINEAR) { double c0, c1, c2, c3, c4, c5; - if (this->ply->interpolation > INTERPOLATION_4POINTBSPLINE) + if (this->ply->interpolation == INTERPOLATION_6POINTLEGRANGE) { - if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE) - { - double ym2py2 = data[-2] + data[2], ym1py1 = data[-1] + data[1]; - double y2mym2 = data[2] - data[-2], y1mym1 = data[1] - data[-1]; - double sixthym1py1 = 1 / 6.0 * ym1py1; - c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * data[0]; - c1 = 1 / 24.0 * y2mym2 + 5 / 12.0 * y1mym1; - c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * data[0]; - c3 = 1 / 12.0 * y2mym2 - 1 / 6.0 * y1mym1; - c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * data[0]; - c5 = 1 / 120.0 * (data[3] - data[-2]) + 1 / 24.0 * (data[-1] - data[2]) + 1 / 12.0 * (data[1] - data[0]); - return static_cast(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); - } - else // INTERPOLATION_6POINTOSCULATING - { - ratio -= 0.5; - double even1 = data[-2] + data[3], odd1 = data[-2] - data[3]; - double even2 = data[-1] + data[2], odd2 = data[-1] - data[2]; - double even3 = data[0] + data[1], odd3 = data[0] - data[1]; - c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3; - c1 = 0.2109375 * odd2 - 281 / 192.0 * odd3 - 13 / 384.0 * odd1; - c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1; - c3 = 0.1875 * odd1 - 53 / 48.0 * odd2 + 2.375 * odd3; - c4 = 1 / 48.0 * even1 - 0.0625 * even2 + 1 / 24.0 * even3; - c5 = 25 / 24.0 * odd2 - 25 / 12.0 * odd3 - 5 / 24.0 * odd1; - return static_cast(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); - } + ratio -= 0.5; + double even1 = data[-2] + data[3], odd1 = data[-2] - data[3]; + double even2 = data[-1] + data[2], odd2 = data[-1] - data[2]; + double even3 = data[0] + data[1], odd3 = data[0] - data[1]; + c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3; + c1 = 25 / 384.0 * odd2 - 1.171875 * odd3 - 0.0046875 * odd1; + c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1; + c3 = 1 / 48.0 * odd1 - 13 / 48.0 * odd2 + 17 / 24.0 * odd3; + c4 = 1 / 48.0 * even1 - 0.0625 * even2 + 1 / 24.0 * even3; + c5 = 1 / 24.0 * odd2 - 1 / 12.0 * odd3 - 1 / 120.0 * odd1; + return static_cast(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); } - else // INTERPOLATION_4POINTBSPLINE + else // INTERPOLATION_4POINTLEAGRANGE { - double ym1py1 = data[-1] + data[1]; - c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * data[0]; - c1 = 0.5 * (data[1] - data[-1]); - c2 = 0.5 * ym1py1 - data[0]; - c3 = 0.5 * (data[0] - data[1]) + 1 / 6.0 * (data[2] - data[-1]); + c0 = data[0]; + c1 = data[1] - 1 / 3.0 * data[-1] - 0.5 * data[0] - 1 / 6.0 * data[2]; + c2 = 0.5 * (data[-1] + data[1]) - data[0]; + c3 = 1 / 6.0 * (data[2] - data[-1]) + 0.5 * (data[0] - data[1]); return static_cast(((c3 * ratio + c2) * ratio + c1) * ratio + c0); } } - else if (this->ply->interpolation == INTERPOLATION_COSINE) - return static_cast(data[0] + this->cosine_lut[static_cast(ratio * COSINE_RESOLUTION)] * (data[1] - data[0])); else // INTERPOLATION_LINEAR return static_cast(data[0] + ratio * (data[1] - data[0])); } diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/Channel.h b/Frameworks/SSEQPlayer/SSEQPlayer/Channel.h index 0a116fec7..f958adb8e 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/Channel.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/Channel.h @@ -1,7 +1,7 @@ /* * SSEQ Player - Channel structures * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-02 + * Last modification on 2014-09-17 * * Adapted from source code of FeOS Sound System * By fincs @@ -11,8 +11,7 @@ * http://desmume.org/ */ -#ifndef SSEQPLAYER_CHANNEL_H -#define SSEQPLAYER_CHANNEL_H +#pragma once #include #include @@ -136,18 +135,17 @@ struct Channel int16_t sampleHistory[64]; /* - * Lookup tables for the cosine and Lanczos Sinc interpolations, to + * Lookup tables for the Sinc interpolation, to * avoid the need to call the sin/cos functions all the time. * These are static as they will not change between channels or runs * of the program. */ static bool initializedLUTs; - static const unsigned COSINE_RESOLUTION = 8192; - static const unsigned LANCZOS_RESOLUTION = 8192; - static const unsigned LANCZOS_WIDTH = 8; - static const unsigned LANCZOS_SAMPLES = LANCZOS_RESOLUTION * LANCZOS_WIDTH; - static double cosine_lut[COSINE_RESOLUTION]; - static double lanczos_lut[LANCZOS_SAMPLES + 1]; + static const unsigned SINC_RESOLUTION = 8192; + static const unsigned SINC_WIDTH = 8; + static const unsigned SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH; + static double sinc_lut[SINC_SAMPLES + 1]; + static double window_lut[SINC_SAMPLES + 1]; Channel(); @@ -165,5 +163,3 @@ struct Channel void IncrementSample(); void clearHistory(); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/ConvertUTF.cpp b/Frameworks/SSEQPlayer/SSEQPlayer/ConvertUTF.cpp deleted file mode 100644 index 747f447b5..000000000 --- a/Frameworks/SSEQPlayer/SSEQPlayer/ConvertUTF.cpp +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Copyright 2001-2004 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Source code file. - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Sept 2001: fixed const & error conditions per - mods suggested by S. Parent & A. Lillich. - June 2002: Tim Dodd added detection and handling of incomplete - source sequences, enhanced error detection, added casts - to eliminate compiler warnings. - July 2003: slight mods to back out aggressive FFFE detection. - Jan 2004: updated switches in from-UTF8 conversions. - Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. - - See the header file "ConvertUTF.h" for complete documentation. - ------------------------------------------------------------------------- */ - -#include "ConvertUTF.h" - -static const int halfShift = 10; /* used for shifting by 10 bits */ - -static const UTF32 halfBase = 0x0010000UL; -static const UTF32 halfMask = 0x3FFUL; - -static const UTF32 UNI_SUR_HIGH_START = 0xD800; -static const UTF32 UNI_SUR_HIGH_END = 0xDBFF; -static const UTF32 UNI_SUR_LOW_START = 0xDC00; -static const UTF32 UNI_SUR_LOW_END = 0xDFFF; - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags) -{ - ConversionResult result = conversionOK; - const UTF32 *source = *sourceStart; - UTF16 *target = *targetStart; - while (source < sourceEnd) - { - if (target >= targetEnd) - { - result = targetExhausted; - break; - } - UTF32 ch = *source++; - if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */ - { - /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) - { - if (flags == strictConversion) - { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - else - *target++ = UNI_REPLACEMENT_CHAR; - } - else - *target++ = static_cast(ch); /* normal case */ - } - else if (ch > UNI_MAX_LEGAL_UTF32) - { - if (flags == strictConversion) - result = sourceIllegal; - else - *target++ = UNI_REPLACEMENT_CHAR; - } - else - { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) - { - --source; /* Back up source pointer! */ - result = targetExhausted; - break; - } - ch -= halfBase; - *target++ = static_cast((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = static_cast((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags) -{ - ConversionResult result = conversionOK; - const UTF16 *source = *sourceStart; - UTF32 *target = *targetStart; - while (source < sourceEnd) - { - const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */ - UTF32 ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) - { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) - { - UTF32 ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) - { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } - else if (flags == strictConversion) /* it's an unpaired high surrogate */ - { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - else /* We don't have the 16 bits following the high surrogate. */ - { - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } - else if (flags == strictConversion) - { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) - { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - if (target >= targetEnd) - { - source = oldSource; /* Back up source pointer! */ - result = targetExhausted; - break; - } - *target++ = ch; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Index into the table below with the first byte of a UTF-8 sequence to - * get the number of trailing bytes that are supposed to follow it. - * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is - * left as-is for anyone who may want to do such conversion, which was - * allowed in earlier algorithms. - */ -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 -}; - -/* - * Magic values subtracted from a buffer value during UTF8 conversion. - * This table contains as many values as there might be trailing bytes - * in a UTF-8 sequence. - */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; - -/* - * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed - * into the first byte, depending on how many bytes follow. There are - * as many entries in this table as there are UTF-8 sequence types. - * (I.e., one byte sequence, two byte... etc.). Remember that sequencs - * for *legal* UTF-8 will be 4 or fewer bytes total. - */ -static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - -/* --------------------------------------------------------------------- */ - -/* The interface converts a whole buffer to avoid function-call overhead. - * Constants have been gathered. Loops & conditionals have been removed as - * much as possible for efficiency, in favor of drop-through switches. - * (See "Note A" at the bottom of the file for equivalent code.) - * If your compiler supports it, the "isLegalUTF8" call can be turned - * into an inline function. - */ - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags) -{ - ConversionResult result = conversionOK; - const UTF16 *source = *sourceStart; - UTF8 *target = *targetStart; - while (source < sourceEnd) - { - const UTF32 byteMask = 0xBF, byteMark = 0x80; - const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */ - UTF32 ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) - { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) - { - UTF32 ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) - { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } - else if (flags == strictConversion) /* it's an unpaired high surrogate */ - { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - else /* We don't have the 16 bits following the high surrogate. */ - { - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } - else if (flags == strictConversion) - { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) - { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* Figure out how many bytes the result will require */ - unsigned short bytesToWrite = 0; - if (ch < 0x80) - bytesToWrite = 1; - else if (ch < 0x800) - bytesToWrite = 2; - else if (ch < 0x10000) - bytesToWrite = 3; - else if (ch < 0x110000) - bytesToWrite = 4; - else - { - bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - } - target += bytesToWrite; - if (target > targetEnd) - { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; - result = targetExhausted; - break; - } - switch (bytesToWrite) /* note: everything falls through. */ - { - case 4: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = static_cast(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Utility routine to tell whether a sequence of bytes is legal UTF-8. - * This must be called with the length pre-determined by the first byte. - * If not calling this from ConvertUTF8to*, then the length can be set by: - * length = trailingBytesForUTF8[*source]+1; - * and the sequence is illegal right away if there aren't that many bytes - * available. - * If presented with a length > 4, this returns false. The Unicode - * definition of UTF-8 goes up to 4-byte sequences. - */ - -static bool isLegalUTF8(const UTF8 *source, int length) -{ - const UTF8 *srcptr = source + length; - UTF8 a; - switch (length) - { - default: return false; - /* Everything else falls through when "true"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; - - switch (*source) - { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xED: if (a > 0x9F) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; - } - - case 1: if (*source >= 0x80 && *source < 0xC2) return false; - } - if (*source > 0xF4) - return false; - return true; -} - -/* --------------------------------------------------------------------- */ - -/* - * Exported function to return whether a UTF-8 sequence is legal or not. - * This is not used here; it's just exported. - */ -bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) -{ - int length = trailingBytesForUTF8[*source] + 1; - if (source + length > sourceEnd) - return false; - return isLegalUTF8(source, length); -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags) -{ - ConversionResult result = conversionOK; - const UTF8 *source = *sourceStart; - UTF16 *target = *targetStart; - while (source < sourceEnd) - { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) - { - result = sourceExhausted; - break; - } - /* Do this check whether lenient or strict */ - if (!isLegalUTF8(source, extraBytesToRead + 1)) - { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) - { - case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) - { - source -= extraBytesToRead + 1; /* Back up source pointer! */ - result = targetExhausted; - break; - } - if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */ - { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) - { - if (flags == strictConversion) - { - source -= extraBytesToRead + 1; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - else - *target++ = UNI_REPLACEMENT_CHAR; - } - else - *target++ = static_cast(ch); /* normal case */ - } - else if (ch > UNI_MAX_UTF16) - { - if (flags == strictConversion) - { - result = sourceIllegal; - source -= extraBytesToRead + 1; /* return to the start */ - break; /* Bail out; shouldn't continue */ - } - else - *target++ = UNI_REPLACEMENT_CHAR; - } - else - { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) - { - source -= extraBytesToRead + 1; /* Back up source pointer! */ - result = targetExhausted; - break; - } - ch -= halfBase; - *target++ = static_cast((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = static_cast((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags) -{ - ConversionResult result = conversionOK; - const UTF32 *source = *sourceStart; - UTF8 *target = *targetStart; - while (source < sourceEnd) - { - const UTF32 byteMask = 0xBF, byteMark = 0x80; - UTF32 ch = *source++; - if (flags == strictConversion) - { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) - { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* - * Figure out how many bytes the result will require. Turn any - * illegally large UTF32 things (> Plane 17) into replacement chars. - */ - unsigned short bytesToWrite = 0; - if (ch < 0x80) - bytesToWrite = 1; - else if (ch < 0x800) - bytesToWrite = 2; - else if (ch < 0x10000) - bytesToWrite = 3; - else if (ch <= UNI_MAX_LEGAL_UTF32) - bytesToWrite = 4; - else - { - bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - result = sourceIllegal; - } - - target += bytesToWrite; - if (target > targetEnd) - { - --source; /* Back up source pointer! */ - target -= bytesToWrite; - result = targetExhausted; - break; - } - switch (bytesToWrite) /* note: everything falls through. */ - { - case 4: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = static_cast(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags) -{ - ConversionResult result = conversionOK; - const UTF8 *source = *sourceStart; - UTF32 *target = *targetStart; - while (source < sourceEnd) - { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) - { - result = sourceExhausted; - break; - } - /* Do this check whether lenient or strict */ - if (!isLegalUTF8(source, extraBytesToRead + 1)) - { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) - { - case 5: ch += *source++; ch <<= 6; - case 4: ch += *source++; ch <<= 6; - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) - { - source -= extraBytesToRead + 1; /* Back up the source pointer! */ - result = targetExhausted; - break; - } - if (ch <= UNI_MAX_LEGAL_UTF32) - { - /* - * UTF-16 surrogate values are illegal in UTF-32, and anything - * over Plane 17 (> 0x10FFFF) is illegal. - */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) - { - if (flags == strictConversion) - { - source -= extraBytesToRead + 1; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - else - *target++ = UNI_REPLACEMENT_CHAR; - } - else - *target++ = ch; - } - else /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ - { - result = sourceIllegal; - *target++ = UNI_REPLACEMENT_CHAR; - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- - - Note A. - The fall-through switches in UTF-8 reading code save a - temp variable, some decrements & conditionals. The switches - are equivalent to the following loop: - { - int tmpBytesToRead = extraBytesToRead+1; - do { - ch += *source++; - --tmpBytesToRead; - if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); - } - In UTF-8 writing code, the switches on "bytesToWrite" are - similarly unrolled loops. - - --------------------------------------------------------------------- */ diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/ConvertUTF.h b/Frameworks/SSEQPlayer/SSEQPlayer/ConvertUTF.h deleted file mode 100644 index c363ffa1c..000000000 --- a/Frameworks/SSEQPlayer/SSEQPlayer/ConvertUTF.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2001-2004 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Header file. - - Several funtions are included here, forming a complete set of - conversions between the three formats. UTF-7 is not included - here, but is handled in a separate source file. - - Each of these routines takes pointers to input buffers and output - buffers. The input buffers are const. - - Each routine converts the text between *sourceStart and sourceEnd, - putting the result into the buffer between *targetStart and - targetEnd. Note: the end pointers are *after* the last item: e.g. - *(sourceEnd - 1) is the last item. - - The return result indicates whether the conversion was successful, - and if not, whether the problem was in the source or target buffers. - (Only the first encountered problem is indicated.) - - After the conversion, *sourceStart and *targetStart are both - updated to point to the end of last text successfully converted in - the respective buffers. - - Input parameters: - sourceStart - pointer to a pointer to the source buffer. - The contents of this are modified on return so that - it points at the next thing to be converted. - targetStart - similarly, pointer to pointer to the target buffer. - sourceEnd, targetEnd - respectively pointers to the ends of the - two buffers, for overflow checking only. - - These conversion functions take a ConversionFlags argument. When this - flag is set to strict, both irregular sequences and isolated surrogates - will cause an error. When the flag is set to lenient, both irregular - sequences and isolated surrogates are converted. - - Whether the flag is strict or lenient, all illegal sequences will cause - an error return. This includes sequences such as: , , - or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code - must check for illegal sequences. - - When the flag is set to lenient, characters over 0x10FFFF are converted - to the replacement character; otherwise (when the flag is set to strict) - they constitute an error. - - Output parameters: - The value "sourceIllegal" is returned from some routines if the input - sequence is malformed. When "sourceIllegal" is returned, the source - value will point to the illegal value that caused the problem. E.g., - in UTF-8 when a sequence is malformed, it points to the start of the - malformed sequence. - - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Fixes & updates, Sept 2001. - ------------------------------------------------------------------------- */ - -#ifndef _CONVERTUTF_H_ -#define _CONVERTUTF_H_ - -/* --------------------------------------------------------------------- - The following 4 definitions are compiler-specific. - The C standard does not guarantee that wchar_t has at least - 16 bits, so wchar_t is no less portable than unsigned short! - All should be unsigned values to avoid sign extension during - bit mask & shift operations. ------------------------------------------------------------------------- */ - -typedef unsigned long UTF32; /* at least 32 bits */ -typedef unsigned short UTF16; /* at least 16 bits */ -typedef unsigned char UTF8; /* typically 8 bits */ - -/* Some fundamental constants */ -static const UTF32 UNI_REPLACEMENT_CHAR = 0x0000FFFD; -static const UTF32 UNI_MAX_BMP = 0x0000FFFF; -static const UTF32 UNI_MAX_UTF16 = 0x0010FFFF; -static const UTF32 UNI_MAX_UTF32 = 0x7FFFFFFF; -static const UTF32 UNI_MAX_LEGAL_UTF32 = 0x0010FFFF; - -enum ConversionResult -{ - conversionOK, /* conversion successful */ - sourceExhausted, /* partial character in source, but hit end */ - targetExhausted, /* insuff. room in target for conversion */ - sourceIllegal /* source sequence is illegal/malformed */ -}; - -enum ConversionFlags -{ - strictConversion, - lenientConversion -}; - -ConversionResult ConvertUTF8toUTF16(const UTF8 **, const UTF8 *, UTF16 **, UTF16 *, ConversionFlags); - -ConversionResult ConvertUTF16toUTF8(const UTF16 **, const UTF16 *, UTF8 **, UTF8 *, ConversionFlags); - -ConversionResult ConvertUTF8toUTF32(const UTF8 **, const UTF8 *, UTF32 **, UTF32 *, ConversionFlags); - -ConversionResult ConvertUTF32toUTF8(const UTF32 **, const UTF32 *, UTF8 **, UTF8 *, ConversionFlags); - -ConversionResult ConvertUTF16toUTF32(const UTF16 **, const UTF16 *, UTF32 **, UTF32 *, ConversionFlags); - -ConversionResult ConvertUTF32toUTF16(const UTF32 **, const UTF32 *, UTF16 **, UTF16 *, ConversionFlags); - -bool isLegalUTF8Sequence(const UTF8 *, const UTF8 *); - -/* --------------------------------------------------------------------- */ - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/FATSection.h b/Frameworks/SSEQPlayer/SSEQPlayer/FATSection.h index 198cfae12..636c6f121 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/FATSection.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/FATSection.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT FAT (File Allocation Table) Section structures * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-21 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_FATSECTION_H -#define SSEQPLAYER_FATSECTION_H +#pragma once #include "common.h" @@ -29,5 +28,3 @@ struct FATSection void Read(PseudoFile &file); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/INFOEntry.h b/Frameworks/SSEQPlayer/SSEQPlayer/INFOEntry.h index 0a4b4dd7b..c06a7d82f 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/INFOEntry.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/INFOEntry.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT INFO Entry structures * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-21 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_INFOENTRY_H -#define SSEQPLAYER_INFOENTRY_H +#pragma once #include "common.h" @@ -50,5 +49,3 @@ struct INFOEntryWAVEARC : INFOEntry void Read(PseudoFile &file); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/INFOSection.h b/Frameworks/SSEQPlayer/SSEQPlayer/INFOSection.h index a41361a46..0fbe58246 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/INFOSection.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/INFOSection.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT INFO Section structures * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-21 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_INFOSECTION_H -#define SSEQPLAYER_INFOSECTION_H +#pragma once #include #include "INFOEntry.h" @@ -33,5 +32,3 @@ struct INFOSection void Read(PseudoFile &file); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/NDSStdHeader.h b/Frameworks/SSEQPlayer/SSEQPlayer/NDSStdHeader.h index 7b2b6077a..2a8e141b8 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/NDSStdHeader.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/NDSStdHeader.h @@ -1,14 +1,13 @@ /* * SSEQ Player - Nintendo DS Standard Header structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-21 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_NDSSTDHEADER_H -#define SSEQPLAYER_NDSSTDHEADER_H +#pragma once #include "common.h" @@ -22,5 +21,3 @@ struct NDSStdHeader void Read(PseudoFile &file); void Verify(const std::string &typeToCheck, uint32_t magicToCheck); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/Player.cpp b/Frameworks/SSEQPlayer/SSEQPlayer/Player.cpp index 19e6ba20c..854f49d3b 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/Player.cpp +++ b/Frameworks/SSEQPlayer/SSEQPlayer/Player.cpp @@ -1,7 +1,7 @@ /* * SSEQ Player - Player structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-01 + * Last modification on 2014-10-23 * * Adapted from source code of FeOS Sound System * By fincs @@ -11,13 +11,23 @@ #include "Player.h" #include "common.h" -Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseq(nullptr), sampleRate(0), interpolation(INTERPOLATION_NONE) +#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION) +std::locale::id std::codecvt::id; +std::locale::id std::codecvt::id; +#endif + +Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseqVol(0), sseq(nullptr), sampleRate(0), interpolation(INTERPOLATION_NONE) { memset(this->trackIds, 0, sizeof(this->trackIds)); for (size_t i = 0; i < 16; ++i) + { this->channels[i].chnId = i; + this->channels[i].ply = this; + } + memset(this->variables, -1, sizeof(this->variables)); } +// Original FSS Function: Player_Setup bool Player::Setup(const SSEQ *sseqToPlay) { this->sseq = sseqToPlay; @@ -30,21 +40,7 @@ bool Player::Setup(const SSEQ *sseqToPlay) this->nTracks = 1; this->trackIds[0] = firstTrack; - auto pData = &this->sseq->data[0]; - if (*pData == 0xFE) - for (pData += 3; *pData == 0x93; ) // Prepare extra tracks - { - ++pData; - int tNum = read8(&pData); - auto pos = &this->sseq->data[read24(&pData)]; - int newTrack = this->TrackAlloc(); - if (newTrack == -1) - continue; - this->tracks[newTrack].Init(newTrack, this, pos, tNum); - this->trackIds[this->nTracks++] = newTrack; - } - - this->tracks[firstTrack].startPos = this->tracks[firstTrack].pos = pData; + this->tracks[firstTrack].startPos = this->tracks[firstTrack].pos = &this->sseq->data[0]; this->secondsPerSample = 1.0 / this->sampleRate; @@ -53,16 +49,19 @@ bool Player::Setup(const SSEQ *sseqToPlay) return true; } +// Original FSS Function: Player_ClearState void Player::ClearState() { this->tempo = 120; this->tempoCount = 0; this->tempoRate = 0x100; this->masterVol = 0; // this is actually the highest level + memset(this->variables, -1, sizeof(this->variables)); this->secondsIntoPlayback = 0; this->secondsUntilNextClock = SecondsPerClockCycle; } +// Original FSS Function: Player_FreeTracks void Player::FreeTracks() { for (uint8_t i = 0; i < this->nTracks; ++i) @@ -70,6 +69,7 @@ void Player::FreeTracks() this->nTracks = 0; } +// Original FSS Function: Player_Stop void Player::Stop(bool bKillSound) { this->ClearState(); @@ -92,11 +92,12 @@ void Player::Stop(bool bKillSound) this->FreeTracks(); } +// Original FSS Function: Chn_Alloc int Player::ChannelAlloc(int type, int priority) { static const uint8_t pcmChnArray[] = { 4, 5, 6, 7, 2, 0, 3, 1, 8, 9, 10, 11, 14, 12, 15, 13 }; - static const uint8_t psgChnArray[] = { 13, 12, 11, 10, 9, 8 }; - static const uint8_t noiseChnArray[] = { 15, 14 }; + static const uint8_t psgChnArray[] = { 8, 9, 10, 11, 12, 13 }; + static const uint8_t noiseChnArray[] = { 14, 15 }; static const uint8_t arraySizes[] = { sizeof(pcmChnArray), sizeof(psgChnArray), sizeof(noiseChnArray) }; static const uint8_t *const arrayArray[] = { pcmChnArray, psgChnArray, noiseChnArray }; @@ -121,13 +122,13 @@ int Player::ChannelAlloc(int type, int priority) if (curChnNo == -1 || priority < this->channels[curChnNo].prio) return -1; - this->channels[curChnNo].ply = this; this->channels[curChnNo].noteLength = -1; - this->channels[curChnNo].vol = 0; + this->channels[curChnNo].vol = 0x7FF; this->channels[curChnNo].clearHistory(); return curChnNo; } +// Original FSS Function: Track_Alloc int Player::TrackAlloc() { for (int i = 0; i < FSS_MAXTRACKS; ++i) @@ -144,6 +145,7 @@ int Player::TrackAlloc() return -1; } +// Original FSS Function: Player_Run void Player::Run() { while (this->tempoCount > 240) @@ -163,6 +165,7 @@ void Player::UpdateTracks() this->tracks[i].updateFlags.reset(); } +// Original FSS Function: Snd_Timer void Player::Timer() { this->UpdateTracks(); @@ -173,14 +176,6 @@ void Player::Timer() this->Run(); } -template static inline void clamp(T1 &valueToClamp, const T2 &minValue, const T2 &maxValue) -{ - if (valueToClamp < minValue) - valueToClamp = minValue; - else if (valueToClamp > maxValue) - valueToClamp = maxValue; -} - static inline int32_t muldiv7(int32_t val, uint8_t mul) { return mul == 127 ? val : ((val * mul) >> 7); @@ -219,9 +214,6 @@ void Player::GenerateSamples(std::vector &buf, unsigned offset, unsigne } } - leftChannel = muldiv7(leftChannel, 127 - this->masterVol); - rightChannel = muldiv7(rightChannel, 127 - this->masterVol); - clamp(leftChannel, -0x8000, 0x7FFF); clamp(rightChannel, -0x8000, 0x7FFF); diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/Player.h b/Frameworks/SSEQPlayer/SSEQPlayer/Player.h index 40b20d32d..afa948bae 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/Player.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/Player.h @@ -1,15 +1,14 @@ /* * SSEQ Player - Player structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-01 + * Last modification on 2014-10-18 * * Adapted from source code of FeOS Sound System * By fincs * https://github.com/fincs/FSS */ -#ifndef SSEQPLAYER_PLAYER_H -#define SSEQPLAYER_PLAYER_H +#pragma once #include #include @@ -22,13 +21,14 @@ struct Player { uint8_t prio, nTracks; uint16_t tempo, tempoCount, tempoRate /* 8.8 fixed point */; - int16_t masterVol; + int16_t masterVol, sseqVol; const SSEQ *sseq; uint8_t trackIds[FSS_TRACKCOUNT]; Track tracks[FSS_MAXTRACKS]; Channel channels[16]; + int16_t variables[32]; uint32_t sampleRate; Interpolation interpolation; @@ -50,5 +50,3 @@ struct Player std::bitset<16> mutes; void GenerateSamples(std::vector &buf, unsigned offset, unsigned samples); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/SBNK.h b/Frameworks/SSEQPlayer/SSEQPlayer/SBNK.h index 0bdad32de..e35f28067 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/SBNK.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/SBNK.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT SBNK (Sound Bank) structures * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-21 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_SBNK_H -#define SSEQPLAYER_SBNK_H +#pragma once #include "SWAR.h" #include "INFOEntry.h" @@ -57,5 +56,3 @@ struct SBNK void Read(PseudoFile &file); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/SDAT.h b/Frameworks/SSEQPlayer/SSEQPlayer/SDAT.h index 1f576b792..a850b0afc 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/SDAT.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/SDAT.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-30 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_SDAT_H -#define SSEQPLAYER_SDAT_H +#pragma once #include #include "SSEQ.h" @@ -27,5 +26,3 @@ private: SDAT(const SDAT &); SDAT &operator=(const SDAT &); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/SSEQ.h b/Frameworks/SSEQPlayer/SSEQPlayer/SSEQ.h index 562a1a6e8..d036f7e58 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/SSEQ.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/SSEQ.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT SSEQ (Sequence) structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-21 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_SSEQ_H -#define SSEQPLAYER_SSEQ_H +#pragma once #include "SBNK.h" #include "INFOEntry.h" @@ -28,5 +27,3 @@ struct SSEQ void Read(PseudoFile &file); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/SWAR.h b/Frameworks/SSEQPlayer/SSEQPlayer/SWAR.h index c149636a8..90d36a04f 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/SWAR.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/SWAR.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT SWAR (Wave Archive) structures * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-21 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_SWAR_H -#define SSEQPLAYER_SWAR_H +#pragma once #include #include "SWAV.h" @@ -29,5 +28,3 @@ struct SWAR void Read(PseudoFile &file); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/SWAV.cpp b/Frameworks/SSEQPlayer/SSEQPlayer/SWAV.cpp index e24749435..d16702a7e 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/SWAV.cpp +++ b/Frameworks/SSEQPlayer/SSEQPlayer/SWAV.cpp @@ -1,7 +1,7 @@ /* * SSEQ Player - SDAT SWAV (Waveform/Sample) structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-10 + * Last modification on 2013-04-12 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html @@ -62,20 +62,21 @@ static inline void DecodeADPCMNibble(int32_t nibble, int32_t &stepIndex, int32_t predictedValue = 0x7FFF; } -void SWAV::DecodeADPCM(const std::vector &origData) +void SWAV::DecodeADPCM(const uint8_t *origData, uint32_t len) { int32_t predictedValue = origData[0] | (origData[1] << 8); int32_t stepIndex = origData[2] | (origData[3] << 8); + auto finalData = &this->data[0]; - for (long i = 0, len = origData.size() - 4; i < len; ++i) + for (uint32_t i = 0; i < len; ++i) { int32_t nibble = origData[i + 4] & 0x0F; DecodeADPCMNibble(nibble, stepIndex, predictedValue); - this->data[2 * i] = predictedValue; + finalData[2 * i] = predictedValue; nibble = (origData[i + 4] >> 4) & 0x0F; DecodeADPCMNibble(nibble, stepIndex, predictedValue); - this->data[2 * i + 1] = predictedValue; + finalData[2 * i + 1] = predictedValue; } } @@ -114,7 +115,7 @@ void SWAV::Read(PseudoFile &file) { // IMA ADPCM -> PCM signed 16-bit this->data.resize((origData.size() - 4) * 2, 0); - this->DecodeADPCM(origData); + this->DecodeADPCM(&origData[0], origData.size() - 4); --this->loopOffset; this->loopOffset *= 8; this->nonLoopLength *= 8; diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/SWAV.h b/Frameworks/SSEQPlayer/SSEQPlayer/SWAV.h index ad9c1454b..85ddf1828 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/SWAV.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/SWAV.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT SWAV (Waveform/Sample) structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-10 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_SWAV_H -#define SSEQPLAYER_SWAV_H +#pragma once #include "common.h" @@ -26,7 +25,5 @@ struct SWAV SWAV(); void Read(PseudoFile &file); - void DecodeADPCM(const std::vector &data); + void DecodeADPCM(const uint8_t *origData, uint32_t len); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/SYMBSection.h b/Frameworks/SSEQPlayer/SSEQPlayer/SYMBSection.h index 62d33851f..9afa3e926 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/SYMBSection.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/SYMBSection.h @@ -1,14 +1,13 @@ /* * SSEQ Player - SDAT SYMB (Symbol/Filename) Section structures * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-21 + * Last modification on 2014-09-08 * * Nintendo DS Nitro Composer (SDAT) Specification document found at * http://www.feshrine.net/hacking/doc/nds-sdat.html */ -#ifndef SSEQPLAYER_SYMBSECTION_H -#define SSEQPLAYER_SYMBSECTION_H +#pragma once #include #include "common.h" @@ -35,5 +34,3 @@ struct SYMBSection void Read(PseudoFile &file); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/Track.cpp b/Frameworks/SSEQPlayer/SSEQPlayer/Track.cpp index 0188d789f..9f5227072 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/Track.cpp +++ b/Frameworks/SSEQPlayer/SSEQPlayer/Track.cpp @@ -1,13 +1,14 @@ /* * SSEQ Player - Track structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-01 + * Last modification on 2014-10-23 * * Adapted from source code of FeOS Sound System * By fincs * https://github.com/fincs/FSS */ +#include #include "Track.h" #include "Player.h" #include "common.h" @@ -17,6 +18,7 @@ Track::Track() this->Zero(); } +// Original FSS Function: Player_InitTrack void Track::Init(uint8_t handle, Player *player, const uint8_t *dataPos, int n) { this->trackId = handle; @@ -35,9 +37,11 @@ void Track::Zero() this->ply = nullptr; this->startPos = this->pos = nullptr; - memset(this->stack, 0, sizeof(this->stack)); + std::fill_n(&this->stack[0], FSS_TRACKSTACKSIZE, StackValue()); this->stackPos = 0; memset(this->loopCount, 0, sizeof(this->loopCount)); + this->overriding() = false; + this->lastComparisonResult = true; this->wait = 0; this->patch = 0; @@ -56,6 +60,7 @@ void Track::Zero() this->updateFlags.reset(); } +// Original FSS Function: Track_ClearState void Track::ClearState() { this->state.reset(); @@ -71,8 +76,7 @@ void Track::ClearState() this->portaKey = 60; this->portaTime = 0; this->sweepPitch = 0; - this->vol = 64; - this->expr = 127; + this->vol = this->expr = 127; this->pan = 0; this->pitchBendRange = 2; this->pitchBend = this->transpose = 0; @@ -82,16 +86,18 @@ void Track::ClearState() this->modType = 0; this->modRange = 1; this->modSpeed = 16; - this->modDelay = 10; + this->modDelay = 0; this->modDepth = 0; } +// Original FSS Function: Track_Free void Track::Free() { this->state.reset(); this->updateFlags.reset(); } +// Original FSS Function: Note_On int Track::NoteOn(int key, int vel, int len) { auto sbnk = this->ply->sseq->bank; @@ -210,6 +216,7 @@ int Track::NoteOn(int key, int vel, int len) return nCh; } +// Original FSS Function: Note_On_Tie int Track::NoteOnTie(int key, int vel) { // Find an existing note @@ -245,6 +252,7 @@ int Track::NoteOnTie(int key, int vel) return i; } +// Original FSS Function: Track_ReleaseAllNotes void Track::ReleaseAllNotes() { for (int i = 0; i < 16; ++i) @@ -257,6 +265,9 @@ void Track::ReleaseAllNotes() enum SseqCommand { + SSEQ_CMD_ALLOCTRACK = 0xFE, // Silently ignored + SSEQ_CMD_OPENTRACK = 0x93, + SSEQ_CMD_REST = 0x80, SSEQ_CMD_PATCH = 0x81, SSEQ_CMD_PAN = 0xC0, @@ -298,11 +309,173 @@ enum SseqCommand SSEQ_CMD_RANDOM = 0xA0, SSEQ_CMD_PRINTVAR = 0xD6, SSEQ_CMD_IF = 0xA2, - SSEQ_CMD_UNSUP1 = 0xA1, - SSEQ_CMD_UNSUP2_LO = 0xB0, - SSEQ_CMD_UNSUP2_HI = 0xBD + SSEQ_CMD_FROMVAR = 0xA1, + SSEQ_CMD_SETVAR = 0xB0, + SSEQ_CMD_ADDVAR = 0xB1, + SSEQ_CMD_SUBVAR = 0xB2, + SSEQ_CMD_MULVAR = 0xB3, + SSEQ_CMD_DIVVAR = 0xB4, + SSEQ_CMD_SHIFTVAR = 0xB5, + SSEQ_CMD_RANDVAR = 0xB6, + SSEQ_CMD_CMP_EQ = 0xB8, + SSEQ_CMD_CMP_GE = 0xB9, + SSEQ_CMD_CMP_GT = 0xBA, + SSEQ_CMD_CMP_LE = 0xBB, + SSEQ_CMD_CMP_LT = 0xBC, + SSEQ_CMD_CMP_NE = 0xBD, + + SSEQ_CMD_MUTE = 0xD7 // Unsupported }; +static const uint8_t VariableByteCount = 1 << 7; +static const uint8_t ExtraByteOnNoteOrVarOrCmp = 1 << 6; + +static inline uint8_t SseqCommandByteCount(int cmd) +{ + if (cmd < 0x80) + return 1 | VariableByteCount; + else + switch (cmd) + { + case SSEQ_CMD_REST: + case SSEQ_CMD_PATCH: + return VariableByteCount; + + case SSEQ_CMD_PAN: + case SSEQ_CMD_VOL: + case SSEQ_CMD_MASTERVOL: + case SSEQ_CMD_PRIO: + case SSEQ_CMD_NOTEWAIT: + case SSEQ_CMD_TIE: + case SSEQ_CMD_EXPR: + case SSEQ_CMD_LOOPSTART: + case SSEQ_CMD_TRANSPOSE: + case SSEQ_CMD_PITCHBEND: + case SSEQ_CMD_PITCHBENDRANGE: + case SSEQ_CMD_ATTACK: + case SSEQ_CMD_DECAY: + case SSEQ_CMD_SUSTAIN: + case SSEQ_CMD_RELEASE: + case SSEQ_CMD_PORTAKEY: + case SSEQ_CMD_PORTAFLAG: + case SSEQ_CMD_PORTATIME: + case SSEQ_CMD_MODDEPTH: + case SSEQ_CMD_MODSPEED: + case SSEQ_CMD_MODTYPE: + case SSEQ_CMD_MODRANGE: + case SSEQ_CMD_PRINTVAR: + case SSEQ_CMD_MUTE: + return 1; + + case SSEQ_CMD_ALLOCTRACK: + case SSEQ_CMD_TEMPO: + case SSEQ_CMD_SWEEPPITCH: + case SSEQ_CMD_MODDELAY: + return 2; + + case SSEQ_CMD_GOTO: + case SSEQ_CMD_CALL: + case SSEQ_CMD_SETVAR: + case SSEQ_CMD_ADDVAR: + case SSEQ_CMD_SUBVAR: + case SSEQ_CMD_MULVAR: + case SSEQ_CMD_DIVVAR: + case SSEQ_CMD_SHIFTVAR: + case SSEQ_CMD_RANDVAR: + case SSEQ_CMD_CMP_EQ: + case SSEQ_CMD_CMP_GE: + case SSEQ_CMD_CMP_GT: + case SSEQ_CMD_CMP_LE: + case SSEQ_CMD_CMP_LT: + case SSEQ_CMD_CMP_NE: + return 3; + + case SSEQ_CMD_OPENTRACK: + return 4; + + case SSEQ_CMD_FROMVAR: + return 1 | ExtraByteOnNoteOrVarOrCmp; // Technically 2 bytes with an additional 1, leaving 1 off because we will be reading it to determine if the additional byte is needed + + case SSEQ_CMD_RANDOM: + return 4 | ExtraByteOnNoteOrVarOrCmp; // Technically 5 bytes with an additional 1, leaving 1 off because we will be reading it to determine if the additional byte is needed + + default: + return 0; + } +} + +static auto varFuncSet = [](int16_t, int16_t value) { return value; }; +static auto varFuncAdd = [](int16_t var, int16_t value) -> int16_t { return var + value; }; +static auto varFuncSub = [](int16_t var, int16_t value) -> int16_t { return var - value; }; +static auto varFuncMul = [](int16_t var, int16_t value) -> int16_t { return var * value; }; +static auto varFuncDiv = [](int16_t var, int16_t value) -> int16_t { return var / value; }; +static auto varFuncShift = [](int16_t var, int16_t value) -> int16_t +{ + if (value < 0) + return var >> -value; + else + return var << value; +}; +static auto varFuncRand = [](int16_t, int16_t value) -> int16_t +{ + if (value < 0) + return -(std::rand() % (-value + 1)); + else + return std::rand() % (value + 1); +}; + +static inline std::function VarFunc(int cmd) +{ + switch (cmd) + { + case SSEQ_CMD_SETVAR: + return varFuncSet; + case SSEQ_CMD_ADDVAR: + return varFuncAdd; + case SSEQ_CMD_SUBVAR: + return varFuncSub; + case SSEQ_CMD_MULVAR: + return varFuncMul; + case SSEQ_CMD_DIVVAR: + return varFuncDiv; + case SSEQ_CMD_SHIFTVAR: + return varFuncShift; + case SSEQ_CMD_RANDVAR: + return varFuncRand; + default: + return nullptr; + } +} + +static auto compareFuncEq = [](int16_t a, int16_t b) { return a == b; }; +static auto compareFuncGe = [](int16_t a, int16_t b) { return a >= b; }; +static auto compareFuncGt = [](int16_t a, int16_t b) { return a > b; }; +static auto compareFuncLe = [](int16_t a, int16_t b) { return a <= b; }; +static auto compareFuncLt = [](int16_t a, int16_t b) { return a < b; }; +static auto compareFuncNe = [](int16_t a, int16_t b) { return a != b; }; + +static inline std::function CompareFunc(int cmd) +{ + switch (cmd) + { + case SSEQ_CMD_CMP_EQ: + return compareFuncEq; + case SSEQ_CMD_CMP_GE: + return compareFuncGe; + case SSEQ_CMD_CMP_GT: + return compareFuncGt; + case SSEQ_CMD_CMP_LE: + return compareFuncLe; + case SSEQ_CMD_CMP_LT: + return compareFuncLt; + case SSEQ_CMD_CMP_NE: + return compareFuncNe; + default: + return nullptr; + } +} + +// Original FSS Function: Track_Run void Track::Run() { // Indicate "heartbeat" for this track @@ -323,13 +496,17 @@ void Track::Run() while (!this->wait) { - int cmd = read8(pData); + int cmd; + if (this->overriding()) + cmd = this->overriding.cmd; + else + cmd = read8(pData); if (cmd < 0x80) { // Note on int key = cmd + this->transpose; - int vel = read8(pData); - int len = readvl(pData); + int vel = this->overriding.val(pData, read8, true); + int len = this->overriding.val(pData, readvl); if (this->state[TS_NOTEWAIT]) this->wait = len; if (this->state[TS_TIEBIT]) @@ -338,18 +515,33 @@ void Track::Run() this->NoteOn(key, vel, len); } else + { + int value; switch (cmd) { //----------------------------------------------------------------- // Main commands //----------------------------------------------------------------- + case SSEQ_CMD_OPENTRACK: + { + int tNum = read8(pData); + auto trackPos = &this->ply->sseq->data[read24(pData)]; + int newTrack = this->ply->TrackAlloc(); + if (newTrack != -1) + { + this->ply->tracks[newTrack].Init(newTrack, this->ply, trackPos, tNum); + this->ply->trackIds[this->ply->nTracks++] = newTrack; + } + break; + } + case SSEQ_CMD_REST: - this->wait = readvl(pData); + this->wait = this->overriding.val(pData, readvl); break; case SSEQ_CMD_PATCH: - this->patch = readvl(pData); + this->patch = this->overriding.val(pData, readvl); break; case SSEQ_CMD_GOTO: @@ -357,29 +549,32 @@ void Track::Run() break; case SSEQ_CMD_CALL: - { - const uint8_t *dest = &this->ply->sseq->data[read24(pData)]; - this->stack[this->stackPos++] = *pData; - *pData = dest; + value = read24(pData); + if (this->stackPos < FSS_TRACKSTACKSIZE) + { + const uint8_t *dest = &this->ply->sseq->data[value]; + this->stack[this->stackPos++] = StackValue(STACKTYPE_CALL, *pData); + *pData = dest; + } break; - } case SSEQ_CMD_RET: - *pData = this->stack[--this->stackPos]; + if (this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_CALL) + *pData = this->stack[--this->stackPos].dest; break; case SSEQ_CMD_PAN: - this->pan = read8(pData) - 64; + this->pan = this->overriding.val(pData, read8) - 64; this->updateFlags.set(TUF_PAN); break; case SSEQ_CMD_VOL: - this->vol = read8(pData); + this->vol = this->overriding.val(pData, read8); this->updateFlags.set(TUF_VOL); break; case SSEQ_CMD_MASTERVOL: - this->ply->masterVol = Cnv_Sust(read8(pData)); + this->ply->masterVol = Cnv_Sust(this->overriding.val(pData, read8)); for (uint8_t i = 0; i < this->ply->nTracks; ++i) this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL); break; @@ -399,7 +594,7 @@ void Track::Run() break; case SSEQ_CMD_EXPR: - this->expr = read8(pData); + this->expr = this->overriding.val(pData, read8); this->updateFlags.set(TUF_VOL); break; @@ -412,19 +607,24 @@ void Track::Run() return; case SSEQ_CMD_LOOPSTART: - this->loopCount[this->stackPos] = read8(pData); - this->stack[this->stackPos++] = *pData; + value = this->overriding.val(pData, read8); + if (this->stackPos < FSS_TRACKSTACKSIZE) + { + this->loopCount[this->stackPos] = value; + this->stack[this->stackPos++] = StackValue(STACKTYPE_LOOP, *pData); + } break; case SSEQ_CMD_LOOPEND: - if (this->stackPos) + if (this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_LOOP) { - const uint8_t *rPos = this->stack[this->stackPos - 1]; + const uint8_t *rPos = this->stack[this->stackPos - 1].dest; uint8_t &nR = this->loopCount[this->stackPos - 1]; uint8_t prevR = nR; - if (prevR && !--nR) + if (!prevR || --nR) + *pData = rPos; + else --this->stackPos; - *pData = rPos; } break; @@ -433,11 +633,11 @@ void Track::Run() //----------------------------------------------------------------- case SSEQ_CMD_TRANSPOSE: - this->transpose = read8(pData); + this->transpose = this->overriding.val(pData, read8); break; case SSEQ_CMD_PITCHBEND: - this->pitchBend = read8(pData); + this->pitchBend = this->overriding.val(pData, read8); this->updateFlags.set(TUF_TIMER); break; @@ -451,19 +651,19 @@ void Track::Run() //----------------------------------------------------------------- case SSEQ_CMD_ATTACK: - this->a = read8(pData); + this->a = this->overriding.val(pData, read8); break; case SSEQ_CMD_DECAY: - this->d = read8(pData); + this->d = this->overriding.val(pData, read8); break; case SSEQ_CMD_SUSTAIN: - this->s = read8(pData); + this->s = this->overriding.val(pData, read8); break; case SSEQ_CMD_RELEASE: - this->r = read8(pData); + this->r = this->overriding.val(pData, read8); break; //----------------------------------------------------------------- @@ -482,12 +682,12 @@ void Track::Run() break; case SSEQ_CMD_PORTATIME: - this->portaTime = read8(pData); + this->portaTime = this->overriding.val(pData, read8); // Update here? break; case SSEQ_CMD_SWEEPPITCH: - this->sweepPitch = read16(pData); + this->sweepPitch = this->overriding.val(pData, read16); // Update here? break; @@ -496,12 +696,12 @@ void Track::Run() //----------------------------------------------------------------- case SSEQ_CMD_MODDEPTH: - this->modDepth = read8(pData); + this->modDepth = this->overriding.val(pData, read8); this->updateFlags.set(TUF_MOD); break; case SSEQ_CMD_MODSPEED: - this->modSpeed = read8(pData); + this->modSpeed = this->overriding.val(pData, read8); this->updateFlags.set(TUF_MOD); break; @@ -516,37 +716,97 @@ void Track::Run() break; case SSEQ_CMD_MODDELAY: - this->modDelay = read16(pData); + this->modDelay = this->overriding.val(pData, read16); this->updateFlags.set(TUF_MOD); break; + //----------------------------------------------------------------- + // Randomness-related commands + //----------------------------------------------------------------- + + case SSEQ_CMD_RANDOM: + { + this->overriding() = true; + this->overriding.cmd = read8(pData); + if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80) + this->overriding.extraValue = read8(pData); + int16_t minVal = read16(pData); + int16_t maxVal = read16(pData); + this->overriding.value = (std::rand() % (maxVal - minVal + 1)) + minVal; + break; + } + //----------------------------------------------------------------- // Variable-related commands //----------------------------------------------------------------- - case SSEQ_CMD_RANDOM: // TODO - *pData += 5; + case SSEQ_CMD_FROMVAR: + this->overriding() = true; + this->overriding.cmd = read8(pData); + if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80) + this->overriding.extraValue = read8(pData); + this->overriding.value = this->ply->variables[read8(pData)]; break; - case SSEQ_CMD_PRINTVAR: // TODO - *pData += 1; - break; - - case SSEQ_CMD_UNSUP1: // TODO + case SSEQ_CMD_SETVAR: + case SSEQ_CMD_ADDVAR: + case SSEQ_CMD_SUBVAR: + case SSEQ_CMD_MULVAR: + case SSEQ_CMD_DIVVAR: + case SSEQ_CMD_SHIFTVAR: + case SSEQ_CMD_RANDVAR: { - int t = read8(pData); - if (t >= SSEQ_CMD_UNSUP2_LO && t <= SSEQ_CMD_UNSUP2_HI) - *pData += 1; - *pData += 1; + int8_t varNo = this->overriding.val(pData, read8, true); + value = this->overriding.val(pData, read16); + if (cmd == SSEQ_CMD_DIVVAR && !value) // Division by 0, skip it to prevent crashing + break; + this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], value); break; } - case SSEQ_CMD_IF: // TODO + //----------------------------------------------------------------- + // Conditional-related commands + //----------------------------------------------------------------- + + case SSEQ_CMD_CMP_EQ: + case SSEQ_CMD_CMP_GE: + case SSEQ_CMD_CMP_GT: + case SSEQ_CMD_CMP_LE: + case SSEQ_CMD_CMP_LT: + case SSEQ_CMD_CMP_NE: + { + int8_t varNo = this->overriding.val(pData, read8, true); + value = this->overriding.val(pData, read16); + this->lastComparisonResult = CompareFunc(cmd)(this->ply->variables[varNo], value); + break; + } + + case SSEQ_CMD_IF: + if (!this->lastComparisonResult) + { + int nextCmd = read8(pData); + uint8_t cmdBytes = SseqCommandByteCount(nextCmd); + bool variableBytes = !!(cmdBytes & VariableByteCount); + bool extraByte = !!(cmdBytes & ExtraByteOnNoteOrVarOrCmp); + cmdBytes &= ~(VariableByteCount | ExtraByteOnNoteOrVarOrCmp); + if (extraByte) + { + int extraCmd = read8(pData); + if ((extraCmd >= SSEQ_CMD_SETVAR && extraCmd <= SSEQ_CMD_CMP_NE) || extraCmd < 0x80) + ++cmdBytes; + } + *pData += cmdBytes; + if (variableBytes) + readvl(pData); + } break; default: - if (cmd >= SSEQ_CMD_UNSUP2_LO && cmd <= SSEQ_CMD_UNSUP2_HI) // TODO - *pData += 3; + *pData += SseqCommandByteCount(cmd); } + } + + if (cmd != SSEQ_CMD_RANDOM && cmd != SSEQ_CMD_FROMVAR) + this->overriding() = false; } } diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/Track.h b/Frameworks/SSEQPlayer/SSEQPlayer/Track.h index c209cd063..41ab47cd6 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/Track.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/Track.h @@ -1,21 +1,55 @@ /* * SSEQ Player - Track structure * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-01 + * Last modification on 2014-10-13 * * Adapted from source code of FeOS Sound System * By fincs * https://github.com/fincs/FSS */ -#ifndef SSEQPLAYER_TRACK_H -#define SSEQPLAYER_TRACK_H +#pragma once +#include #include #include "consts.h" struct Player; +enum StackType +{ + STACKTYPE_CALL, + STACKTYPE_LOOP +}; + +struct StackValue +{ + StackType type; + const uint8_t *dest; + + StackValue() : type(STACKTYPE_CALL), dest(nullptr) { } + StackValue(StackType newType, const uint8_t *newDest) : type(newType), dest(newDest) { } +}; + +struct Override +{ + bool overriding; + int cmd; + int value; + int extraValue; + + Override() : overriding(false) { } + bool operator()() const { return this->overriding; } + bool &operator()() { return this->overriding; } + int val(const uint8_t **pData, std::function reader, bool returnExtra = false) + { + if (this->overriding) + return returnExtra ? this->extraValue : this->value; + else + return reader(pData); + } +}; + struct Track { int8_t trackId; @@ -26,9 +60,11 @@ struct Track const uint8_t *startPos; const uint8_t *pos; - const uint8_t *stack[FSS_TRACKSTACKSIZE]; + StackValue stack[FSS_TRACKSTACKSIZE]; uint8_t stackPos; uint8_t loopCount[FSS_TRACKSTACKSIZE]; + Override overriding; + bool lastComparisonResult; int wait; uint16_t patch; @@ -58,5 +94,3 @@ struct Track void ReleaseAllNotes(); void Run(); }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/UTFEncodeDecode.cpp b/Frameworks/SSEQPlayer/SSEQPlayer/UTFEncodeDecode.cpp deleted file mode 100644 index 663006ad6..000000000 --- a/Frameworks/SSEQPlayer/SSEQPlayer/UTFEncodeDecode.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// original code is from here: http://www.codeproject.com/Tips/197097/Converting-ANSI-to-Unicode-and-back -// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx - -#include "UTFEncodeDecode.h" -#include "UtfConverter.h" - -std::string EncodeToUTF8(const std::string &source, const std::locale &L) -{ - try - { - return UtfConverter::ToUtf8(cp_converter<>(L).widen(source)); - } - catch (const std::runtime_error &) - { - return ""; - } -} - -std::string DecodeFromUTF8(const std::string &source, const std::locale &L) -{ - try - { - return cp_converter<>(L).narrow(UtfConverter::FromUtf8(source)); - } - catch (const std::runtime_error &) - { - return ""; - } -} diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/UTFEncodeDecode.h b/Frameworks/SSEQPlayer/SSEQPlayer/UTFEncodeDecode.h deleted file mode 100644 index f796b4cc4..000000000 --- a/Frameworks/SSEQPlayer/SSEQPlayer/UTFEncodeDecode.h +++ /dev/null @@ -1,63 +0,0 @@ -// original code is from here: http://www.codeproject.com/Tips/197097/Converting-ANSI-to-Unicode-and-back -// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx - -#ifndef UTFENCODEDECODE_H -#define UTFENCODEDECODE_H - -#include -#include -#include -#include - -std::string EncodeToUTF8(const std::string &, const std::locale & = std::locale::classic()); -std::string DecodeFromUTF8(const std::string &, const std::locale & = std::locale::classic()); - -template class cp_converter -{ - const std::locale loc; -public: - cp_converter(const std::locale &L = std::locale::classic()) : loc(L) { } - inline std::wstring widen(const std::string &in) - { - return this->convert(in); - } - inline std::string narrow(const std::wstring &in) - { - return this->convert(in); - } -private: - typedef std::codecvt codecvt_facet; - - // widen - inline codecvt_facet::result cv(const codecvt_facet &facet, mbstate_t &s, const char *f1, const char *l1, const char *&n1, wchar_t *f2, wchar_t *l2, wchar_t *&n2) const - { - return facet.in(s, f1, l1, n1, f2, l2, n2); - } - - // narrow - inline codecvt_facet::result cv(const codecvt_facet &facet, mbstate_t &s, const wchar_t *f1, const wchar_t *l1, const wchar_t *&n1, char *f2, char *l2, char *&n2) const - { - return facet.out(s, f1, l1, n1, f2, l2, n2); - } - - template std::basic_string convert(const std::basic_string &in) - { - auto &facet = std::use_facet(this->loc); - std::basic_stringstream os; - ct_out buf[buf_size]; - mbstate_t state = {0}; - codecvt_facet::result result; - const ct_in *ipc = &in[0]; - do - { - ct_out *opc = nullptr; - result = this->cv(facet, state, ipc, &in[0] + in.length(), ipc, buf, buf + buf_size, opc); - os << std::basic_string(buf, opc - buf); - } while (ipc < &in[0] + in.length() && result != codecvt_facet::error); - if (result != codecvt_facet::ok) - throw std::runtime_error("result is not ok!"); - return os.str(); - } -}; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/UtfConverter.cpp b/Frameworks/SSEQPlayer/SSEQPlayer/UtfConverter.cpp deleted file mode 100644 index b0f148a4a..000000000 --- a/Frameworks/SSEQPlayer/SSEQPlayer/UtfConverter.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// original code is from here: http://www.codeproject.com/Articles/17573/Convert-Between-std-string-and-std-wstring-UTF-8-a -// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx - -#include -#include -#include -#include "ConvertUTF.h" - -namespace UtfConverter -{ - std::wstring FromUtf8(const std::string &utf8string) - { - auto widesize = utf8string.length(); - auto result = std::vector(widesize + 1, L'\0'); - auto orig = std::vector(widesize + 1, '\0'); - std::copy(utf8string.begin(), utf8string.end(), orig.begin()); - auto *sourcestart = reinterpret_cast(&orig[0]), *sourceend = sourcestart + widesize; - ConversionResult res; - if (sizeof(wchar_t) == 2) - { - auto *targetstart = reinterpret_cast(&result[0]), *targetend = targetstart + widesize; - res = ConvertUTF8toUTF16(&sourcestart, sourceend, &targetstart, targetend, strictConversion); - *targetstart = 0; - unsigned end = targetstart - reinterpret_cast(&result[0]); - result.erase(result.begin() + end, result.end()); - } - else if (sizeof(wchar_t) == 4) - { - auto *targetstart = reinterpret_cast(&result[0]), *targetend = targetstart + widesize; - res = ConvertUTF8toUTF32(&sourcestart, sourceend, &targetstart, targetend, strictConversion); - *targetstart = 0; - unsigned long end = targetstart - reinterpret_cast(&result[0]); - result.erase(result.begin() + end, result.end()); - } - else - throw std::runtime_error("UtfConverter::FromUtf8: sizeof(wchar_t) is not 2 or 4."); - if (res != conversionOK) - throw std::runtime_error("UtfConverter::FromUtf8: Conversion failed."); - return std::wstring(result.begin(), result.end()); - } - - std::string ToUtf8(const std::wstring &widestring) - { - auto widesize = widestring.length(), utf8size = (sizeof(wchar_t) == 2 ? 3 : 4) * widesize + 1; - auto result = std::vector(utf8size, '\0'); - auto orig = std::vector(widesize + 1, L'\0'); - std::copy(widestring.begin(), widestring.end(), orig.begin()); - auto *targetstart = reinterpret_cast(&result[0]), *targetend = targetstart + utf8size; - ConversionResult res; - if (sizeof(wchar_t) == 2) - { - auto *sourcestart = reinterpret_cast(&orig[0]), *sourceend = sourcestart + widesize; - res = ConvertUTF16toUTF8(&sourcestart, sourceend, &targetstart, targetend, strictConversion); - } - else if (sizeof(wchar_t) == 4) - { - auto *sourcestart = reinterpret_cast(&orig[0]), *sourceend = sourcestart + widesize; - res = ConvertUTF32toUTF8(&sourcestart, sourceend, &targetstart, targetend, strictConversion); - } - else - throw std::runtime_error("UtfConverter::ToUtf8: sizeof(wchar_t) is not 2 or 4."); - if (res != conversionOK) - throw std::runtime_error("UtfConverter::ToUtf8: Conversion failed."); - *targetstart = 0; - auto end = targetstart - reinterpret_cast(&result[0]); - result.erase(result.begin() + end, result.end()); - return std::string(result.begin(), result.end()); - } -} diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/UtfConverter.h b/Frameworks/SSEQPlayer/SSEQPlayer/UtfConverter.h deleted file mode 100644 index 92e423b53..000000000 --- a/Frameworks/SSEQPlayer/SSEQPlayer/UtfConverter.h +++ /dev/null @@ -1,15 +0,0 @@ -// original code is from here: http://www.codeproject.com/Articles/17573/Convert-Between-std-string-and-std-wstring-UTF-8-a -// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx - -#ifndef UTFCONVERTER_H -#define UTFCONVERTER_H - -#include - -namespace UtfConverter -{ - std::wstring FromUtf8(const std::string &); - std::string ToUtf8(const std::wstring &); -} - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/codecvt.h b/Frameworks/SSEQPlayer/SSEQPlayer/codecvt.h new file mode 100644 index 000000000..d7e1a8504 --- /dev/null +++ b/Frameworks/SSEQPlayer/SSEQPlayer/codecvt.h @@ -0,0 +1,2098 @@ +// This comes from llvm's libcxx project. I've copied the code from there (with very minor modifications) for use with GCC and Clang when libcxx isn't being used. + +#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION) +#pragma once + +#include + +namespace std +{ + +enum codecvt_mode +{ + consume_header = 4, + generate_header = 2, + little_endian = 1 +}; + +// Valid UTF ranges +// UTF-32 UTF-16 UTF-8 # of code points +// first second first second third fourth +// 000000 - 00007F 0000 - 007F 00 - 7F 127 +// 000080 - 0007FF 0080 - 07FF C2 - DF, 80 - BF 1920 +// 000800 - 000FFF 0800 - 0FFF E0 - E0, A0 - BF, 80 - BF 2048 +// 001000 - 00CFFF 1000 - CFFF E1 - EC, 80 - BF, 80 - BF 49152 +// 00D000 - 00D7FF D000 - D7FF ED - ED, 80 - 9F, 80 - BF 2048 +// 00D800 - 00DFFF invalid +// 00E000 - 00FFFF E000 - FFFF EE - EF, 80 - BF, 80 - BF 8192 +// 010000 - 03FFFF D800 - D8BF, DC00 - DFFF F0 - F0, 90 - BF, 80 - BF, 80 - BF 196608 +// 040000 - 0FFFFF D8C0 - DBBF, DC00 - DFFF F1 - F3, 80 - BF, 80 - BF, 80 - BF 786432 +// 100000 - 10FFFF DBC0 - DBFF, DC00 - DFFF F4 - F4, 80 - 8F, 80 - BF, 80 - BF 65536 + +namespace UnicodeConverters +{ + inline codecvt_base::result utf16_to_utf8(const uint16_t *frm, const uint16_t *frm_end, const uint16_t *&frm_nxt, uint8_t *to, uint8_t *to_end, uint8_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if (mode & generate_header) + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = 0xEF; + *to_nxt++ = 0xBB; + *to_nxt++ = 0xBF; + } + for (; frm_nxt < frm_end; ++frm_nxt) + { + uint16_t wc1 = *frm_nxt; + if (wc1 > Maxcode) + return codecvt_base::error; + if (wc1 < 0x0080) + { + if (to_end - to_nxt < 1) + return codecvt_base::partial; + *to_nxt++ = static_cast(wc1); + } + else if (wc1 < 0x0800) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xC0 | (wc1 >> 6)); + *to_nxt++ = static_cast(0x80 | (wc1 & 0x03F)); + } + else if (wc1 < 0xD800) + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xE0 | (wc1 >> 12)); + *to_nxt++ = static_cast(0x80 | ((wc1 & 0x0FC0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc1 & 0x003F)); + } + else if (wc1 < 0xDC00) + { + if (frm_end - frm_nxt < 2) + return codecvt_base::partial; + uint16_t wc2 = frm_nxt[1]; + if ((wc2 & 0xFC00) != 0xDC00) + return codecvt_base::error; + if (to_end - to_nxt < 4) + return codecvt_base::partial; + if (((((static_cast(wc1) & 0x03C0) >> 6) + 1) << 16) + ((static_cast(wc1) & 0x003F) << 10) + (wc2 & 0x03FF) > Maxcode) + return codecvt_base::error; + ++frm_nxt; + uint8_t z = ((wc1 & 0x03C0) >> 6) + 1; + *to_nxt++ = static_cast(0xF0 | (z >> 2)); + *to_nxt++ = static_cast(0x80 | ((z & 0x03) << 4) | ((wc1 & 0x003C) >> 2)); + *to_nxt++ = static_cast(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc2 & 0x003F)); + } + else if (wc1 < 0xE000) + return codecvt_base::error; + else + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xE0 | (wc1 >> 12)); + *to_nxt++ = static_cast(0x80 | ((wc1 & 0x0FC0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc1 & 0x003F)); + } + } + return codecvt_base::ok; + } + + inline codecvt_base::result utf16_to_utf8(const uint32_t *frm, const uint32_t *frm_end, const uint32_t *&frm_nxt, uint8_t *to, uint8_t *to_end, uint8_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if (mode & generate_header) + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = 0xEF; + *to_nxt++ = 0xBB; + *to_nxt++ = 0xBF; + } + for (; frm_nxt < frm_end; ++frm_nxt) + { + uint16_t wc1 = static_cast(*frm_nxt); + if (wc1 > Maxcode) + return codecvt_base::error; + if (wc1 < 0x0080) + { + if (to_end - to_nxt < 1) + return codecvt_base::partial; + *to_nxt++ = static_cast(wc1); + } + else if (wc1 < 0x0800) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xC0 | (wc1 >> 6)); + *to_nxt++ = static_cast(0x80 | (wc1 & 0x03F)); + } + else if (wc1 < 0xD800) + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xE0 | (wc1 >> 12)); + *to_nxt++ = static_cast(0x80 | ((wc1 & 0x0FC0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc1 & 0x003F)); + } + else if (wc1 < 0xDC00) + { + if (frm_end - frm_nxt < 2) + return codecvt_base::partial; + uint16_t wc2 = static_cast(frm_nxt[1]); + if ((wc2 & 0xFC00) != 0xDC00) + return codecvt_base::error; + if (to_end - to_nxt < 4) + return codecvt_base::partial; + if (((((static_cast(wc1) & 0x03C0) >> 6) + 1) << 16) + ((static_cast(wc1) & 0x003F) << 10) + (wc2 & 0x03FF) > Maxcode) + return codecvt_base::error; + ++frm_nxt; + uint8_t z = ((wc1 & 0x03C0) >> 6) + 1; + *to_nxt++ = static_cast(0xF0 | (z >> 2)); + *to_nxt++ = static_cast(0x80 | ((z & 0x03) << 4) | ((wc1 & 0x003C) >> 2)); + *to_nxt++ = static_cast(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc2 & 0x003F)); + } + else if (wc1 < 0xE000) + return codecvt_base::error; + else + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xE0 | (wc1 >> 12)); + *to_nxt++ = static_cast(0x80 | ((wc1 & 0x0FC0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc1 & 0x003F)); + } + } + return codecvt_base::ok; + } + + inline codecvt_base::result utf8_to_utf16(const uint8_t *frm, const uint8_t *frm_end, const uint8_t *&frm_nxt, uint16_t *to, uint16_t *to_end, uint16_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if ((mode & consume_header) && frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF) + frm_nxt += 3; + for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt) + { + uint8_t c1 = *frm_nxt; + if (c1 > Maxcode) + return codecvt_base::error; + if (c1 < 0x80) + { + *to_nxt = static_cast(c1); + ++frm_nxt; + } + else if (c1 < 0xC2) + return codecvt_base::error; + else if (c1 < 0xE0) + { + if (frm_end - frm_nxt < 2) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + uint16_t t = static_cast(((c1 & 0x1F) << 6) | (c2 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 2; + } + else if (c1 < 0xF0) + { + if (frm_end - frm_nxt < 3) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + switch (c1) + { + case 0xE0: + if ((c2 & 0xE0) != 0xA0) + return codecvt_base::error; + break; + case 0xED: + if ((c2 & 0xE0) != 0x80) + return codecvt_base::error; + break; + default: + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + } + if ((c3 & 0xC0) != 0x80) + return codecvt_base::error; + uint16_t t = static_cast(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 3; + } + else if (c1 < 0xF5) + { + if (frm_end - frm_nxt < 4) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + uint8_t c4 = frm_nxt[3]; + switch (c1) + { + case 0xF0: + if (c2 < 0x90 || c2 > 0xBF) + return codecvt_base::error; + break; + case 0xF4: + if ((c2 & 0xF0) != 0x80) + return codecvt_base::error; + break; + default: + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + } + if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80) + return codecvt_base::error; + if (to_end - to_nxt < 2) + return codecvt_base::partial; + if ((((static_cast(c1) & 7) << 18) + ((static_cast(c2) & 0x3F) << 12) + ((static_cast(c3) & 0x3F) << 6) + (c4 & 0x3F)) > Maxcode) + return codecvt_base::error; + *to_nxt = static_cast(0xD800 | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6) | ((c2 & 0x0F) << 2) | ((c3 & 0x30) >> 4)); + *++to_nxt = static_cast(0xDC00 | ((c3 & 0x0F) << 6) | (c4 & 0x3F)); + frm_nxt += 4; + } + else + return codecvt_base::error; + } + return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok; + } + + inline codecvt_base::result utf8_to_utf16(const uint8_t *frm, const uint8_t *frm_end, const uint8_t *&frm_nxt, uint32_t *to, uint32_t *to_end, uint32_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if ((mode & consume_header) && frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF) + frm_nxt += 3; + for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt) + { + uint8_t c1 = *frm_nxt; + if (c1 > Maxcode) + return codecvt_base::error; + if (c1 < 0x80) + { + *to_nxt = static_cast(c1); + ++frm_nxt; + } + else if (c1 < 0xC2) + return codecvt_base::error; + else if (c1 < 0xE0) + { + if (frm_end - frm_nxt < 2) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + uint16_t t = static_cast(((c1 & 0x1F) << 6) | (c2 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = static_cast(t); + frm_nxt += 2; + } + else if (c1 < 0xF0) + { + if (frm_end - frm_nxt < 3) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + switch (c1) + { + case 0xE0: + if ((c2 & 0xE0) != 0xA0) + return codecvt_base::error; + break; + case 0xED: + if ((c2 & 0xE0) != 0x80) + return codecvt_base::error; + break; + default: + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + } + if ((c3 & 0xC0) != 0x80) + return codecvt_base::error; + uint16_t t = static_cast(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = static_cast(t); + frm_nxt += 3; + } + else if (c1 < 0xF5) + { + if (frm_end - frm_nxt < 4) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + uint8_t c4 = frm_nxt[3]; + switch (c1) + { + case 0xF0: + if (c2 < 0x90 || c2 > 0xBF) + return codecvt_base::error; + break; + case 0xF4: + if ((c2 & 0xF0) != 0x80) + return codecvt_base::error; + break; + default: + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + } + if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80) + return codecvt_base::error; + if (to_end - to_nxt < 2) + return codecvt_base::partial; + if ((((static_cast(c1) & 7) << 18) + ((static_cast(c2) & 0x3F) << 12) + ((static_cast(c3) & 0x3F) << 6) + (c4 & 0x3F)) > Maxcode) + return codecvt_base::error; + *to_nxt = static_cast(0xD800 | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6) | ((c2 & 0x0F) << 2) | ((c3 & 0x30) >> 4)); + *++to_nxt = static_cast( 0xDC00 | ((c3 & 0x0F) << 6) | (c4 & 0x3F)); + frm_nxt += 4; + } + else + return codecvt_base::error; + } + return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok; + } + + inline int utf8_to_utf16_length(const uint8_t *frm, const uint8_t *frm_end, size_t mx, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + auto frm_nxt = frm; + if ((mode & consume_header) && frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF) + frm_nxt += 3; + for (size_t nchar16_t = 0; frm_nxt < frm_end && nchar16_t < mx; ++nchar16_t) + { + uint8_t c1 = *frm_nxt; + if (c1 > Maxcode) + break; + if (c1 < 0x80) + ++frm_nxt; + else if (c1 < 0xC2) + break; + else if (c1 < 0xE0) + { + if (frm_end - frm_nxt < 2 || (frm_nxt[1] & 0xC0) != 0x80) + break; + uint16_t t = static_cast(((c1 & 0x1F) << 6) | (frm_nxt[1] & 0x3F)); + if (t > Maxcode) + break; + frm_nxt += 2; + } + else if (c1 < 0xF0) + { + if (frm_end - frm_nxt < 3) + break; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + switch (c1) + { + case 0xE0: + if ((c2 & 0xE0) != 0xA0) + return static_cast(frm_nxt - frm); + break; + case 0xED: + if ((c2 & 0xE0) != 0x80) + return static_cast(frm_nxt - frm); + break; + default: + if ((c2 & 0xC0) != 0x80) + return static_cast(frm_nxt - frm); + } + if ((c3 & 0xC0) != 0x80) + break; + if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode) + break; + frm_nxt += 3; + } + else if (c1 < 0xF5) + { + if (frm_end - frm_nxt < 4 || mx - nchar16_t < 2) + break; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + uint8_t c4 = frm_nxt[3]; + switch (c1) + { + case 0xF0: + if (c2 < 0x90 || c2 > 0xBF) + return static_cast(frm_nxt - frm); + break; + case 0xF4: + if ((c2 & 0xF0) != 0x80) + return static_cast(frm_nxt - frm); + break; + default: + if ((c2 & 0xC0) != 0x80) + return static_cast(frm_nxt - frm); + } + if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80) + break; + if ((((static_cast(c1) & 7) << 18) + ((static_cast(c2) & 0x3F) << 12) + ((static_cast(c3) & 0x3F) << 6) + (c4 & 0x3F)) > Maxcode) + break; + ++nchar16_t; + frm_nxt += 4; + } + else + break; + } + return static_cast(frm_nxt - frm); + } + + inline codecvt_base::result ucs4_to_utf8(const uint32_t *frm, const uint32_t *frm_end, const uint32_t *&frm_nxt, uint8_t *to, uint8_t *to_end, uint8_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if (mode & generate_header) + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = 0xEF; + *to_nxt++ = 0xBB; + *to_nxt++ = 0xBF; + } + for (; frm_nxt < frm_end; ++frm_nxt) + { + uint32_t wc = *frm_nxt; + if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode) + return codecvt_base::error; + if (wc < 0x000080) + { + if (to_end - to_nxt < 1) + return codecvt_base::partial; + *to_nxt++ = static_cast(wc); + } + else if (wc < 0x000800) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xC0 | (wc >> 6)); + *to_nxt++ = static_cast(0x80 | (wc & 0x03F)); + } + else if (wc < 0x010000) + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xE0 | (wc >> 12)); + *to_nxt++ = static_cast(0x80 | ((wc & 0x0FC0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc & 0x003F)); + } + else // if (wc < 0x110000) + { + if (to_end - to_nxt < 4) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xF0 | (wc >> 18)); + *to_nxt++ = static_cast(0x80 | ((wc & 0x03F000) >> 12)); + *to_nxt++ = static_cast(0x80 | ((wc & 0x000FC0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc & 0x00003F)); + } + } + return codecvt_base::ok; + } + + inline codecvt_base::result utf8_to_ucs4(const uint8_t *frm, const uint8_t *frm_end, const uint8_t *&frm_nxt, uint32_t *to, uint32_t *to_end, uint32_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if ((mode & consume_header) && frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF) + frm_nxt += 3; + for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt) + { + uint8_t c1 = *frm_nxt; + if (c1 < 0x80) + { + if (c1 > Maxcode) + return codecvt_base::error; + *to_nxt = static_cast(c1); + ++frm_nxt; + } + else if (c1 < 0xC2) + return codecvt_base::error; + else if (c1 < 0xE0) + { + if (frm_end - frm_nxt < 2) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + uint32_t t = static_cast(((c1 & 0x1F) << 6) | (c2 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 2; + } + else if (c1 < 0xF0) + { + if (frm_end - frm_nxt < 3) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + switch (c1) + { + case 0xE0: + if ((c2 & 0xE0) != 0xA0) + return codecvt_base::error; + break; + case 0xED: + if ((c2 & 0xE0) != 0x80) + return codecvt_base::error; + break; + default: + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + } + if ((c3 & 0xC0) != 0x80) + return codecvt_base::error; + uint32_t t = static_cast(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 3; + } + else if (c1 < 0xF5) + { + if (frm_end - frm_nxt < 4) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + uint8_t c4 = frm_nxt[3]; + switch (c1) + { + case 0xF0: + if (c2 < 0x90 || c2 > 0xBF) + return codecvt_base::error; + break; + case 0xF4: + if ((c2 & 0xF0) != 0x80) + return codecvt_base::error; + break; + default: + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + } + if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80) + return codecvt_base::error; + uint32_t t = static_cast(((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 4; + } + else + return codecvt_base::error; + } + return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok; + } + + inline int utf8_to_ucs4_length(const uint8_t *frm, const uint8_t *frm_end, size_t mx, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + auto frm_nxt = frm; + if ((mode & consume_header) && frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF) + frm_nxt += 3; + for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t) + { + uint8_t c1 = *frm_nxt; + if (c1 < 0x80) + { + if (c1 > Maxcode) + break; + ++frm_nxt; + } + else if (c1 < 0xC2) + break; + else if (c1 < 0xE0) + { + if (frm_end - frm_nxt < 2 || (frm_nxt[1] & 0xC0) != 0x80) + break; + if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode) + break; + frm_nxt += 2; + } + else if (c1 < 0xF0) + { + if (frm_end - frm_nxt < 3) + break; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + switch (c1) + { + case 0xE0: + if ((c2 & 0xE0) != 0xA0) + return static_cast(frm_nxt - frm); + break; + case 0xED: + if ((c2 & 0xE0) != 0x80) + return static_cast(frm_nxt - frm); + break; + default: + if ((c2 & 0xC0) != 0x80) + return static_cast(frm_nxt - frm); + } + if ((c3 & 0xC0) != 0x80) + break; + if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode) + break; + frm_nxt += 3; + } + else if (c1 < 0xF5) + { + if (frm_end - frm_nxt < 4) + break; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + uint8_t c4 = frm_nxt[3]; + switch (c1) + { + case 0xF0: + if (c2 < 0x90 || c2 > 0xBF) + return static_cast(frm_nxt - frm); + break; + case 0xF4: + if ((c2 & 0xF0) != 0x80) + return static_cast(frm_nxt - frm); + break; + default: + if ((c2 & 0xC0) != 0x80) + return static_cast(frm_nxt - frm); + } + if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80) + break; + if ((((c1 & 0x07u) << 18) | ((c2 & 0x3Fu) << 12) | ((c3 & 0x3Fu) << 6) | (c4 & 0x3Fu)) > Maxcode) + break; + frm_nxt += 4; + } + else + break; + } + return static_cast(frm_nxt - frm); + } + + inline codecvt_base::result ucs2_to_utf8(const uint16_t *frm, const uint16_t *frm_end, const uint16_t *&frm_nxt, uint8_t *to, uint8_t *to_end, uint8_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if (mode & generate_header) + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = 0xEF; + *to_nxt++ = 0xBB; + *to_nxt++ = 0xBF; + } + for (; frm_nxt < frm_end; ++frm_nxt) + { + uint16_t wc = *frm_nxt; + if ((wc & 0xF800) == 0xD800 || wc > Maxcode) + return codecvt_base::error; + if (wc < 0x0080) + { + if (to_end - to_nxt < 1) + return codecvt_base::partial; + *to_nxt++ = static_cast(wc); + } + else if (wc < 0x0800) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xC0 | (wc >> 6)); + *to_nxt++ = static_cast(0x80 | (wc & 0x03F)); + } + else // if (wc <= 0xFFFF) + { + if (to_end - to_nxt < 3) + return codecvt_base::partial; + *to_nxt++ = static_cast(0xE0 | (wc >> 12)); + *to_nxt++ = static_cast(0x80 | ((wc & 0x0FC0) >> 6)); + *to_nxt++ = static_cast(0x80 | (wc & 0x003F)); + } + } + return codecvt_base::ok; + } + + inline codecvt_base::result utf8_to_ucs2(const uint8_t *frm, const uint8_t *frm_end, const uint8_t *&frm_nxt, uint16_t *to, uint16_t *to_end, uint16_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if ((mode & consume_header) && frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF) + frm_nxt += 3; + for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt) + { + uint8_t c1 = *frm_nxt; + if (c1 < 0x80) + { + if (c1 > Maxcode) + return codecvt_base::error; + *to_nxt = static_cast(c1); + ++frm_nxt; + } + else if (c1 < 0xC2) + return codecvt_base::error; + else if (c1 < 0xE0) + { + if (frm_end - frm_nxt < 2) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + uint16_t t = static_cast(((c1 & 0x1F) << 6) | (c2 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 2; + } + else if (c1 < 0xF0) + { + if (frm_end - frm_nxt < 3) + return codecvt_base::partial; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + switch (c1) + { + case 0xE0: + if ((c2 & 0xE0) != 0xA0) + return codecvt_base::error; + break; + case 0xED: + if ((c2 & 0xE0) != 0x80) + return codecvt_base::error; + break; + default: + if ((c2 & 0xC0) != 0x80) + return codecvt_base::error; + } + if ((c3 & 0xC0) != 0x80) + return codecvt_base::error; + uint16_t t = static_cast(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 3; + } + else + return codecvt_base::error; + } + return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok; + } + + inline int utf8_to_ucs2_length(const uint8_t *frm, const uint8_t *frm_end, size_t mx, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + auto frm_nxt = frm; + if ((mode & consume_header) && frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF) + frm_nxt += 3; + for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t) + { + uint8_t c1 = *frm_nxt; + if (c1 < 0x80) + { + if (c1 > Maxcode) + break; + ++frm_nxt; + } + else if (c1 < 0xC2) + break; + else if (c1 < 0xE0) + { + if (frm_end - frm_nxt < 2 || (frm_nxt[1] & 0xC0) != 0x80) + break; + if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode) + break; + frm_nxt += 2; + } + else if (c1 < 0xF0) + { + if (frm_end - frm_nxt < 3) + break; + uint8_t c2 = frm_nxt[1]; + uint8_t c3 = frm_nxt[2]; + switch (c1) + { + case 0xE0: + if ((c2 & 0xE0) != 0xA0) + return static_cast(frm_nxt - frm); + break; + case 0xED: + if ((c2 & 0xE0) != 0x80) + return static_cast(frm_nxt - frm); + break; + default: + if ((c2 & 0xC0) != 0x80) + return static_cast(frm_nxt - frm); + } + if ((c3 & 0xC0) != 0x80) + break; + if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode) + break; + frm_nxt += 3; + } + else + break; + } + return static_cast(frm_nxt - frm); + } + + inline codecvt_base::result ucs4_to_utf16be(const uint32_t *frm, const uint32_t *frm_end, const uint32_t *&frm_nxt, uint8_t *to, uint8_t *to_end, uint8_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if (mode & generate_header) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = 0xFE; + *to_nxt++ = 0xFF; + } + for (; frm_nxt < frm_end; ++frm_nxt) + { + uint32_t wc = *frm_nxt; + if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode) + return codecvt_base::error; + if (wc < 0x010000) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = static_cast(wc >> 8); + *to_nxt++ = static_cast(wc); + } + else + { + if (to_end - to_nxt < 4) + return codecvt_base::partial; + uint16_t t = static_cast(0xD800 | ((((wc & 0x1F0000) >> 16) - 1) << 6) | ((wc & 0x00FC00) >> 10)); + *to_nxt++ = static_cast(t >> 8); + *to_nxt++ = static_cast(t); + t = static_cast(0xDC00 | (wc & 0x03FF)); + *to_nxt++ = static_cast(t >> 8); + *to_nxt++ = static_cast(t); + } + } + return codecvt_base::ok; + } + + inline codecvt_base::result utf16be_to_ucs4(const uint8_t *frm, const uint8_t *frm_end, const uint8_t *&frm_nxt, uint32_t *to, uint32_t *to_end, uint32_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if ((mode & consume_header) && frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF) + frm_nxt += 2; + for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt) + { + uint16_t c1 = static_cast((frm_nxt[0] << 8) | frm_nxt[1]); + if ((c1 & 0xFC00) == 0xDC00) + return codecvt_base::error; + if ((c1 & 0xFC00) != 0xD800) + { + if (c1 > Maxcode) + return codecvt_base::error; + *to_nxt = static_cast(c1); + frm_nxt += 2; + } + else + { + if (frm_end - frm_nxt < 4) + return codecvt_base::partial; + uint16_t c2 = static_cast((frm_nxt[2] << 8) | frm_nxt[3]); + if ((c2 & 0xFC00) != 0xDC00) + return codecvt_base::error; + uint32_t t = static_cast(((((c1 & 0x03C0) >> 6) + 1) << 16) | ((c1 & 0x003F) << 10) | (c2 & 0x03FF)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 4; + } + } + return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok; + } + + inline int utf16be_to_ucs4_length(const uint8_t *frm, const uint8_t *frm_end, size_t mx, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + auto frm_nxt = frm; + if ((mode & consume_header) && frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF) + frm_nxt += 2; + for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t) + { + uint16_t c1 = static_cast((frm_nxt[0] << 8) | frm_nxt[1]); + if ((c1 & 0xFC00) == 0xDC00) + break; + if ((c1 & 0xFC00) != 0xD800) + { + if (c1 > Maxcode) + break; + frm_nxt += 2; + } + else + { + if (frm_end - frm_nxt < 4) + break; + uint16_t c2 = static_cast((frm_nxt[2] << 8) | frm_nxt[3]); + if ((c2 & 0xFC00) != 0xDC00) + break; + uint32_t t = static_cast(((((c1 & 0x03C0) >> 6) + 1) << 16) | ((c1 & 0x003F) << 10) | (c2 & 0x03FF)); + if (t > Maxcode) + break; + frm_nxt += 4; + } + } + return static_cast(frm_nxt - frm); + } + + inline codecvt_base::result ucs4_to_utf16le(const uint32_t *frm, const uint32_t *frm_end, const uint32_t *&frm_nxt, uint8_t *to, uint8_t *to_end, uint8_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if (mode & generate_header) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = 0xFF; + *to_nxt++ = 0xFE; + } + for (; frm_nxt < frm_end; ++frm_nxt) + { + uint32_t wc = *frm_nxt; + if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode) + return codecvt_base::error; + if (wc < 0x010000) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = static_cast(wc); + *to_nxt++ = static_cast(wc >> 8); + } + else + { + if (to_end - to_nxt < 4) + return codecvt_base::partial; + uint16_t t = static_cast(0xD800 | ((((wc & 0x1F0000) >> 16) - 1) << 6) | ((wc & 0x00FC00) >> 10)); + *to_nxt++ = static_cast(t); + *to_nxt++ = static_cast(t >> 8); + t = static_cast(0xDC00 | (wc & 0x03FF)); + *to_nxt++ = static_cast(t); + *to_nxt++ = static_cast(t >> 8); + } + } + return codecvt_base::ok; + } + + inline codecvt_base::result utf16le_to_ucs4(const uint8_t *frm, const uint8_t *frm_end, const uint8_t *&frm_nxt, uint32_t *to, uint32_t *to_end, uint32_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if ((mode & consume_header) && frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE) + frm_nxt += 2; + for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt) + { + uint16_t c1 = static_cast((frm_nxt[1] << 8) | frm_nxt[0]); + if ((c1 & 0xFC00) == 0xDC00) + return codecvt_base::error; + if ((c1 & 0xFC00) != 0xD800) + { + if (c1 > Maxcode) + return codecvt_base::error; + *to_nxt = static_cast(c1); + frm_nxt += 2; + } + else + { + if (frm_end - frm_nxt < 4) + return codecvt_base::partial; + uint16_t c2 = static_cast((frm_nxt[3] << 8) | frm_nxt[2]); + if ((c2 & 0xFC00) != 0xDC00) + return codecvt_base::error; + uint32_t t = static_cast(((((c1 & 0x03C0) >> 6) + 1) << 16) | ((c1 & 0x003F) << 10) | (c2 & 0x03FF)); + if (t > Maxcode) + return codecvt_base::error; + *to_nxt = t; + frm_nxt += 4; + } + } + return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok; + } + + inline int utf16le_to_ucs4_length(const uint8_t *frm, const uint8_t *frm_end, size_t mx, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + auto frm_nxt = frm; + if ((mode & consume_header) && frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE) + frm_nxt += 2; + for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t) + { + uint16_t c1 = static_cast((frm_nxt[1] << 8) | frm_nxt[0]); + if ((c1 & 0xFC00) == 0xDC00) + break; + if ((c1 & 0xFC00) != 0xD800) + { + if (c1 > Maxcode) + break; + frm_nxt += 2; + } + else + { + if (frm_end - frm_nxt < 4) + break; + uint16_t c2 = static_cast((frm_nxt[3] << 8) | frm_nxt[2]); + if ((c2 & 0xFC00) != 0xDC00) + break; + uint32_t t = static_cast(((((c1 & 0x03C0) >> 6) + 1) << 16) | ((c1 & 0x003F) << 10) | (c2 & 0x03FF)); + if (t > Maxcode) + break; + frm_nxt += 4; + } + } + return static_cast(frm_nxt - frm); + } + + inline codecvt_base::result ucs2_to_utf16be(const uint16_t *frm, const uint16_t *frm_end, const uint16_t *&frm_nxt, uint8_t *to, uint8_t *to_end, uint8_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if (mode & generate_header) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = 0xFE; + *to_nxt++ = 0xFF; + } + for (; frm_nxt < frm_end; ++frm_nxt) + { + uint16_t wc = *frm_nxt; + if ((wc & 0xF800) == 0xD800 || wc > Maxcode) + return codecvt_base::error; + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = static_cast(wc >> 8); + *to_nxt++ = static_cast(wc); + } + return codecvt_base::ok; + } + + inline codecvt_base::result utf16be_to_ucs2(const uint8_t *frm, const uint8_t *frm_end, const uint8_t *&frm_nxt, uint16_t *to, uint16_t *to_end, uint16_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if ((mode & consume_header) && frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF) + frm_nxt += 2; + for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt) + { + uint16_t c1 = static_cast((frm_nxt[0] << 8) | frm_nxt[1]); + if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode) + return codecvt_base::error; + *to_nxt = c1; + frm_nxt += 2; + } + return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok; + } + + inline int utf16be_to_ucs2_length(const uint8_t *frm, const uint8_t *frm_end, size_t mx, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + auto frm_nxt = frm; + if ((mode & consume_header) && frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF) + frm_nxt += 2; + for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t) + { + uint16_t c1 = static_cast((frm_nxt[0] << 8) | frm_nxt[1]); + if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode) + break; + frm_nxt += 2; + } + return static_cast(frm_nxt - frm); + } + + inline codecvt_base::result ucs2_to_utf16le(const uint16_t *frm, const uint16_t *frm_end, const uint16_t *&frm_nxt, uint8_t *to, uint8_t *to_end, uint8_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if (mode & generate_header) + { + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = 0xFF; + *to_nxt++ = 0xFE; + } + for (; frm_nxt < frm_end; ++frm_nxt) + { + uint16_t wc = *frm_nxt; + if ((wc & 0xF800) == 0xD800 || wc > Maxcode) + return codecvt_base::error; + if (to_end - to_nxt < 2) + return codecvt_base::partial; + *to_nxt++ = static_cast(wc); + *to_nxt++ = static_cast(wc >> 8); + } + return codecvt_base::ok; + } + + inline codecvt_base::result utf16le_to_ucs2(const uint8_t *frm, const uint8_t *frm_end, const uint8_t *&frm_nxt, uint16_t *to, uint16_t *to_end, uint16_t *&to_nxt, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + frm_nxt = frm; + to_nxt = to; + if ((mode & consume_header) && frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE) + frm_nxt += 2; + for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt) + { + uint16_t c1 = static_cast((frm_nxt[1] << 8) | frm_nxt[0]); + if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode) + return codecvt_base::error; + *to_nxt = c1; + frm_nxt += 2; + } + return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok; + } + + inline int utf16le_to_ucs2_length(const uint8_t *frm, const uint8_t *frm_end, size_t mx, unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = static_cast(0)) + { + auto frm_nxt = frm; + if ((mode & consume_header) && frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE) + frm_nxt += 2; + for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t) + { + uint16_t c1 = static_cast((frm_nxt[1] << 8) | frm_nxt[0]); + if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode) + break; + frm_nxt += 2; + } + return static_cast(frm_nxt - frm); + } +} + +template<> class codecvt : public locale::facet, public codecvt_base +{ +public: + typedef char16_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit codecvt(size_t __refs = 0) : locale::facet(__refs) { } + + result out(state_type &__st, const intern_type *__frm, const intern_type *__frm_end, const intern_type *&__frm_nxt, extern_type *__to, extern_type *__to_end, extern_type *&__to_nxt) const + { + return this->do_out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + result unshift(state_type &__st, extern_type *__to, extern_type *__to_end, extern_type *&__to_nxt) const + { + return this->do_unshift(__st, __to, __to_end, __to_nxt); + } + + result in(state_type &__st, const extern_type *__frm, const extern_type *__frm_end, const extern_type *&__frm_nxt, intern_type *__to, intern_type *__to_end, intern_type *&__to_nxt) const + { + return this->do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + int encoding() const noexcept + { + return this->do_encoding(); + } + + bool always_noconv() const noexcept + { + return this->do_always_noconv(); + } + + int length(state_type &__st, const extern_type *__frm, const extern_type *__end, size_t __mx) const + { + return this->do_length(__st, __frm, __end, __mx); + } + + int max_length() const noexcept + { + return this->do_max_length(); + } + + static locale::id id; + +protected: + explicit codecvt(const char *, size_t __refs = 0) : locale::facet(__refs) { } + + ~codecvt() { } + + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf8_to_utf16_length(_frm, _frm_end, mx); + } + virtual int do_max_length() const noexcept { return 4; } +}; + +template<> class codecvt : public locale::facet, public codecvt_base +{ +public: + typedef char32_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit codecvt(size_t __refs = 0) : locale::facet(__refs) { } + + result out(state_type &__st, const intern_type *__frm, const intern_type *__frm_end, const intern_type *&__frm_nxt, extern_type *__to, extern_type *__to_end, extern_type *&__to_nxt) const + { + return this->do_out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + result unshift(state_type &__st, extern_type *__to, extern_type *__to_end, extern_type *&__to_nxt) const + { + return this->do_unshift(__st, __to, __to_end, __to_nxt); + } + + result in(state_type &__st, const extern_type *__frm, const extern_type *__frm_end, const extern_type *&__frm_nxt, intern_type *__to, intern_type *__to_end, intern_type *&__to_nxt) const + { + return this->do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + int encoding() const noexcept + { + return this->do_encoding(); + } + + bool always_noconv() const noexcept + { + return this->do_always_noconv(); + } + + int length(state_type &__st, const extern_type *__frm, const extern_type *__end, size_t __mx) const + { + return this->do_length(__st, __frm, __end, __mx); + } + + int max_length() const noexcept + { + return this->do_max_length(); + } + + static locale::id id; + +protected: + explicit codecvt(const char *, size_t __refs = 0) : locale::facet(__refs) { } + + ~codecvt() { } + + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf8_to_ucs4_length(_frm, _frm_end, mx); + } + virtual int do_max_length() const noexcept { return 4; } +}; + +template class __codecvt_utf8; + +template<> class __codecvt_utf8 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef wchar_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf8(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { +#ifdef _WIN32 + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); +#else + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); +#endif + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters:: +#ifdef _WIN32 + ucs2_to_utf8 +#else + ucs4_to_utf8 +#endif + (_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; +#ifdef _WIN32 + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); +#else + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); +#endif + auto _to_nxt = _to; + auto r = UnicodeConverters:: +#ifdef _WIN32 + utf8_to_ucs2 +#else + utf8_to_ucs4 +#endif + (_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf8_to_ucs4_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 7; + return 4; + } +}; + +template<> class __codecvt_utf8 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef char16_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf8(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf8_to_ucs2_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 6; + return 3; + } +}; + +template<> class __codecvt_utf8 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef char32_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf8(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf8_to_ucs4_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 7; + return 4; + } +}; + +template(0)> class codecvt_utf8 : public __codecvt_utf8<_Elem> +{ +public: + explicit codecvt_utf8(size_t __refs = 0) : __codecvt_utf8<_Elem>(__refs, _Maxcode, _Mode) { } + + ~codecvt_utf8() { } +}; + +template class __codecvt_utf16; + +template<> class __codecvt_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef wchar_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf16be_to_ucs4_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 6; + return 4; + } +}; + +template<> class __codecvt_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef wchar_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf16le_to_ucs4_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 6; + return 4; + } +}; + +template<> class __codecvt_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef char16_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf16be_to_ucs2_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 4; + return 2; + } +}; + +template<> class __codecvt_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef char16_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf16le_to_ucs2_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 4; + return 2; + } +}; + +template<> class __codecvt_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef char32_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf16be_to_ucs4_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 6; + return 4; + } +}; + +template<> class __codecvt_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef char32_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf16le_to_ucs4_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 6; + return 4; + } +}; + +template(0)> class codecvt_utf16 : public __codecvt_utf16<_Elem, _Mode & little_endian> +{ +public: + explicit codecvt_utf16(size_t __refs = 0) : __codecvt_utf16<_Elem, _Mode & little_endian>(__refs, _Maxcode, _Mode) { } + + ~codecvt_utf16() { } +}; + +template class __codecvt_utf8_utf16; + +template<> class __codecvt_utf8_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef wchar_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf8_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf8_to_utf16_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 7; + return 4; + } +}; + +template<> class __codecvt_utf8_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef char32_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf8_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf8_to_utf16_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 7; + return 4; + } +}; + +template<> class __codecvt_utf8_utf16 : public codecvt +{ + unsigned long _Maxcode_; + codecvt_mode _Mode_; +public: + typedef char16_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit __codecvt_utf8_utf16(size_t __refs, unsigned long _Maxcode, codecvt_mode _Mode) : codecvt(__refs), _Maxcode_(_Maxcode), _Mode_(_Mode) { } +protected: + virtual result do_out(state_type &, const intern_type *frm, const intern_type *frm_end, const intern_type *&frm_nxt, extern_type *to, extern_type *to_end, extern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_in(state_type &, const extern_type *frm, const extern_type *frm_end, const extern_type *&frm_nxt, intern_type *to, intern_type *to_end, intern_type *&to_nxt) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + auto _frm_nxt = _frm; + auto _to = reinterpret_cast(to); + auto _to_end = reinterpret_cast(to_end); + auto _to_nxt = _to; + auto r = UnicodeConverters::utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, this->_Maxcode_, this->_Mode_); + frm_nxt = frm + (_frm_nxt - _frm); + to_nxt = to + (_to_nxt - _to); + return r; + } + virtual result do_unshift(state_type &, extern_type *to, extern_type *, extern_type *&to_nxt) const + { + to_nxt = to; + return noconv; + } + virtual int do_encoding() const noexcept { return 0; } + virtual bool do_always_noconv() const noexcept { return false; } + virtual int do_length(state_type &, const extern_type *frm, const extern_type *frm_end, size_t mx) const + { + auto _frm = reinterpret_cast(frm); + auto _frm_end = reinterpret_cast(frm_end); + return UnicodeConverters::utf8_to_utf16_length(_frm, _frm_end, mx, this->_Maxcode_, this->_Mode_); + } + virtual int do_max_length() const noexcept + { + if (this->_Mode_ & consume_header) + return 7; + return 4; + } +}; + +template(0)> class codecvt_utf8_utf16 : public __codecvt_utf8_utf16<_Elem> +{ +public: + explicit codecvt_utf8_utf16(size_t __refs = 0) : __codecvt_utf8_utf16<_Elem>(__refs, _Maxcode, _Mode) { } + + ~codecvt_utf8_utf16() {} +}; + +} +#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/common.h b/Frameworks/SSEQPlayer/SSEQPlayer/common.h index 2c3437f76..747000615 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/common.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/common.h @@ -1,15 +1,14 @@ /* * SSEQ Player - Common functions * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-3 + * Last modification on 2014-10-18 * * Some code from FeOS Sound System * By fincs * https://github.com/fincs/FSS */ -#ifndef SSEQPLAYER_COMMON_H -#define SSEQPLAYER_COMMON_H +#pragma once #include #include @@ -143,11 +142,15 @@ inline int Cnv_Attack(int attk) 0x5C, 0x64, 0x6D, 0x74, 0x7B, 0x7F, 0x84, 0x89, 0x8F }; + if (attk & 0x80) // Supposedly invalid value... + attk = 0; // Use apparently correct default return attk >= 0x6D ? lut[0x7F - attk] : 0xFF - attk; } inline int Cnv_Fall(int fall) { + if (fall & 0x80) // Supposedly invalid value... + fall = 0; // Use apparently correct default if (fall == 0x7F) return 0xFFFF; else if (fall == 0x7E) @@ -158,6 +161,33 @@ inline int Cnv_Fall(int fall) return (0x1E00 / (0x7E - fall)) & 0xFFFF; } +inline int Cnv_Scale(int scale) +{ + static const int16_t lut[] = + { + -32768, -421, -361, -325, -300, -281, -265, -252, + -240, -230, -221, -212, -205, -198, -192, -186, + -180, -175, -170, -165, -161, -156, -152, -148, + -145, -141, -138, -134, -131, -128, -125, -122, + -120, -117, -114, -112, -110, -107, -105, -103, + -100, -98, -96, -94, -92, -90, -88, -86, + -85, -83, -81, -79, -78, -76, -74, -73, + -71, -70, -68, -67, -65, -64, -62, -61, + -60, -58, -57, -56, -54, -53, -52, -51, + -49, -48, -47, -46, -45, -43, -42, -41, + -40, -39, -38, -37, -36, -35, -34, -33, + -32, -31, -30, -29, -28, -27, -26, -25, + -24, -23, -23, -22, -21, -20, -19, -18, + -17, -17, -16, -15, -14, -13, -12, -12, + -11, -10, -9, -9, -8, -7, -6, -6, + -5, -4, -3, -3, -2, -1, -1, 0 + }; + + if (scale & 0x80) // Supposedly invalid value... + scale = 0x7F; // Use apparently correct default + return lut[scale]; +} + inline int Cnv_Sust(int sust) { static const int16_t lut[] = @@ -180,6 +210,8 @@ inline int Cnv_Sust(int sust) -10, -8, -7, -6, -4, -3, -1, 0 }; + if (sust & 0x80) // Supposedly invalid value... + sust = 0x7F; // Use apparently correct default return lut[sust]; } @@ -238,4 +270,11 @@ inline int readvl(const uint8_t **ppData) return x; } -#endif +// Clamp a value between a minimum and maximum value +template inline void clamp(T1 &valueToClamp, const T2 &minValue, const T2 &maxValue) +{ + if (valueToClamp < minValue) + valueToClamp = minValue; + else if (valueToClamp > maxValue) + valueToClamp = maxValue; +} diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/consts.h b/Frameworks/SSEQPlayer/SSEQPlayer/consts.h index 364b51856..be1cc9a3d 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/consts.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/consts.h @@ -1,7 +1,7 @@ /* * SSEQ Player - Constants/Macros * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-04-12 + * Last modification on 2014-09-08 * * Adapted from source code of FeOS Sound System * By fincs @@ -11,8 +11,7 @@ * http://devkitpro.org/ */ -#ifndef SSEQPLAYER_CONSTS_H -#define SSEQPLAYER_CONSTS_H +#pragma once #include @@ -55,11 +54,7 @@ enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, - INTERPOLATION_COSINE, - INTERPOLATION_4POINTBSPLINE, - INTERPOLATION_6POINTOSCULATING, - INTERPOLATION_6POINTBSPLINE, - INTERPOLATION_LANCZOS + INTERPOLATION_4POINTLEGRANGE, + INTERPOLATION_6POINTLEGRANGE, + INTERPOLATION_SINC }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/convert.h b/Frameworks/SSEQPlayer/SSEQPlayer/convert.h index 0c18d1994..db5ade16b 100644 --- a/Frameworks/SSEQPlayer/SSEQPlayer/convert.h +++ b/Frameworks/SSEQPlayer/SSEQPlayer/convert.h @@ -1,20 +1,24 @@ /* * Common conversion functions * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] - * Last modification on 2013-03-30 + * Last modification on 2014-09-24 */ -#ifndef _CONVERT_H_ -#define _CONVERT_H_ +#pragma once #include #include #include #include #include +#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION) +# include "wstring_convert.h" +# include "codecvt.h" +#else +# include +#endif #include #include -#include "BigSString.h" /* * The following exception class and the *stringify and convert* functions are @@ -130,7 +134,7 @@ public: static unsigned long StringToMS(const std::wstring &time) { - return ConvertFuncs::StringToMS(String(time).GetAnsi()); + return ConvertFuncs::StringToMS(ConvertFuncs::WStringToString(time)); } static std::string MSToString(unsigned long time) @@ -149,8 +153,18 @@ public: static std::wstring MSToWString(unsigned long time) { - return String(ConvertFuncs::MSToString(time)).GetWStr(); + return ConvertFuncs::StringToWString(ConvertFuncs::MSToString(time)); + } + + static std::wstring StringToWString(const std::string &str) + { + static std::wstring_convert> conv; + return conv.from_bytes(str); + } + + static std::string WStringToString(const std::wstring &wstr) + { + static std::wstring_convert> conv; + return conv.to_bytes(wstr); } }; - -#endif diff --git a/Frameworks/SSEQPlayer/SSEQPlayer/wstring_convert.h b/Frameworks/SSEQPlayer/SSEQPlayer/wstring_convert.h new file mode 100644 index 000000000..5ab6a4bb5 --- /dev/null +++ b/Frameworks/SSEQPlayer/SSEQPlayer/wstring_convert.h @@ -0,0 +1,183 @@ +// This comes from llvm's libcxx project. I've copied the code from there (with very minor modifications) for use with GCC and Clang when libcxx isn't being used. + +#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION) +#pragma once + +#include +#include +#include + +namespace std +{ + +template, class _Byte_alloc = allocator> class wstring_convert +{ +public: + typedef basic_string, _Byte_alloc> byte_string; + typedef basic_string<_Elem, char_traits<_Elem>, _Wide_alloc> wide_string; + typedef typename _Codecvt::state_type state_type; + typedef typename wide_string::traits_type::int_type int_type; + +private: + byte_string __byte_err_string_; + wide_string __wide_err_string_; + _Codecvt *__cvtptr_; + state_type __cvtstate_; + size_t __cvtcount_; + + wstring_convert(const wstring_convert &__wc); + wstring_convert& operator=(const wstring_convert &__wc); +public: + wstring_convert(_Codecvt *__pcvt = new _Codecvt) : __cvtptr_(__pcvt), __cvtstate_(), __cvtcount_(0) { } + wstring_convert(_Codecvt *__pcvt, state_type __state) : __cvtptr_(__pcvt), __cvtstate_(__state), __cvtcount_(0) { } + wstring_convert(const byte_string &__byte_err, const wide_string &__wide_err = wide_string()) : __byte_err_string_(__byte_err), __wide_err_string_(__wide_err), __cvtptr_(new _Codecvt), __cvtstate_(), __cvtcount_(0) { } + wstring_convert(wstring_convert &&__wc) : __byte_err_string_(move(__wc.__byte_err_string_)), __wide_err_string_(move(__wc.__wide_err_string_)), __cvtptr_(__wc.__cvtptr_), __cvtstate_(__wc.__cvtstate_), __cvtcount_(__wc.__cvtstate_) + { + __wc.__cvtptr_ = nullptr; + } + ~wstring_convert() { delete this->__cvtptr_; } + + wide_string from_bytes(char __byte) { return from_bytes(&__byte, &__byte + 1); } + wide_string from_bytes(const char *__ptr) { return from_bytes(__ptr, __ptr + char_traits::length(__ptr)); } + wide_string from_bytes(const byte_string &__str) { return from_bytes(__str.data(), __str.data() + __str.size()); } + wide_string from_bytes(const char *__frm, const char *__frm_end) + { + this->__cvtcount_ = 0; + if (this->__cvtptr_) + { + wide_string __ws(2 * (__frm_end - __frm), _Elem()); + if (__frm != __frm_end) + __ws.resize(__ws.capacity()); + auto __r = codecvt_base::ok; + auto __st = this->__cvtstate_; + if (__frm != __frm_end) + { + auto __to = &__ws[0]; + auto __to_end = __to + __ws.size(); + const char *__frm_nxt; + do + { + _Elem *__to_nxt; + __r = this->__cvtptr_->in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + this->__cvtcount_ += __frm_nxt - __frm; + if (__frm_nxt == __frm) + __r = codecvt_base::error; + else if (__r == codecvt_base::noconv) + { + __ws.resize(__to - &__ws[0]); + // This only gets executed if _Elem is char + __ws.append(reinterpret_cast(__frm), reinterpret_cast(__frm_end)); + __frm = __frm_nxt; + __r = codecvt_base::ok; + } + else if (__r == codecvt_base::ok) + { + __ws.resize(__to_nxt - &__ws[0]); + __frm = __frm_nxt; + } + else if (__r == codecvt_base::partial) + { + ptrdiff_t __s = __to_nxt - &__ws[0]; + __ws.resize(2 * __s); + __to = &__ws[0] + __s; + __to_end = &__ws[0] + __ws.size(); + __frm = __frm_nxt; + } + } while (__r == codecvt_base::partial && __frm_nxt < __frm_end); + } + if (__r == codecvt_base::ok) + return __ws; + } + if (this->__wide_err_string_.empty()) + throw range_error("wstring_convert: from_bytes error"); + return this->__wide_err_string_; + } + + byte_string to_bytes(_Elem __wchar) { return to_bytes(&__wchar, &__wchar + 1); } + byte_string to_bytes(const _Elem *__wptr) { return to_bytes(__wptr, __wptr + char_traits<_Elem>::length(__wptr)); } + byte_string to_bytes(const wide_string &__wstr) { return to_bytes(__wstr.data(), __wstr.data() + __wstr.size()); } + byte_string to_bytes(const _Elem *__frm, const _Elem *__frm_end) + { + this->__cvtcount_ = 0; + if (this->__cvtptr_) + { + byte_string __bs(2 * (__frm_end - __frm), char()); + if (__frm != __frm_end) + __bs.resize(__bs.capacity()); + auto __r = codecvt_base::ok; + auto __st = this->__cvtstate_; + if (__frm != __frm_end) + { + auto __to = &__bs[0]; + auto __to_end = __to + __bs.size(); + const _Elem *__frm_nxt; + do + { + char *__to_nxt; + __r = this->__cvtptr_->out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + this->__cvtcount_ += __frm_nxt - __frm; + if (__frm_nxt == __frm) + __r = codecvt_base::error; + else if (__r == codecvt_base::noconv) + { + __bs.resize(__to - &__bs[0]); + // This only gets executed if _Elem is char + __bs.append(reinterpret_cast(__frm), reinterpret_cast(__frm_end)); + __frm = __frm_nxt; + __r = codecvt_base::ok; + } + else if (__r == codecvt_base::ok) + { + __bs.resize(__to_nxt - &__bs[0]); + __frm = __frm_nxt; + } + else if (__r == codecvt_base::partial) + { + ptrdiff_t __s = __to_nxt - &__bs[0]; + __bs.resize(2 * __s); + __to = &__bs[0] + __s; + __to_end = &__bs[0] + __bs.size(); + __frm = __frm_nxt; + } + } while (__r == codecvt_base::partial && __frm_nxt < __frm_end); + } + if (__r == codecvt_base::ok) + { + auto __s = __bs.size(); + __bs.resize(__bs.capacity()); + auto __to = &__bs[0] + __s; + auto __to_end = __to + __bs.size(); + do + { + char *__to_nxt; + __r = this->__cvtptr_->unshift(__st, __to, __to_end, __to_nxt); + if (__r == codecvt_base::noconv) + { + __bs.resize(__to - &__bs[0]); + __r = codecvt_base::ok; + } + else if (__r == codecvt_base::ok) + __bs.resize(__to_nxt - &__bs[0]); + else if (__r == codecvt_base::partial) + { + ptrdiff_t __sp = __to_nxt - &__bs[0]; + __bs.resize(2 * __sp); + __to = &__bs[0] + __sp; + __to_end = &__bs[0] + __bs.size(); + } + } while (__r == codecvt_base::partial); + if (__r == codecvt_base::ok) + return __bs; + } + } + if (this->__byte_err_string_.empty()) + throw range_error("wstring_convert: to_bytes error"); + return this->__byte_err_string_; + } + + size_t converted() const noexcept { return this->__cvtcount_; } + state_type state() const { return this->__cvtstate_; } +}; + +} +#endif