From 0413de548bb7e83fb0be321739acf7998a5d42ce Mon Sep 17 00:00:00 2001 From: "RichardAsh1981@gmail.com" Date: Sun, 3 Nov 2013 15:49:12 +0000 Subject: [PATCH] fix the loading of projects with more than 2^31 samples in a waveclip, and possibly some other similar constraints on waveclips. This fixes a long-standing problem with long recordings being saved but unable to re-open them. Tested by Gale and Steve. --- src/Sequence.cpp | 38 ++++++++++++++++++++++++------------ src/xml/XMLTagHandler.cpp | 41 +++++++++++++++++++++++++++++++++++++++ src/xml/XMLTagHandler.h | 23 +++++++++++++++++++--- 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/Sequence.cpp b/src/Sequence.cpp index d576f8c45..32ed975e0 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -823,8 +823,9 @@ sampleCount Sequence::GetBestBlockSize(sampleCount start) const bool Sequence::HandleXMLTag(const wxChar *tag, const wxChar **attrs) { - long nValue; + sampleCount nValue; + /* handle waveblock tag and it's attributes */ if (!wxStrcmp(tag, wxT("waveblock"))) { SeqBlock *wb = new SeqBlock(); wb->f = NULL; @@ -839,9 +840,11 @@ bool Sequence::HandleXMLTag(const wxChar *tag, const wxChar **attrs) if (!value) break; - // All these attributes have non-negative integer values, so just test & convert here. + // Both these attributes have non-negative integer counts of samples, so + // we can test & convert here, making sure that values > 2^31 are OK + // because long clips will need them. const wxString strValue = value; - if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) || (nValue < 0)) + if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue < 0)) { delete (wb); mErrorOpening = true; @@ -880,6 +883,7 @@ bool Sequence::HandleXMLTag(const wxChar *tag, const wxChar **attrs) return true; } + /* handle sequence tag and it's attributes */ if (!wxStrcmp(tag, wxT("sequence"))) { while(*attrs) { const wxChar *attr = *attrs++; @@ -888,16 +892,16 @@ bool Sequence::HandleXMLTag(const wxChar *tag, const wxChar **attrs) if (!value) break; - // All these attributes have non-negative integer values, so just test & convert here. - const wxString strValue = value; - if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) || (nValue < 0)) - { - mErrorOpening = true; - return false; - } + const wxString strValue = value; // promote string, we need this for all if (!wxStrcmp(attr, wxT("maxsamples"))) { + // This attribute is a sample count, so can be 64bit + if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue < 0)) + { + mErrorOpening = true; + return false; + } // Dominic, 12/10/2006: // Let's check that maxsamples is >= 1024 and <= 64 * 1024 * 1024 // - that's a pretty wide range of reasonable values. @@ -911,15 +915,25 @@ bool Sequence::HandleXMLTag(const wxChar *tag, const wxChar **attrs) } else if (!wxStrcmp(attr, wxT("sampleformat"))) { - if (!XMLValueChecker::IsValidSampleFormat(nValue)) + // This attribute is a sample format, normal int + long fValue; + if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&fValue) || (fValue < 0) || !XMLValueChecker::IsValidSampleFormat(fValue)) { mErrorOpening = true; return false; } - mSampleFormat = (sampleFormat)nValue; + mSampleFormat = (sampleFormat)fValue; } else if (!wxStrcmp(attr, wxT("numsamples"))) + { + // This attribute is a sample count, so can be 64bit + if (!XMLValueChecker::IsGoodInt64(strValue) || !strValue.ToLongLong(&nValue) || (nValue < 0)) + { + mErrorOpening = true; + return false; + } mNumSamples = nValue; + } } // while //// Both mMaxSamples and mSampleFormat should have been set. diff --git a/src/xml/XMLTagHandler.cpp b/src/xml/XMLTagHandler.cpp index 421e98b06..46d3b9cc6 100644 --- a/src/xml/XMLTagHandler.cpp +++ b/src/xml/XMLTagHandler.cpp @@ -145,6 +145,47 @@ bool XMLValueChecker::IsGoodInt(const wxString strInt) return true; } +bool XMLValueChecker::IsGoodInt64(const wxString strInt) +{ + if (!IsGoodString(strInt)) + return false; + + // Check that the value won't overflow. + // Signed 64-bit: -18446744073709551616 to +18446744073709551615, i.e., -2^64 to 2^64-1 + // We're strict about disallowing spaces and commas, and requiring minus sign to be first char for negative. + const size_t lenMAXABS = strlen("18446744073709551615"); + const size_t lenStrInt = strInt.Length(); + + if (lenStrInt > (lenMAXABS + 1)) + return false; + else if ((lenStrInt == (lenMAXABS + 1)) && (strInt[0] == '-')) + { + const int digitsMAXABS[] = {1, 8, 4, 4, 6, 7, 4, 4, 0, 7, 3, 7, 0, 9, 5, 5, 1, 6, 1, 7}; + unsigned int i; + for (i = 0; i < lenMAXABS; i++) + if (strInt[i+1] < '0' || strInt[i+1] > '9') + return false; // not a digit + + for (i = 0; i < lenMAXABS; i++) + if (strInt[i+1] - '0' < digitsMAXABS[i]) + return true; // number is small enough + return false; + } + else if (lenStrInt == lenMAXABS) + { + const int digitsMAXABS[] = {1, 8, 4, 4, 6, 7, 4, 4, 0, 7, 3, 7, 0, 9, 5, 5, 1, 6, 1, 6}; + unsigned int i; + for (i = 0; i < lenMAXABS; i++) + if (strInt[i] < '0' || strInt[i+1] > '9') + return false; // not a digit + for (i = 0; i < lenMAXABS; i++) + if (strInt[i] - '0' < digitsMAXABS[i]) + return true; // number is small enough + return false; + } + return true; +} + bool XMLValueChecker::IsValidChannel(const int nValue) { return (nValue >= Track::LeftChannel) && (nValue <= Track::MonoChannel); diff --git a/src/xml/XMLTagHandler.h b/src/xml/XMLTagHandler.h index 7d40e4043..b7f4f2e52 100644 --- a/src/xml/XMLTagHandler.h +++ b/src/xml/XMLTagHandler.h @@ -37,10 +37,27 @@ public: static bool IsGoodPathName(const wxString strPathName); static bool IsGoodPathString(wxString str); - // Note that because wxString::ToLong does additional testing, IsGoodInt doesn't duplicate - // that testing, so use wxString::ToLong after IsGoodInt, not just atoi. + /** @brief Check that the supplied string can be converted to a long (32bit) + * integer. + * + * Note that because wxString::ToLong does additional testing, IsGoodInt doesn't + * duplicate that testing, so use wxString::ToLong after IsGoodInt, not just + * atoi. + * @param strInt The string to test + * @return true if the string is convertable, false if not + */ static bool IsGoodInt(const wxString strInt); - + /** @brief Check that the supplied string can be converted to a 64bit + * integer. + * + * Note that because wxString::ToLongLong does additional testing, IsGoodInt64 + * doesn't duplicate that testing, so use wxString::ToLongLong after IsGoodInt64 + * not just atoll. + * @param strInt The string to test + * @return true if the string is convertable, false if not + */ + static bool IsGoodInt64(const wxString strInt); + static bool IsValidChannel(const int nValue); #ifdef USE_MIDI static bool IsValidVisibleChannels(const int nValue);