Quellcode durchsuchen

android: Remove call to mktime() in APK entry parsing.

Ryan C. Gordon vor 6 Tagen
Ursprung
Commit
e1d623505e
1 geänderte Dateien mit 24 neuen und 21 gelöschten Zeilen
  1. 24 21
      src/core/android/SDL_android.c

+ 24 - 21
src/core/android/SDL_android.c

@@ -2027,27 +2027,30 @@ static APKNode *AddAPKDirs(char *path, APKNode *parent)
 
 static SDL_Time ZipDosTimeToSDLTime(Uint32 dostime)
 {
-    Uint32 dosdate;
-    struct tm unixtime;
-    SDL_zero(unixtime);
-
-    dosdate = (Uint32) ((dostime >> 16) & 0xFFFF);
-    dostime &= 0xFFFF;
-
-    /* dissect date */
-    unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;
-    unixtime.tm_mon  = ((dosdate >> 5) & 0x0F) - 1;
-    unixtime.tm_mday = ((dosdate     ) & 0x1F);
-
-    /* dissect time */
-    unixtime.tm_hour = ((dostime >> 11) & 0x1F);
-    unixtime.tm_min  = ((dostime >>  5) & 0x3F);
-    unixtime.tm_sec  = ((dostime <<  1) & 0x3E);
-
-    /* let mktime calculate daylight savings time. */
-    unixtime.tm_isdst = -1;
-
-    return ((SDL_Time) mktime(&unixtime));
+    // Note that DOS-style datetimes in a zip don't have timezone info, etc,
+    // so these are treated as UTC for lack of a better option. Also, they have
+    // 2-second precision and the year bits are going to roll over in 2108.
+    // There are possibly better timestamps in extended fields (!!! FIXME: add
+    // support for those), but this field is guaranteed to exist with all its
+    // flaws and is probably Good Enough anyhow.
+    const Uint32 dosdate = (Uint32) ((dostime >> 16) & 0xFFFF);
+    const Uint32 dostime16 = dostime & 0xFFFF;
+
+    const int m = (int) ((dosdate >> 5) & 0x0F);
+    const int d = (int) ((dosdate >> 0) & 0x1F) + 1;
+    const int y = (int) (((dosdate >> 9) & 0x7F) + 1980) - (m <= 2 ? 1 : 0);
+    const int hour   = (int) ((dostime16 >> 11) & 0x1F);
+    const int minute = (int) ((dostime16 >>  5) & 0x3F);
+    const int sec    = (int) ((dostime16 <<  1) & 0x3E);
+
+    // days since 1/1/1970: https://howardhinnant.github.io/date_algorithms.html#days_from_civil
+    const int era = ((y >= 0) ? y : (y - 399)) / 400;
+    const unsigned int yoe = (unsigned int) (y - era * 400);      // [0, 399]
+    const unsigned int doy = (((153 * ((m > 2) ? (m - 3) : (m + 9))) + 2) / 5) + (d - 1);  // [0, 365]
+    const unsigned int doe = (yoe * 365) + (yoe / 4) - (yoe / 100) + doy;         // [0, 146096]
+    const int days = (era * 146097) + ((int) doe) - 719468;
+    const int seconds = (hour * (60 * 60)) + (minute * 60) + (sec);
+    return (SDL_Time) (((Sint64) days) * 86400) + seconds;
 }