mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-10 16:43:33 +02:00
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.
This commit is contained in:
@@ -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.
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user