Switch timestamp format to combined UTC + local so fewer stupid hacks are required.

This commit is contained in:
elasota
2020-01-23 22:36:12 -05:00
parent 6171b1185e
commit 928efdd527
8 changed files with 143 additions and 90 deletions

View File

@@ -5,10 +5,7 @@ mkdir ResourceTemp
x64\Release\MiniRez.exe "GliderProData\Glider PRO.r" Packaged\ApplicationResources.gpr
copy /B /Y NUL Packaged\Empty.txt
x64\Release\FTagData.exe "Packaged\Empty.txt" "DefaultTimestamp.timestamp" "Packaged\ApplicationResources" APPL ozm5 0 0 locked
x64\Release\gpr2gpa.exe Packaged\ApplicationResources Packaged\ApplicationResources.gpa
x64\Release\gpr2gpa.exe "Packaged\ApplicationResources.gpr" "DefaultTimestamp.timestamp" "Packaged\ApplicationResources.gpa"
x64\Release\ConvertColorCursors.exe
@@ -35,28 +32,28 @@ x64\Release\hqx2gp.exe "GliderProData\Houses\Teddy World.binhex" "DefaultTimesta
x64\Release\hqx2gp.exe "GliderProData\Houses\The Asylum Pro.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\The Asylum Pro"
x64\Release\hqx2gp.exe "GliderProData\Houses\Titanic.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Titanic"
x64\Release\gpr2gpa.exe "Packaged\Houses\Art Museum" "Packaged\Houses\Art Museum.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\California or Bust!" "Packaged\Houses\California or Bust!.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Castle o' the Air" "Packaged\Houses\Castle o' the Air.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\CD Demo House" "Packaged\Houses\CD Demo House.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Davis Station" "Packaged\Houses\Davis Station.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Demo House" "Packaged\Houses\Demo House.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Empty House" "Packaged\Houses\Empty House.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Fun House" "Packaged\Houses\Fun House.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Grand Prix" "Packaged\Houses\Grand Prix.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\ImagineHouse PRO II" "Packaged\Houses\ImagineHouse PRO II.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\In The Mirror" "Packaged\Houses\In The Mirror.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Land of Illusion" "Packaged\Houses\Land of Illusion.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Leviathan" "Packaged\Houses\Leviathan.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Metropolis" "Packaged\Houses\Metropolis.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Nemo's Market" "Packaged\Houses\Nemo's Market.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Rainbow's End" "Packaged\Houses\Rainbow's End.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Sampler" "Packaged\Houses\Sampler.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Slumberland" "Packaged\Houses\Slumberland.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\SpacePods" "Packaged\Houses\SpacePods.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Teddy World" "Packaged\Houses\Teddy World.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\The Asylum Pro" "Packaged\Houses\The Asylum Pro.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Titanic" "Packaged\Houses\Titanic.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Art Museum.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Art Museum.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\California or Bust!.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\California or Bust!.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Castle o' the Air.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Castle o' the Air.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\CD Demo House.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\CD Demo House.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Davis Station.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Davis Station.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Demo House.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Demo House.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Empty House.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Empty House.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Fun House.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Fun House.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Grand Prix.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Grand Prix.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\ImagineHouse PRO II.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\ImagineHouse PRO II.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\In The Mirror.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\In The Mirror.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Land of Illusion.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Land of Illusion.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Leviathan.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Leviathan.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Metropolis.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Metropolis.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Nemo's Market.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Nemo's Market.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Rainbow's End.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Rainbow's End.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Sampler.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Sampler.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Slumberland.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Slumberland.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\SpacePods.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\SpacePods.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Teddy World.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Teddy World.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\The Asylum Pro.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\The Asylum Pro.gpa"
x64\Release\gpr2gpa.exe "Packaged\Houses\Titanic.gpr" "DefaultTimestamp.timestamp" "Packaged\Houses\Titanic.gpa"
x64\Release\FTagData.exe "GliderProData\Houses\Art Museum.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Art Museum.mov" MooV ozm5 0 0 locked
x64\Release\FTagData.exe "GliderProData\Houses\Castle o' the Air.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Castle o' the Air.mov" MooV ozm5 0 0 locked
@@ -76,8 +73,5 @@ x64\Release\FTagData.exe "GliderProData\Houses\Titanic.mov" "DefaultTimestamp.ti
del /Q Packaged\Houses\*.gpr
del /Q Packaged\ApplicationResources.gpr
del /Q Packaged\ApplicationResources.gpf
del /Q Packaged\ApplicationResources.gpd
del /Q Packaged\Empty.txt
pause

Binary file not shown.

View File

