Fix Schism Tracker version date calculation.

Fixes several issues with the calculation of Schism Tracker dates.
Schism Tracker date calculation is now handled in a utility function.

* The date calculation was using a UTC epoch time but calculating
  the version date with localtime_r.
* The UTC epoch time was wrong (2009-10-01 instead of 2009-10-31).
* The S3M loader was not calculating Schism Tracker dates at all.
* Added detection for extended Schism Tracker dates (>2020-10-28)
  to both the S3M and IT loaders.

Additionally, the libxmp dependency on localtime_r has been entirely
removed in favor of an inline algorithm provided by Saga Musix.
This commit is contained in:
AliceLR
2020-11-05 01:27:53 -07:00
committed by Ozkan Sezer
parent 37585c285e
commit 7e20a828c7
6 changed files with 61 additions and 43 deletions

View File

@@ -150,7 +150,7 @@ darwin*)
LIBS="${old_LIBS}"
;;
esac
AC_CHECK_FUNCS(popen mkstemp fnmatch umask localtime_r round powf)
AC_CHECK_FUNCS(popen mkstemp fnmatch umask round powf)
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([libxmp.pc])

View File

@@ -149,7 +149,7 @@ darwin*)
LIBS="${old_LIBS}"
;;
esac
AC_CHECK_FUNCS(localtime_r round powf)
AC_CHECK_FUNCS(round powf)
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([libxmp-lite.pc])

View File

@@ -364,3 +364,54 @@ void libxmp_set_type(struct module_data *m, const char *fmt, ...)
vsnprintf(m->mod.type, XMP_NAME_SIZE, fmt, ap);
va_end(ap);
}
static int schism_tracker_date(int year, int month, int day)
{
int mm = (month + 9) % 12;
int yy = year - mm / 10;
yy = yy * 365 + (yy / 4) - (yy / 100) + (yy / 400);
mm = (mm * 306 + 5) / 10;
return yy + mm + (day - 1);
}
/* Generate a Schism Tracker version string.
* Schism Tracker versions are stored as follows:
*
* s_ver <= 0x50: 0.s_ver
* s_ver > 0x50, < 0xfff: days from epoch=(s_ver - 0x50)
* s_ver = 0xfff: days from epoch=l_ver
*/
void libxmp_schism_tracker_string(char *buf, size_t size, int s_ver, int l_ver)
{
if (s_ver >= 0x50) {
/* time_t epoch_sec = 1256947200; */
int t = schism_tracker_date(2009, 10, 31);
int year, month, day, dayofyear;
if (s_ver == 0xfff) {
t += l_ver;
} else
t += s_ver - 0x50;
/* Date algorithm reimplemented from OpenMPT.
*/
year = (int)(((int64)t * 10000L + 14780) / 3652425);
dayofyear = t - (365 * year + (year / 4) - (year / 100) + (year / 400));
if (dayofyear < 0) {
year--;
dayofyear = t - (365 * year + (year / 4) - (year / 100) + (year / 400));
}
month = (100 * dayofyear + 52) / 3060;
day = dayofyear - (month * 306 + 5) / 10 + 1;
year += (month + 2) / 12;
month = (month + 2) % 12 + 1;
snprintf(buf, size, "Schism Tracker %04d-%02d-%02d",
year, month, day);
} else {
snprintf(buf, size, "Schism Tracker 0.%x", s_ver);
}
}

View File

@@ -22,7 +22,6 @@
#ifndef LIBXMP_CORE_DISABLE_IT
#include <time.h>
#include "loader.h"
#include "it.h"
#include "period.h"
@@ -41,23 +40,6 @@ const struct format_loader libxmp_loader_it = {
it_load
};
#ifndef LIBXMP_CORE_PLAYER /* */
#if defined(__WATCOMC__)
#undef localtime_r
#define localtime_r _localtime
#elif !defined(HAVE_LOCALTIME_R) || defined(_WIN32)
#undef localtime_r
#define localtime_r libxmp_localtime_r
static struct tm *libxmp_localtime_r(const time_t * timep, struct tm *result)
{
/* Note: Win32 localtime() is thread-safe */
memcpy(result, localtime(timep), sizeof(struct tm));
return result;
}
#endif
#endif /* ! LIBXMP_CORE_PLAYER */
static int it_test(HIO_HANDLE * f, char *t, const int start)
{
if (hio_read32b(f) != MAGIC_IMPM)
@@ -373,25 +355,10 @@ static void identify_tracker(struct module_data *m, struct it_file_header *ifh)
break;
default:
switch (ifh->cwt >> 12) {
case 0x1:{
uint16 cwtv = ifh->cwt & 0x0fff;
struct tm version;
time_t version_sec;
if (cwtv > 0x50) {
version_sec = ((cwtv - 0x050) * 86400) + 1254355200;
if (localtime_r(&version_sec, &version)) {
snprintf(tracker_name, 40,
"Schism Tracker %04d-%02d-%02d",
version.tm_year + 1900,
version.tm_mon + 1,
version.tm_mday);
}
} else {
snprintf(tracker_name, 40,
"Schism Tracker 0.%x", cwtv);
}
break; }
case 0x1:
libxmp_schism_tracker_string(tracker_name, 40,
(ifh->cwt & 0x0fff), ifh->rsvd);
break;
case 0x5:
snprintf(tracker_name, 40, "OpenMPT %d.%02x",
(ifh->cwt & 0x0f00) >> 8, ifh->cwt & 0xff);

View File

@@ -47,6 +47,7 @@ void libxmp_get_instrument_path (struct module_data *, char *, int);
void libxmp_set_type (struct module_data *, const char *, ...);
int libxmp_load_sample (struct module_data *, HIO_HANDLE *, int,
struct xmp_sample *, const void *);
void libxmp_schism_tracker_string (char *, size_t, int, int);
extern uint8 libxmp_ord_xlat[];
extern const int libxmp_arch_vol_table[];

View File

@@ -271,7 +271,7 @@ static int s3m_load(struct module_data *m, HIO_HANDLE * f, const int start)
sfh.mv = buf[51]; /* Master volume */
sfh.uc = buf[52]; /* Ultra click removal */
sfh.dp = buf[53]; /* Default pan positions if 0xfc */
/* 54-61 reserved */
memcpy(sfh.rsvd2, buf + 54, 8); /* Reserved */
sfh.special = readmem16l(buf + 62); /* Ptr to special custom data */
memcpy(sfh.chset, buf + 64, 32); /* Channel settings */
@@ -418,9 +418,8 @@ static int s3m_load(struct module_data *m, HIO_HANDLE * f, const int start)
break;
case 4:
if (sfh.version != 0x4100) {
snprintf(tracker_name, 40, "Schism Tracker %d.%02x",
(sfh.version & 0x0f00) >> 8,
sfh.version & 0xff);
libxmp_schism_tracker_string(tracker_name, 40,
(sfh.version & 0x0fff), sfh.rsvd2[0] | (sfh.rsvd2[1] << 8));
break;
}
/* fall through */