]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Compute LOC text representation without using floating point for latitude and longitude
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 25 Feb 2025 16:19:10 +0000 (17:19 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 13 Jun 2025 09:38:07 +0000 (11:38 +0200)
Signed-off-by: Otto Moerbeek <otto.moerbeek@open-xchange.com>
pdns/sillyrecords.cc
pdns/test-dnsrecords_cc.cc

index a6edc189e2903af18cdcabaf481e3aeb4d05c95a..af935f3d5a5fb9434f91ea7e96457b4a2bb9b64c 100644 (file)
@@ -301,8 +301,6 @@ string LOCRecordContent::getZoneRepresentation(bool /* noDot */) const
   // convert d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude to:
   // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m
 
-  double latitude= ((int32_t)((uint32_t)d_latitude  - ((uint32_t)1<<31)))/3600000.0;
-  double longitude=((int32_t)((uint32_t)d_longitude - ((uint32_t)1<<31)))/3600000.0;
   double altitude= ((int32_t)d_altitude           )/100.0 - 100000;
 
   double size=0.01*((d_size>>4)&0xf);
@@ -320,15 +318,43 @@ string LOCRecordContent::getZoneRepresentation(bool /* noDot */) const
   while(count--)
     vertpre*=10;
 
-  double remlat=60.0*(latitude-(int)latitude);
-  double remlong=60.0*(longitude-(int)longitude);
-  static const boost::format fmt("%d %d %2.03f %c %d %d %2.03f %c %.2fm %.2fm %.2fm %.2fm");
+  char hemLat = 'N';
+  uint32_t lat = d_latitude;
+  if (lat >= 1U << 31) {
+    lat -= 1U << 31;
+  }
+  else {
+    hemLat = 'S';
+    lat = (1U << 31) - lat;
+  }
+  auto fracLat = lat % 1000;
+  lat /= 1000;
+  auto secLat = lat % 60;
+  lat /= 60;
+  auto minutesLat = lat % 60;
+  auto degreesLat = lat / 60;
+
+  char hemLon= 'E';
+  uint32_t lon = d_longitude;
+  if (lon >= 1U << 31) {
+    lon -= 1U << 31;
+  }
+  else {
+    hemLon = 'W';
+    lon = (1U << 31) - lon;
+  }
+  auto fracLon = lon % 1000;
+  lon /= 1000;
+  auto secLon = lon % 60;
+  lon /= 60;
+  auto minutesLon = lon % 60;
+  auto degreesLon = lon / 60;
+
+  static const boost::format fmt("%d %d %d.%03d %c %d %d %d.%03d %c %.2fm %.2fm %.2fm %.2fm");
   std::string ret = boost::str(
     boost::format(fmt)
-    % abs((int)latitude) % abs((int) ((latitude-(int)latitude)*60))
-    % fabs((double)((remlat-(int)remlat)*60.0)) % (latitude>0 ? 'N' : 'S')
-    % abs((int)longitude) % abs((int) ((longitude-(int)longitude)*60))
-    % fabs((double)((remlong-(int)remlong)*60.0)) % (longitude>0 ? 'E' : 'W')
+    % degreesLat % minutesLat % secLat % fracLat % hemLat
+    % degreesLon % minutesLon % secLon % fracLon % hemLon
     % altitude % size
     % horizpre % vertpre
     );
index fb83a86bbc3153c2e3c0623233a0c6117ec7885e..bbe1761556baa0b1daffe491760ad9660fafe294 100644 (file)
@@ -117,7 +117,13 @@ BOOST_AUTO_TEST_CASE(test_record_types) {
      (CASE_L(QType::LOC, "32 7 19 S 116 2 25 E 10m", "32 7 19.000 S 116 2 25.000 E 10.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x79\x1b\x7d\x28\x98\xe6\x48\x68\x00\x98\x9a\x68"))
      (CASE_L(QType::LOC, "42 21 54 N 71 06 18 W -24m 30m", "42 21 54.000 N 71 6 18.000 W -24.00m 30.00m 10000.00m 10.00m", "\x00\x33\x16\x13\x89\x17\x2d\xd0\x70\xbe\x15\xf0\x00\x98\x8d\x20"))
      (CASE_L(QType::LOC, "42 21 43.952 N 71 5 6.344 W -24m 1m 200m", "42 21 43.952 N 71 5 6.344 W -24.00m 1.00m 200.00m 10.00m", "\x00\x12\x24\x13\x89\x17\x06\x90\x70\xbf\x2d\xd8\x00\x98\x8d\x20"))
+     (CASE_L(QType::LOC, "57 9 0.000 N 2 7 9.998 W 0.00m 0.00m 0.00m 0.00m", "57 9 0.000 N 2 7 9.998 W 0.00m 0.00m 0.00m 0.00m", "\x00\x00\x00\x00\x8c\x43\x57\xe0\x7f\x8b\x93\x52\x00\x98\x96\x80"))
+     (CASE_L(QType::LOC, "57 8 59.999 N 2 7 9.998 W 0.00m 0.00m 0.00m 0.00m", "57 8 59.999 N 2 7 9.998 W 0.00m 0.00m 0.00m 0.00m", "\x00\x00\x00\x00\x8c\x43\x57\xdf\x7f\x8b\x93\x52\x00\x98\x96\x80"))
 // local name
+     (CASE_L(QType::LOC, "51 11 60.000 N 2 12 5.080 W 0.00m 0.00m 0.00m 0.00m", "51 12 0.000 N 2 12 5.080 W 0.00m 0.00m 0.00m 0.00m", "\x00\x00\x00\x00\x8a\xfc\x80\x00\x7f\x87\x12\xa8\x00\x98\x96\x80"))
+     (CASE_L(QType::LOC, "51 11 59.999 N 2 12 5.080 W 0.00m 0.00m 0.00m 0.00m", "51 11 59.999 N 2 12 5.080 W 0.00m 0.00m 0.00m 0.00m", "\x00\x00\x00\x00\x8a\xfc\x7f\xff\x7f\x87\x12\xa8\x00\x98\x96\x80"))
+     (CASE_L(QType::LOC, "49 18 0.000 N 10 35 0.000 E 409.00m 1.00m 10000.00m 10.00m", "49 18 0.000 N 10 35 0.000 E 409.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x8a\x94\x21\x40\x82\x45\x5c\x20\x00\x99\x36\x44"))
+     (CASE_L(QType::LOC, "49 18 0.000 S 10 35 0.000 W 409.00m 1.00m 10000.00m 10.00m", "49 18 0.000 S 10 35 0.000 W 409.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x75\x6b\xde\xc0\x7d\xba\xa3\xe0\x00\x99\x36\x44"))
      (CASE_S(QType::SRV, "10 10 5060 sip.rec.test.", "\x00\x0a\x00\x0a\x13\xc4\x03sip\x03rec\x04test\x00"))
 // non-local name
      (CASE_S(QType::SRV, "10 10 5060 sip.example.com.", "\x00\x0a\x00\x0a\x13\xc4\x03sip\x07""example\x03""com\x00"))