@@ -2,6 +2,8 @@
#include <stdio.h>
#include <stdint.h>
#include "CombinedTimestamp.h"
int main(int argc, const char **argv)
{
if (argc != 2)
@@ -39,11 +41,29 @@ int main(int argc, const char **argv)
return -1;
}
uint8_t encodedTimestamp[8];
for (int i = 0; i < 8; i++)
encodedTimestamp[i] = static_cast<uint8_t>((timeDelta >> (i * 8)) & 0xff);
TIME_ZONE_INFORMATION tz;
GetTimeZoneInformation(&tz);
fwrite(encodedTimestamp, 8, 1, f);
SYSTEMTIME utcST;
FileTimeToSystemTime(&timestampFT, &utcST);
SYSTEMTIME localST;
SystemTimeToTzSpecificLocalTime(&tz, &utcST, &localST);
PortabilityLayer::CombinedTimestamp ts;
ts.SetUTCTime(timeDelta);
ts.SetLocalYear(localST.wYear);
ts.m_localMonth = localST.wMonth;
ts.m_localDay = localST.wDay;
ts.m_localHour = localST.wHour;
ts.m_localMinute = localST.wMinute;
ts.m_localSecond = localST.wSecond;
memset(ts.m_padding, 0, sizeof(ts.m_padding));
fwrite(&ts, sizeof(ts), 1, f);
fclose(f);

View File

@@ -58,15 +58,19 @@
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\PortabilityLayer.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\PortabilityLayer.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\PortabilityLayer.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\PortabilityLayer.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />

View File

@@ -0,0 +1,57 @@
#pragma once
#include <stdint.h>
namespace PortabilityLayer
{
struct CombinedTimestamp
{
uint8_t m_utcTimestamp[8];
uint8_t m_localYear[4];
uint8_t m_localMonth;
uint8_t m_localDay;
uint8_t m_localHour;
uint8_t m_localMinute;
uint8_t m_localSecond;
uint8_t m_padding[3];
int64_t GetUTCTime() const;
void SetUTCTime(int64_t timestamp);
int32_t GetLocalYear() const;
void SetLocalYear(int32_t year);
};
inline int64_t CombinedTimestamp::GetUTCTime() const
{
int64_t result = 0;
for (int i = 0; i < 8; i++)
result |= static_cast<int64_t>(m_utcTimestamp[i]) << (i * 8);
return result;
}
void CombinedTimestamp::SetUTCTime(int64_t timestamp)
{
for (int i = 0; i < 8; i++)
m_utcTimestamp[i] = static_cast<uint8_t>((timestamp >> (i * 8)) & 0xff);
}
inline int32_t CombinedTimestamp::GetLocalYear() const
{
int32_t result = 0;
for (int i = 0; i < 4; i++)
result |= static_cast<int32_t>(m_localYear[i]) << (i * 8);
return result;
}
void CombinedTimestamp::SetLocalYear(int32_t timestamp)
{
for (int i = 0; i < 4; i++)
m_localYear[i] = static_cast<uint8_t>((timestamp >> (i * 8)) & 0xff);
}
}

View File

@@ -147,6 +147,7 @@
<ClInclude Include="ByteSwap.h" />
<ClInclude Include="ByteUnpack.h" />
<ClInclude Include="CFileStream.h" />
<ClInclude Include="CombinedTimestamp.h" />
<ClInclude Include="DataTypes.h" />
<ClInclude Include="DeflateCodec.h" />
<ClInclude Include="DialogManager.h" />

View File

@@ -465,6 +465,9 @@
<ClInclude Include="BitmapImage.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CombinedTimestamp.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CFileStream.cpp">

View File

