2011-07-22 21:17:16 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
|
|
|
|
|
|
|
#include <base/math.h>
|
|
|
|
|
|
|
|
#include <engine/storage.h>
|
|
|
|
|
|
|
|
#include "filecollection.h"
|
|
|
|
|
|
|
|
bool CFileCollection::IsFilenameValid(const char *pFilename)
|
|
|
|
{
|
2015-08-22 15:21:00 +00:00
|
|
|
if(m_aFileDesc[0] == '\0')
|
|
|
|
{
|
|
|
|
int FilenameLength = str_length(pFilename);
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_FileExtLength + TIMESTAMP_LENGTH > FilenameLength)
|
2015-08-22 15:21:00 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
pFilename += FilenameLength - m_FileExtLength - TIMESTAMP_LENGTH;
|
2015-08-22 15:21:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(str_length(pFilename) != m_FileDescLength + TIMESTAMP_LENGTH + m_FileExtLength ||
|
2015-08-22 15:21:00 +00:00
|
|
|
str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) ||
|
2020-09-26 19:41:58 +00:00
|
|
|
str_comp(pFilename + m_FileDescLength + TIMESTAMP_LENGTH, m_aFileExt))
|
2015-08-22 15:21:00 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
pFilename += m_FileDescLength;
|
|
|
|
}
|
2011-07-22 21:17:16 +00:00
|
|
|
|
2022-01-22 16:34:23 +00:00
|
|
|
return pFilename[0] == '_' &&
|
|
|
|
pFilename[1] >= '0' && pFilename[1] <= '9' &&
|
|
|
|
pFilename[2] >= '0' && pFilename[2] <= '9' &&
|
|
|
|
pFilename[3] >= '0' && pFilename[3] <= '9' &&
|
|
|
|
pFilename[4] >= '0' && pFilename[4] <= '9' &&
|
|
|
|
pFilename[5] == '-' &&
|
|
|
|
pFilename[6] >= '0' && pFilename[6] <= '9' &&
|
|
|
|
pFilename[7] >= '0' && pFilename[7] <= '9' &&
|
|
|
|
pFilename[8] == '-' &&
|
|
|
|
pFilename[9] >= '0' && pFilename[9] <= '9' &&
|
|
|
|
pFilename[10] >= '0' && pFilename[10] <= '9' &&
|
|
|
|
pFilename[11] == '_' &&
|
|
|
|
pFilename[12] >= '0' && pFilename[12] <= '9' &&
|
|
|
|
pFilename[13] >= '0' && pFilename[13] <= '9' &&
|
|
|
|
pFilename[14] == '-' &&
|
|
|
|
pFilename[15] >= '0' && pFilename[15] <= '9' &&
|
|
|
|
pFilename[16] >= '0' && pFilename[16] <= '9' &&
|
|
|
|
pFilename[17] == '-' &&
|
|
|
|
pFilename[18] >= '0' && pFilename[18] <= '9' &&
|
|
|
|
pFilename[19] >= '0' && pFilename[19] <= '9';
|
2011-07-22 21:17:16 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 05:05:49 +00:00
|
|
|
int64_t CFileCollection::ExtractTimestamp(const char *pTimestring)
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
2021-06-23 05:05:49 +00:00
|
|
|
int64_t Timestamp = pTimestring[0] - '0';
|
2020-09-26 19:41:58 +00:00
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[1] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[2] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[3] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[5] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[6] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[8] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[9] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[11] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[12] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[14] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[15] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[17] - '0';
|
|
|
|
Timestamp <<= 4;
|
|
|
|
Timestamp += pTimestring[18] - '0';
|
2011-07-22 21:17:16 +00:00
|
|
|
|
|
|
|
return Timestamp;
|
|
|
|
}
|
|
|
|
|
2021-06-23 05:05:49 +00:00
|
|
|
void CFileCollection::BuildTimestring(int64_t Timestamp, char *pTimestring)
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
|
|
|
pTimestring[19] = 0;
|
2020-09-26 19:41:58 +00:00
|
|
|
pTimestring[18] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
|
|
|
pTimestring[17] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
2011-07-22 21:17:16 +00:00
|
|
|
pTimestring[16] = '-';
|
2020-09-26 19:41:58 +00:00
|
|
|
pTimestring[15] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
|
|
|
pTimestring[14] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
2011-07-22 21:17:16 +00:00
|
|
|
pTimestring[13] = '-';
|
2020-09-26 19:41:58 +00:00
|
|
|
pTimestring[12] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
|
|
|
pTimestring[11] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
2011-07-22 21:17:16 +00:00
|
|
|
pTimestring[10] = '_';
|
2020-09-26 19:41:58 +00:00
|
|
|
pTimestring[9] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
|
|
|
pTimestring[8] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
2011-07-22 21:17:16 +00:00
|
|
|
pTimestring[7] = '-';
|
2020-09-26 19:41:58 +00:00
|
|
|
pTimestring[6] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
|
|
|
pTimestring[5] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
2011-07-22 21:17:16 +00:00
|
|
|
pTimestring[4] = '-';
|
2020-09-26 19:41:58 +00:00
|
|
|
pTimestring[3] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
|
|
|
pTimestring[2] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
|
|
|
pTimestring[1] = (Timestamp & 0xF) + '0';
|
|
|
|
Timestamp >>= 4;
|
|
|
|
pTimestring[0] = (Timestamp & 0xF) + '0';
|
2011-07-22 21:17:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries)
|
|
|
|
{
|
|
|
|
mem_zero(m_aTimestamps, sizeof(m_aTimestamps));
|
|
|
|
m_NumTimestamps = 0;
|
2015-08-22 15:21:00 +00:00
|
|
|
m_Remove = -1;
|
2019-01-11 10:39:05 +00:00
|
|
|
// MAX_ENTRIES - 1 to make sure that we can insert one entry into the sorted
|
|
|
|
// list and then remove the oldest one
|
2020-09-26 19:41:58 +00:00
|
|
|
m_MaxEntries = clamp(MaxEntries, 1, static_cast<int>(MAX_ENTRIES) - 1);
|
2022-07-09 16:14:56 +00:00
|
|
|
str_copy(m_aFileDesc, pFileDesc);
|
2011-07-22 21:17:16 +00:00
|
|
|
m_FileDescLength = str_length(m_aFileDesc);
|
2022-07-09 16:14:56 +00:00
|
|
|
str_copy(m_aFileExt, pFileExt);
|
2011-07-22 21:17:16 +00:00
|
|
|
m_FileExtLength = str_length(m_aFileExt);
|
2022-07-09 16:14:56 +00:00
|
|
|
str_copy(m_aPath, pPath);
|
2011-07-22 21:17:16 +00:00
|
|
|
m_pStorage = pStorage;
|
|
|
|
|
|
|
|
m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this);
|
|
|
|
}
|
|
|
|
|
2021-06-23 05:05:49 +00:00
|
|
|
void CFileCollection::AddEntry(int64_t Timestamp)
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
|
|
|
if(m_NumTimestamps == 0)
|
|
|
|
{
|
|
|
|
// empty list
|
|
|
|
m_aTimestamps[m_NumTimestamps++] = Timestamp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// add entry to the sorted list
|
2019-01-11 10:39:05 +00:00
|
|
|
if(Timestamp < m_aTimestamps[0])
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
|
|
|
// first entry
|
2019-01-11 10:39:05 +00:00
|
|
|
if(m_NumTimestamps <= m_MaxEntries)
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
2021-06-23 05:05:49 +00:00
|
|
|
mem_move(m_aTimestamps + 1, m_aTimestamps, m_NumTimestamps * sizeof(int64_t));
|
2011-07-22 21:17:16 +00:00
|
|
|
m_aTimestamps[0] = Timestamp;
|
|
|
|
++m_NumTimestamps;
|
|
|
|
}
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
else if(Timestamp >= m_aTimestamps[m_NumTimestamps - 1])
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
|
|
|
// last entry
|
2019-01-11 10:39:05 +00:00
|
|
|
if(m_NumTimestamps > m_MaxEntries)
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
2021-06-23 05:05:49 +00:00
|
|
|
mem_move(m_aTimestamps, m_aTimestamps + 1, (m_NumTimestamps - 1) * sizeof(int64_t));
|
2020-09-26 19:41:58 +00:00
|
|
|
m_aTimestamps[m_NumTimestamps - 1] = Timestamp;
|
2011-07-22 21:17:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
m_aTimestamps[m_NumTimestamps++] = Timestamp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// middle entry
|
2020-09-26 19:41:58 +00:00
|
|
|
int Left = 0, Right = m_NumTimestamps - 1;
|
|
|
|
while(Right - Left > 1)
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
int Mid = (Left + Right) / 2;
|
2011-07-22 21:17:16 +00:00
|
|
|
if(m_aTimestamps[Mid] > Timestamp)
|
|
|
|
Right = Mid;
|
|
|
|
else
|
|
|
|
Left = Mid;
|
|
|
|
}
|
|
|
|
|
2019-01-11 10:39:05 +00:00
|
|
|
if(m_NumTimestamps > m_MaxEntries)
|
2011-07-22 21:17:16 +00:00
|
|
|
{
|
2021-06-23 05:05:49 +00:00
|
|
|
mem_move(m_aTimestamps, m_aTimestamps + 1, (Right - 1) * sizeof(int64_t));
|
2020-09-26 19:41:58 +00:00
|
|
|
m_aTimestamps[Right - 1] = Timestamp;
|
2011-07-22 21:17:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-23 05:05:49 +00:00
|
|
|
mem_move(m_aTimestamps + Right + 1, m_aTimestamps + Right, (m_NumTimestamps - Right) * sizeof(int64_t));
|
2011-07-22 21:17:16 +00:00
|
|
|
m_aTimestamps[Right] = Timestamp;
|
|
|
|
++m_NumTimestamps;
|
|
|
|
}
|
|
|
|
}
|
2019-01-11 10:39:05 +00:00
|
|
|
|
|
|
|
// remove old file only after we inserted the new entry, otherwise we can't
|
|
|
|
// know which one is the oldest
|
|
|
|
if(m_NumTimestamps > m_MaxEntries)
|
|
|
|
{
|
|
|
|
if(m_aFileDesc[0] == '\0') // consider an empty file desc as a wild card
|
|
|
|
{
|
|
|
|
m_Remove = m_aTimestamps[0];
|
|
|
|
m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, RemoveCallback, this);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-06-24 14:07:03 +00:00
|
|
|
char aBuf[IO_MAX_PATH_LENGTH];
|
2019-01-11 10:39:05 +00:00
|
|
|
char aTimestring[TIMESTAMP_LENGTH];
|
|
|
|
BuildTimestring(m_aTimestamps[0], aTimestring);
|
|
|
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt);
|
|
|
|
m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
|
|
|
|
}
|
|
|
|
}
|
2011-07-22 21:17:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-23 05:05:49 +00:00
|
|
|
int64_t CFileCollection::GetTimestamp(const char *pFilename)
|
2015-08-22 15:21:00 +00:00
|
|
|
{
|
|
|
|
if(m_aFileDesc[0] == '\0')
|
|
|
|
{
|
|
|
|
int FilenameLength = str_length(pFilename);
|
2020-09-26 19:41:58 +00:00
|
|
|
return ExtractTimestamp(pFilename + FilenameLength - m_FileExtLength - TIMESTAMP_LENGTH + 1);
|
2015-08-22 15:21:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
return ExtractTimestamp(pFilename + m_FileDescLength + 1);
|
2015-08-22 15:21:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-22 21:17:16 +00:00
|
|
|
int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser)
|
|
|
|
{
|
|
|
|
CFileCollection *pThis = static_cast<CFileCollection *>(pUser);
|
|
|
|
|
|
|
|
// check for valid file name format
|
|
|
|
if(IsDir || !pThis->IsFilenameValid(pFilename))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// extract the timestamp
|
2021-06-23 05:05:49 +00:00
|
|
|
int64_t Timestamp = pThis->GetTimestamp(pFilename);
|
2011-07-22 21:17:16 +00:00
|
|
|
|
|
|
|
// add the entry
|
|
|
|
pThis->AddEntry(Timestamp);
|
|
|
|
|
|
|
|
return 0;
|
2011-07-30 16:29:40 +00:00
|
|
|
}
|
2015-08-22 15:21:00 +00:00
|
|
|
|
|
|
|
int CFileCollection::RemoveCallback(const char *pFilename, int IsDir, int StorageType, void *pUser)
|
|
|
|
{
|
|
|
|
CFileCollection *pThis = static_cast<CFileCollection *>(pUser);
|
|
|
|
|
|
|
|
// check for valid file name format
|
|
|
|
if(IsDir || !pThis->IsFilenameValid(pFilename))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// extract the timestamp
|
2021-06-23 05:05:49 +00:00
|
|
|
int64_t Timestamp = pThis->GetTimestamp(pFilename);
|
2015-08-22 15:21:00 +00:00
|
|
|
|
|
|
|
if(Timestamp == pThis->m_Remove)
|
|
|
|
{
|
2023-06-24 14:07:03 +00:00
|
|
|
char aBuf[IO_MAX_PATH_LENGTH];
|
2015-08-22 15:21:00 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "%s/%s", pThis->m_aPath, pFilename);
|
|
|
|
pThis->m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
|
|
|
|
pThis->m_Remove = -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|