From a1475d2ee311ae4394a3c377a6b8b608fc6a0f93 Mon Sep 17 00:00:00 2001 From: elasota Date: Thu, 23 Jan 2020 02:47:31 -0500 Subject: [PATCH] Fixed a bunch of improper timestamp handling, made ZIP timestamping deterministic, added default timestamp --- Aerofoil.sln | 10 ++ Aerofoil/GpSystemServices_Win32.cpp | 2 +- ConvertResources.bat | 126 ++++++++++--------- DefaultTimestamp.timestamp | Bin 0 -> 8 bytes FTagData/FTagData.cpp | 53 ++++---- MakeTimestamp/MakeTimestamp.cpp | 54 +++++++++ MakeTimestamp/MakeTimestamp.vcxproj | 128 ++++++++++++++++++++ MakeTimestamp/MakeTimestamp.vcxproj.filters | 22 ++++ PortabilityLayer/MacFileInfo.h | 3 - gpr2gpa/gpr2gpa.cpp | 123 +++++++++++++------ hqx2gp/hqx2gp.cpp | 44 ++++++- 11 files changed, 429 insertions(+), 136 deletions(-) create mode 100644 DefaultTimestamp.timestamp create mode 100644 MakeTimestamp/MakeTimestamp.cpp create mode 100644 MakeTimestamp/MakeTimestamp.vcxproj create mode 100644 MakeTimestamp/MakeTimestamp.vcxproj.filters diff --git a/Aerofoil.sln b/Aerofoil.sln index 22db251..fedb6ed 100644 --- a/Aerofoil.sln +++ b/Aerofoil.sln @@ -39,6 +39,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcxproj", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin2gp", "bin2gp\bin2gp.vcxproj", "{D7BFE702-0667-4155-9B0B-2A54DF9AE60B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MakeTimestamp", "MakeTimestamp\MakeTimestamp.vcxproj", "{9023DF2F-A33D-485A-B13D-0973348B2F9B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -191,6 +193,14 @@ Global {D7BFE702-0667-4155-9B0B-2A54DF9AE60B}.Release|x64.Build.0 = Release|x64 {D7BFE702-0667-4155-9B0B-2A54DF9AE60B}.Release|x86.ActiveCfg = Release|Win32 {D7BFE702-0667-4155-9B0B-2A54DF9AE60B}.Release|x86.Build.0 = Release|Win32 + {9023DF2F-A33D-485A-B13D-0973348B2F9B}.Debug|x64.ActiveCfg = Debug|x64 + {9023DF2F-A33D-485A-B13D-0973348B2F9B}.Debug|x64.Build.0 = Debug|x64 + {9023DF2F-A33D-485A-B13D-0973348B2F9B}.Debug|x86.ActiveCfg = Debug|Win32 + {9023DF2F-A33D-485A-B13D-0973348B2F9B}.Debug|x86.Build.0 = Debug|Win32 + {9023DF2F-A33D-485A-B13D-0973348B2F9B}.Release|x64.ActiveCfg = Release|x64 + {9023DF2F-A33D-485A-B13D-0973348B2F9B}.Release|x64.Build.0 = Release|x64 + {9023DF2F-A33D-485A-B13D-0973348B2F9B}.Release|x86.ActiveCfg = Release|Win32 + {9023DF2F-A33D-485A-B13D-0973348B2F9B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Aerofoil/GpSystemServices_Win32.cpp b/Aerofoil/GpSystemServices_Win32.cpp index d41c362..0a2229d 100644 --- a/Aerofoil/GpSystemServices_Win32.cpp +++ b/Aerofoil/GpSystemServices_Win32.cpp @@ -35,7 +35,7 @@ int64_t GpSystemServices_Win32::GetTime() const int64_t epochStart64 = (static_cast(epochStartFT.dwLowDateTime) & 0xffffffff) | (static_cast(epochStartFT.dwHighDateTime) << 32); int64_t currentTime64 = (static_cast(currentTime.dwLowDateTime) & 0xffffffff) | (static_cast(currentTime.dwHighDateTime) << 32); - return currentTime64 - epochStart64; + return (currentTime64 - epochStart64) / 10000000; } void GpSystemServices_Win32::GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const diff --git a/ConvertResources.bat b/ConvertResources.bat index 408dac5..ea7235b 100644 --- a/ConvertResources.bat +++ b/ConvertResources.bat @@ -5,73 +5,79 @@ mkdir ResourceTemp x64\Release\MiniRez.exe "GliderProData\Glider PRO.r" Packaged\ApplicationResources.gpr -x64\Release\gpr2gpa.exe Packaged\ApplicationResources.gpr Packaged\ApplicationResources.gpa +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\ConvertColorCursors.exe -x64\Release\hqx2gp.exe "GliderProData\Houses\Art Museum.binhex" "Packaged\Houses\Art Museum" -x64\Release\hqx2gp.exe "GliderProData\Houses\California or Bust!.binhex" "Packaged\Houses\California or Bust!" -x64\Release\hqx2gp.exe "GliderProData\Houses\Castle o' the Air.binhex" "Packaged\Houses\Castle o' the Air" -x64\Release\hqx2gp.exe "GliderProData\Houses\CD Demo House.binhex" "Packaged\Houses\CD Demo House" -x64\Release\hqx2gp.exe "GliderProData\Houses\Davis Station.binhex" "Packaged\Houses\Davis Station" -x64\Release\hqx2gp.exe "GliderProData\Houses\Demo House.binhex" "Packaged\Houses\Demo House" -x64\Release\hqx2gp.exe "GliderProData\Houses\Empty House.binhex" "Packaged\Houses\Empty House" -x64\Release\hqx2gp.exe "GliderProData\Houses\Fun House.binhex" "Packaged\Houses\Fun House" -x64\Release\hqx2gp.exe "GliderProData\Houses\Grand Prix.binhex" "Packaged\Houses\Grand Prix" -x64\Release\hqx2gp.exe "GliderProData\Houses\ImagineHouse PRO II.binhex" "Packaged\Houses\ImagineHouse PRO II" -x64\Release\hqx2gp.exe "GliderProData\Houses\In The Mirror.binhex" "Packaged\Houses\In The Mirror" -x64\Release\hqx2gp.exe "GliderProData\Houses\Land of Illusion.binhex" "Packaged\Houses\Land of Illusion" -x64\Release\hqx2gp.exe "GliderProData\Houses\Leviathan.binhex" "Packaged\Houses\Leviathan" -x64\Release\hqx2gp.exe "GliderProData\Houses\Metropolis.binhex" "Packaged\Houses\Metropolis" -x64\Release\hqx2gp.exe "GliderProData\Houses\Nemo's Market.binhex" "Packaged\Houses\Nemo's Market" -x64\Release\hqx2gp.exe "GliderProData\Houses\Rainbow's End.binhex" "Packaged\Houses\Rainbow's End" -x64\Release\hqx2gp.exe "GliderProData\Houses\Sampler.binhex" "Packaged\Houses\Sampler" -x64\Release\hqx2gp.exe "GliderProData\Houses\Slumberland.binhex" "Packaged\Houses\Slumberland" -x64\Release\hqx2gp.exe "GliderProData\Houses\SpacePods.binhex" "Packaged\Houses\SpacePods" -x64\Release\hqx2gp.exe "GliderProData\Houses\Teddy World.binhex" "Packaged\Houses\Teddy World" -x64\Release\hqx2gp.exe "GliderProData\Houses\The Asylum Pro.binhex" "Packaged\Houses\The Asylum Pro" -x64\Release\hqx2gp.exe "GliderProData\Houses\Titanic.binhex" "Packaged\Houses\Titanic" +x64\Release\hqx2gp.exe "GliderProData\Houses\Art Museum.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Art Museum" +x64\Release\hqx2gp.exe "GliderProData\Houses\California or Bust!.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\California or Bust!" +x64\Release\hqx2gp.exe "GliderProData\Houses\Castle o' the Air.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Castle o' the Air" +x64\Release\hqx2gp.exe "GliderProData\Houses\CD Demo House.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\CD Demo House" +x64\Release\hqx2gp.exe "GliderProData\Houses\Davis Station.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Davis Station" +x64\Release\hqx2gp.exe "GliderProData\Houses\Demo House.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Demo House" +x64\Release\hqx2gp.exe "GliderProData\Houses\Empty House.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Empty House" +x64\Release\hqx2gp.exe "GliderProData\Houses\Fun House.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Fun House" +x64\Release\hqx2gp.exe "GliderProData\Houses\Grand Prix.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Grand Prix" +x64\Release\hqx2gp.exe "GliderProData\Houses\ImagineHouse PRO II.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\ImagineHouse PRO II" +x64\Release\hqx2gp.exe "GliderProData\Houses\In The Mirror.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\In The Mirror" +x64\Release\hqx2gp.exe "GliderProData\Houses\Land of Illusion.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Land of Illusion" +x64\Release\hqx2gp.exe "GliderProData\Houses\Leviathan.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Leviathan" +x64\Release\hqx2gp.exe "GliderProData\Houses\Metropolis.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Metropolis" +x64\Release\hqx2gp.exe "GliderProData\Houses\Nemo's Market.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Nemo's Market" +x64\Release\hqx2gp.exe "GliderProData\Houses\Rainbow's End.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Rainbow's End" +x64\Release\hqx2gp.exe "GliderProData\Houses\Sampler.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Sampler" +x64\Release\hqx2gp.exe "GliderProData\Houses\Slumberland.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Slumberland" +x64\Release\hqx2gp.exe "GliderProData\Houses\SpacePods.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\SpacePods" +x64\Release\hqx2gp.exe "GliderProData\Houses\Teddy World.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Teddy World" +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.gpr" "Packaged\Houses\Art Museum.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\California or Bust!.gpr" "Packaged\Houses\California or Bust!.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Castle o' the Air.gpr" "Packaged\Houses\Castle o' the Air.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\CD Demo House.gpr" "Packaged\Houses\CD Demo House.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Davis Station.gpr" "Packaged\Houses\Davis Station.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Demo House.gpr" "Packaged\Houses\Demo House.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Empty House.gpr" "Packaged\Houses\Empty House.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Fun House.gpr" "Packaged\Houses\Fun House.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Grand Prix.gpr" "Packaged\Houses\Grand Prix.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\ImagineHouse PRO II.gpr" "Packaged\Houses\ImagineHouse PRO II.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\In The Mirror.gpr" "Packaged\Houses\In The Mirror.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Land of Illusion.gpr" "Packaged\Houses\Land of Illusion.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Leviathan.gpr" "Packaged\Houses\Leviathan.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Metropolis.gpr" "Packaged\Houses\Metropolis.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Nemo's Market.gpr" "Packaged\Houses\Nemo's Market.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Rainbow's End.gpr" "Packaged\Houses\Rainbow's End.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Sampler.gpr" "Packaged\Houses\Sampler.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Slumberland.gpr" "Packaged\Houses\Slumberland.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\SpacePods.gpr" "Packaged\Houses\SpacePods.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Teddy World.gpr" "Packaged\Houses\Teddy World.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\The Asylum Pro.gpr" "Packaged\Houses\The Asylum Pro.gpa" -x64\Release\gpr2gpa.exe "Packaged\Houses\Titanic.gpr" "Packaged\Houses\Titanic.gpa" +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\FTagData.exe "GliderProData\Houses\Art Museum.mov", "Packaged\Houses\Art Museum.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Castle o' the Air.mov", "Packaged\Houses\Castle o' the Air.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\CD Demo House.mov", "Packaged\Houses\CD Demo House.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Davis Station.mov", "Packaged\Houses\Davis Station.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Demo House.mov", "Packaged\Houses\Demo House.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Grand Prix.mov", "Packaged\Houses\Grand Prix.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\ImagineHouse PRO II.mov", "Packaged\Houses\ImagineHouse PRO II.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Land of Illusion.mov", "Packaged\Houses\Land of Illusion.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Leviathan.mov", "Packaged\Houses\Leviathan.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Nemo's Market.mov", "Packaged\Houses\Nemo's Market.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Rainbow's End.mov", "Packaged\Houses\Rainbow's End.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Slumberland.mov", "Packaged\Houses\Slumberland.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\SpacePods.mov", "Packaged\Houses\SpacePods.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Teddy World.mov", "Packaged\Houses\Teddy World.mov" MooV ozm5 0 0 locked -x64\Release\FTagData.exe "GliderProData\Houses\Titanic.mov", "Packaged\Houses\Titanic.mov" MooV ozm5 0 0 locked +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 +x64\Release\FTagData.exe "GliderProData\Houses\CD Demo House.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\CD Demo House.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Davis Station.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Davis Station.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Demo House.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Demo House.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Grand Prix.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Grand Prix.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\ImagineHouse PRO II.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\ImagineHouse PRO II.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Land of Illusion.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Land of Illusion.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Leviathan.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Leviathan.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Nemo's Market.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Nemo's Market.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Rainbow's End.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Rainbow's End.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Slumberland.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Slumberland.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\SpacePods.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\SpacePods.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Teddy World.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Teddy World.mov" MooV ozm5 0 0 locked +x64\Release\FTagData.exe "GliderProData\Houses\Titanic.mov" "DefaultTimestamp.timestamp" "Packaged\Houses\Titanic.mov" MooV ozm5 0 0 locked 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 diff --git a/DefaultTimestamp.timestamp b/DefaultTimestamp.timestamp new file mode 100644 index 0000000000000000000000000000000000000000..d2c0e8d6e50e62a4d5e7a210c349719b8c118465 GIT binary patch literal 8 NcmZo#;eU$(2mlVu0#pD1 literal 0 HcmV?d00001 diff --git a/FTagData/FTagData.cpp b/FTagData/FTagData.cpp index e584aa2..f854fb8 100644 --- a/FTagData/FTagData.cpp +++ b/FTagData/FTagData.cpp @@ -5,56 +5,55 @@ int main(int argc, const char **argv) { - if (argc < 7) + if (argc < 8) { - fprintf(stderr, "FTagData [flags]"); + fprintf(stderr, "FTagData [flags]"); return -1; } std::string inPath = argv[1]; - std::string outPath = argv[2]; + std::string timestampPath = argv[2]; + std::string outPath = argv[3]; - if (strlen(argv[3]) != 4) + if (strlen(argv[4]) != 4) { fprintf(stderr, "File type ID must be 4 characters"); return -2; } - if (strlen(argv[4]) != 4) + if (strlen(argv[5]) != 4) { fprintf(stderr, "File creator ID must be 4 characters"); return -3; } - FILETIME currentTime; - GetSystemTimeAsFileTime(¤tTime); + FILE *tsF = nullptr; + errno_t ferr = fopen_s(&tsF, timestampPath.c_str(), "rb"); + int64_t timestamp = 0; - 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; + if (!ferr) + { + uint8_t encodedTimestamp[8]; + if (fread(encodedTimestamp, 1, 8, tsF) != 8) + { + fprintf(stderr, "Error reading timestamp file"); + return -1; + } - FILETIME epochStartFT; - SystemTimeToFileTime(&epochStart, &epochStartFT); + for (int i = 0; i < 8; i++) + timestamp |= static_cast(encodedTimestamp[i]) << (i * 8); - int64_t epochStart64 = (static_cast(epochStartFT.dwLowDateTime) & 0xffffffff) | (static_cast(epochStartFT.dwHighDateTime) << 32); - int64_t currentTime64 = (static_cast(currentTime.dwLowDateTime) & 0xffffffff) | (static_cast(currentTime.dwHighDateTime) << 32); - - int64_t timeDelta = (currentTime64 - epochStart64) / 10000000; + fclose(tsF); + } PortabilityLayer::MacFileProperties mfp; - memcpy(mfp.m_fileType, argv[3], 4); - memcpy(mfp.m_fileCreator, argv[4], 4); - mfp.m_xPos = atoi(argv[5]); - mfp.m_yPos = atoi(argv[6]); + memcpy(mfp.m_fileType, argv[4], 4); + memcpy(mfp.m_fileCreator, argv[5], 4); + mfp.m_xPos = atoi(argv[6]); + mfp.m_yPos = atoi(argv[7]); mfp.m_finderFlags = 0; mfp.m_protected = 0; - mfp.m_modifiedDate = mfp.m_creationDate = static_cast(timeDelta & 0xffffffff); + mfp.m_modifiedDate = mfp.m_creationDate = timestamp; for (int i = 7; i < argc; i++) { diff --git a/MakeTimestamp/MakeTimestamp.cpp b/MakeTimestamp/MakeTimestamp.cpp new file mode 100644 index 0000000..94cefc4 --- /dev/null +++ b/MakeTimestamp/MakeTimestamp.cpp @@ -0,0 +1,54 @@ +#include +#include +#include + +int main(int argc, const char **argv) +{ + if (argc != 2) + { + fprintf(stderr, "Usage: MakeTimestamp \n"); + fprintf(stderr, "Outputs the current timestamp in 1904 epoch format"); + return -1; + } + + 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; + + FILETIME epochStartFT; + if (!SystemTimeToFileTime(&epochStart, &epochStartFT)) + return 0; + + SYSTEMTIME localTime; + GetLocalTime(&localTime); + + FILETIME localTimeFT; + SystemTimeToFileTime(&localTime, &localTimeFT); + + int64_t epochStart64 = (static_cast(epochStartFT.dwLowDateTime) & 0xffffffff) | (static_cast(epochStartFT.dwHighDateTime) << 32); + int64_t currentTime64 = (static_cast(localTimeFT.dwLowDateTime) & 0xffffffff) | (static_cast(localTimeFT.dwHighDateTime) << 32); + int64_t timeDelta = (currentTime64 - epochStart64) / 10000000; + + FILE *f = nullptr; + if (fopen_s(&f, argv[1], "wb")) + { + fprintf(stderr, "Error opening output file"); + return -1; + } + + uint8_t encodedTimestamp[8]; + for (int i = 0; i < 8; i++) + encodedTimestamp[i] = static_cast((timeDelta >> (i * 8)) & 0xff); + + fwrite(encodedTimestamp, 8, 1, f); + + fclose(f); + + return 0; +} diff --git a/MakeTimestamp/MakeTimestamp.vcxproj b/MakeTimestamp/MakeTimestamp.vcxproj new file mode 100644 index 0000000..56fff49 --- /dev/null +++ b/MakeTimestamp/MakeTimestamp.vcxproj @@ -0,0 +1,128 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {9023DF2F-A33D-485A-B13D-0973348B2F9B} + MakeTimestamp + 10.0.17763.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + {6ec62b0f-9353-40a4-a510-3788f1368b33} + + + + + + \ No newline at end of file diff --git a/MakeTimestamp/MakeTimestamp.vcxproj.filters b/MakeTimestamp/MakeTimestamp.vcxproj.filters new file mode 100644 index 0000000..3c4036c --- /dev/null +++ b/MakeTimestamp/MakeTimestamp.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/PortabilityLayer/MacFileInfo.h b/PortabilityLayer/MacFileInfo.h index 69fe00b..564434b 100644 --- a/PortabilityLayer/MacFileInfo.h +++ b/PortabilityLayer/MacFileInfo.h @@ -29,9 +29,6 @@ namespace PortabilityLayer uint8_t m_protected; int64_t m_creationDate; int64_t m_modifiedDate; - - void Serialize(void *buffer) const; - void Deserialize(const void *buffer); }; struct MacFilePropertiesSerialized diff --git a/gpr2gpa/gpr2gpa.cpp b/gpr2gpa/gpr2gpa.cpp index 45c1d60..fac20e3 100644 --- a/gpr2gpa/gpr2gpa.cpp +++ b/gpr2gpa/gpr2gpa.cpp @@ -5,6 +5,7 @@ #include "QDPictDecoder.h" #include "QDPictEmitContext.h" #include "QDPictEmitScanlineParameters.h" +#include "MacFileInfo.h" #include "ResourceFile.h" #include "ResourceCompiledTypeList.h" #include "SharedTypes.h" @@ -93,7 +94,59 @@ bool TryDeflate(const std::vector &uncompressed, std::vector & return true; } -void ExportZipFile(const char *path, const std::vector &entries) +void ConvertToMSDOSTimestamp(int64_t timestamp, 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; + + FILETIME epochStartFT; + SystemTimeToFileTime(&epochStart, &epochStartFT); + + int64_t epochStart64 = (static_cast(epochStartFT.dwLowDateTime) & 0xffffffff) | (static_cast(epochStartFT.dwHighDateTime) << 32); + int64_t offsetDate64 = (epochStart64 + timestamp * 10000000); + + FILETIME timestampFT; + timestampFT.dwLowDateTime = static_cast(offsetDate64 & 0xffffffff); + timestampFT.dwHighDateTime = static_cast((offsetDate64 >> 32) & 0xffffffff); + + // We could use FileTimeToDosDateTime but we want to clamp + SYSTEMTIME timestampST; + FileTimeToSystemTime(×tampFT, ×tampST); + + DWORD yearsSince1980 = timestampST.wYear - 1980; + if (yearsSince1980 < 0) + { + // Time machine + yearsSince1980 = 0; + timestampST.wSecond = 0; + timestampST.wMinute = 0; + timestampST.wHour = 0; + timestampST.wDay = 1; + timestampST.wMonth = 1; + } + else if (yearsSince1980 > 127) + { + // I was promised flying cars, but it's 2107 and you're still flying paper airplanes... + yearsSince1980 = 127; + timestampST.wSecond = 59; + timestampST.wMinute = 59; + timestampST.wHour = 23; + timestampST.wDay = 31; + timestampST.wMonth = 12; + } + + msdosTime = (timestampST.wSecond / 2) | (timestampST.wMinute << 5) | (timestampST.wHour << 11); + msdosDate = timestampST.wDay | (timestampST.wMonth << 5) | (yearsSince1980 << 9); +} + +void ExportZipFile(const char *path, const std::vector &entries, const PortabilityLayer::MacFileProperties &mfp) { FILE *outF = nullptr; if (fopen_s(&outF, path, "wb")) @@ -102,41 +155,10 @@ void ExportZipFile(const char *path, const std::vector &entries) return; } - SYSTEMTIME localTime; - GetLocalTime(&localTime); + uint16_t msdosModificationTime = 0; + uint16_t msdosModificationDate = 0; - DWORD yearsSince1980 = localTime.wYear - 1980; - if (yearsSince1980 < 0) - { - // Time machine - yearsSince1980 = 0; - localTime.wSecond = 0; - localTime.wMinute = 0; - localTime.wHour = 0; - localTime.wDay = 1; - localTime.wMonth = 1; - } - else if (yearsSince1980 > 127) - { - // Original author is either dead or cryofrozen - yearsSince1980 = 127; - localTime.wSecond = 59; - localTime.wMinute = 59; - localTime.wHour = 23; - localTime.wDay = 31; - localTime.wMonth = 12; - } - - uint16_t msdosTime = 0; - uint16_t msdosDate = 0; - - msdosTime |= localTime.wSecond / 2; - msdosTime |= (localTime.wMinute << 5); - msdosTime |= (localTime.wHour << 11); - - msdosDate |= localTime.wDay; - msdosDate |= (localTime.wMonth << 5); - msdosDate |= (yearsSince1980 << 9); + ConvertToMSDOSTimestamp(mfp.m_modifiedDate, msdosModificationDate, msdosModificationTime); std::vector cdirRecords; @@ -162,8 +184,8 @@ void ExportZipFile(const char *path, const std::vector &entries) cdirHeader.m_versionRequired = PortabilityLayer::ZipConstants::kStoredRequiredVersion; cdirHeader.m_flags = 0; cdirHeader.m_method = isCompressed ? PortabilityLayer::ZipConstants::kDeflatedMethod : PortabilityLayer::ZipConstants::kStoredMethod; - cdirHeader.m_modificationTime = msdosTime; - cdirHeader.m_modificationDate = msdosDate; + cdirHeader.m_modificationTime = msdosModificationTime; + cdirHeader.m_modificationDate = msdosModificationDate; cdirHeader.m_crc = 0; if (entry.m_isDirectory) @@ -717,17 +739,38 @@ int main(int argc, const char **argv) { if (argc != 3) { - fprintf(stderr, "Usage: gpr2gpa "); + fprintf(stderr, "Usage: gpr2gpa "); return -1; } + std::string base = argv[1]; + std::string metadataPath = base + ".gpf"; + std::string resPath = base + ".gpr"; + FILE *inF = nullptr; - if (fopen_s(&inF, argv[1], "rb")) + if (fopen_s(&inF, resPath.c_str(), "rb")) { fprintf(stderr, "Error opening input file"); return -1; } + FILE *metaF = nullptr; + if (fopen_s(&metaF, metadataPath.c_str(), "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) + { + fprintf(stderr, "Error reading metadata"); + return -1; + } + + PortabilityLayer::MacFileProperties mfp; + mfpSerialized.Deserialize(mfp); + PortabilityLayer::CFileStream cfs(inF); PortabilityLayer::ResourceFile *resFile = PortabilityLayer::ResourceFile::Create(); @@ -808,7 +851,7 @@ int main(int argc, const char **argv) } } - ExportZipFile(argv[2], contents); + ExportZipFile(argv[2], contents, mfp); resFile->Destroy(); diff --git a/hqx2gp/hqx2gp.cpp b/hqx2gp/hqx2gp.cpp index 893e0cc..1ce874e 100644 --- a/hqx2gp/hqx2gp.cpp +++ b/hqx2gp/hqx2gp.cpp @@ -34,9 +34,9 @@ using namespace PortabilityLayer; int main(int argc, const char **argv) { - if (argc != 3) + if (argc != 4) { - fprintf(stderr, "Usage: hqx2gp "); + fprintf(stderr, "Usage: hqx2gp "); return -1; } @@ -54,18 +54,52 @@ int main(int argc, const char **argv) return -1; } +#ifdef _CRT_INSECURE_DEPRECATE + FILE *tsF = nullptr; + if (fopen_s(&tsF, argv[2], "rb")) + tsF = nullptr; +#else + FILE *tsF = fopen(argv[2], "rb"); +#endif + + if (!tsF) + { + fprintf(stderr, "Could not open timestamp file"); + return -1; + } + + int64_t timestamp = 0; + + { + uint8_t encodedTimestamp[8]; + if (fread(encodedTimestamp, 1, 8, tsF) != 8) + { + fprintf(stderr, "Error reading timestamp file"); + return -1; + } + + for (int i = 0; i < 8; i++) + timestamp |= static_cast(encodedTimestamp[i]) << (i * 8); + + } + + fclose(tsF); + CFileStream fs(f, true, false, true); ScopedPtr memFile = BinHex4::LoadHQX(&fs); fs.Close(); - std::string fname = argv[2]; + std::string fname = argv[3]; - const char* extensions[] = { ".gpf", ".gpr", ".gpd", ".gpc" }; + const char* extensions[] = { ".gpf", ".gpr", ".gpd", ".gpc" }; + + MacFileProperties mfp = memFile->FileInfo().m_properties; + mfp.m_creationDate = mfp.m_modifiedDate = timestamp; MacFilePropertiesSerialized sp; - sp.Serialize(memFile->FileInfo().m_properties); + sp.Serialize(mfp); for (int i = 0; i < 4; i++) {