@@ -1,5 +1,6 @@
#include "BMPFormat.h"
#include "CFileStream.h"
#include "CombinedTimestamp.h"
#include "GPArchive.h"
#include "MemReaderStream.h"
#include "QDPictDecoder.h"
@@ -94,64 +95,42 @@ bool TryDeflate(const std::vector<uint8_t> &uncompressed, std::vector<uint8_t> &
return true;
}
void ConvertToMSDOSTimestamp(int64_t timestamp, uint16_t &msdosDate, uint16_t &msdosTime)
void ConvertToMSDOSTimestamp(const PortabilityLayer::CombinedTimestamp &ts, uint16_t &msdosDate, uint16_t &msdosTime)
{
SYSTEMTIME epochStart;
epochStart.wYear = 1904;
epochStart.wMonth = 1;
epochStart.wDayOfWeek = 5;
epochStart.wDay = 1;
epochStart.wHour = 0;
epochStart.wMinute = 0;
epochStart.wSecond = 0;
epochStart.wMilliseconds = 0;
int32_t yearsSince1980 = ts.GetLocalYear() - 1980;
uint8_t month = ts.m_localMonth;
uint8_t day = ts.m_localDay;
FILETIME epochStartFT;
SystemTimeToFileTime(&epochStart, &epochStartFT);
uint8_t hour = ts.m_localHour;
uint8_t minute = ts.m_localMinute;
uint8_t second = ts.m_localSecond;
int64_t epochStart64 = (static_cast<int64_t>(epochStartFT.dwLowDateTime) & 0xffffffff) | (static_cast<int64_t>(epochStartFT.dwHighDateTime) << 32);
int64_t offsetDate64 = (epochStart64 + timestamp * 10000000);
FILETIME utcTimestampFT;
utcTimestampFT.dwLowDateTime = static_cast<DWORD>(offsetDate64 & 0xffffffff);
utcTimestampFT.dwHighDateTime = static_cast<DWORD>((offsetDate64 >> 32) & 0xffffffff);
TIME_ZONE_INFORMATION tzInfo;
GetTimeZoneInformation(&tzInfo);
SYSTEMTIME utcTimestampST;
FileTimeToSystemTime(&utcTimestampFT, &utcTimestampST);
SYSTEMTIME localTimestampST;
SystemTimeToTzSpecificLocalTime(&tzInfo, &utcTimestampST, &localTimestampST);
DWORD yearsSince1980 = localTimestampST.wYear - 1980;
if (yearsSince1980 < 0)
{
// Time machine
yearsSince1980 = 0;
localTimestampST.wSecond = 0;
localTimestampST.wMinute = 0;
localTimestampST.wHour = 0;
localTimestampST.wDay = 1;
localTimestampST.wMonth = 1;
second = 0;
minute = 0;
hour = 0;
day = 1;
month = 1;
}
else if (yearsSince1980 > 127)
{
// I was promised flying cars, but it's 2107 and you're still flying paper airplanes...
yearsSince1980 = 127;
localTimestampST.wSecond = 59;
localTimestampST.wMinute = 59;
localTimestampST.wHour = 23;
localTimestampST.wDay = 31;
localTimestampST.wMonth = 12;
second = 59;
minute = 59;
hour = 23;
day = 31;
month = 12;
}
msdosTime = (localTimestampST.wSecond / 2) | (localTimestampST.wMinute << 5) | (localTimestampST.wHour << 11);
msdosDate = localTimestampST.wDay | (localTimestampST.wMonth << 5) | (yearsSince1980 << 9);
msdosTime = (second / 2) | (minute << 5) | (hour << 11);
msdosDate = day | (month << 5) | (yearsSince1980 << 9);
}
void ExportZipFile(const char *path, const std::vector<PlannedEntry> &entries, const PortabilityLayer::MacFileProperties &mfp)
void ExportZipFile(const char *path, const std::vector<PlannedEntry> &entries, const PortabilityLayer::CombinedTimestamp &ts)
{
FILE *outF = nullptr;
if (fopen_s(&outF, path, "wb"))
@@ -163,7 +142,7 @@ void ExportZipFile(const char *path, const std::vector<PlannedEntry> &entries, c
uint16_t msdosModificationTime = 0;
uint16_t msdosModificationDate = 0;
ConvertToMSDOSTimestamp(mfp.m_modifiedDate, msdosModificationDate, msdosModificationTime);
ConvertToMSDOSTimestamp(ts, msdosModificationDate, msdosModificationTime);
std::vector<PortabilityLayer::ZipCentralDirectoryFileHeader> cdirRecords;
@@ -742,40 +721,35 @@ bool ImportSound(std::vector<uint8_t> &outWAV, const void *inData, size_t inSize
int main(int argc, const char **argv)
{
if (argc != 3)
if (argc != 4)
{
fprintf(stderr, "Usage: gpr2gpa <prefix> <output.gpa>");
fprintf(stderr, "Usage: gpr2gpa <input.gpr> <input.ts> <output.gpa>");
return -1;
}
std::string base = argv[1];
std::string metadataPath = base + ".gpf";
std::string resPath = base + ".gpr";
FILE *inF = nullptr;
if (fopen_s(&inF, resPath.c_str(), "rb"))
if (fopen_s(&inF, argv[1], "rb"))
{
fprintf(stderr, "Error opening input file");
return -1;
}
FILE *metaF = nullptr;
if (fopen_s(&metaF, metadataPath.c_str(), "rb"))
FILE *timestampF = nullptr;
if (fopen_s(&timestampF, argv[2], "rb"))
{
fprintf(stderr, "Error opening metadata file");
return -1;
}
PortabilityLayer::MacFilePropertiesSerialized mfpSerialized;
if (fread(mfpSerialized.m_data, 1, PortabilityLayer::MacFilePropertiesSerialized::kSize, metaF) != PortabilityLayer::MacFilePropertiesSerialized::kSize)
PortabilityLayer::CombinedTimestamp ts;
if (fread(&ts, 1, sizeof(ts), timestampF) != sizeof(ts))
{
fprintf(stderr, "Error reading metadata");
fprintf(stderr, "Error reading timestamp");
return -1;
}
PortabilityLayer::MacFileProperties mfp;
mfpSerialized.Deserialize(mfp);
PortabilityLayer::CFileStream cfs(inF);
PortabilityLayer::ResourceFile *resFile = PortabilityLayer::ResourceFile::Create();
@@ -856,7 +830,7 @@ int main(int argc, const char **argv)
}
}
ExportZipFile(argv[2], contents, mfp);
ExportZipFile(argv[3], contents, ts);
resFile->Destroy();