You can subscribe to this list here.
| 2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(28) |
Nov
(193) |
Dec
(199) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2011 |
Jan
(214) |
Feb
(133) |
Mar
(81) |
Apr
(67) |
May
(101) |
Jun
(141) |
Jul
(134) |
Aug
(168) |
Sep
(153) |
Oct
(200) |
Nov
(137) |
Dec
(185) |
| 2012 |
Jan
(168) |
Feb
(153) |
Mar
(155) |
Apr
(183) |
May
(145) |
Jun
(166) |
Jul
(264) |
Aug
(285) |
Sep
(247) |
Oct
(108) |
Nov
(224) |
Dec
(193) |
| 2013 |
Jan
(173) |
Feb
(161) |
Mar
(205) |
Apr
(86) |
May
(81) |
Jun
(115) |
Jul
(115) |
Aug
(89) |
Sep
(83) |
Oct
(155) |
Nov
(123) |
Dec
(111) |
| 2014 |
Jan
(152) |
Feb
(180) |
Mar
(184) |
Apr
(106) |
May
(106) |
Jun
(144) |
Jul
(95) |
Aug
(109) |
Sep
(75) |
Oct
(75) |
Nov
(90) |
Dec
(64) |
| 2015 |
Jan
(59) |
Feb
(114) |
Mar
(64) |
Apr
(73) |
May
(113) |
Jun
(129) |
Jul
(127) |
Aug
(150) |
Sep
(127) |
Oct
(77) |
Nov
(178) |
Dec
(98) |
| 2016 |
Jan
(154) |
Feb
(151) |
Mar
(128) |
Apr
(62) |
May
(185) |
Jun
(120) |
Jul
(105) |
Aug
(91) |
Sep
(90) |
Oct
(165) |
Nov
(299) |
Dec
(203) |
| 2017 |
Jan
(184) |
Feb
(187) |
Mar
(209) |
Apr
(142) |
May
(189) |
Jun
(96) |
Jul
(54) |
Aug
(79) |
Sep
(151) |
Oct
(77) |
Nov
(142) |
Dec
(142) |
| 2018 |
Jan
(194) |
Feb
(175) |
Mar
(111) |
Apr
(85) |
May
(114) |
Jun
(205) |
Jul
(159) |
Aug
(102) |
Sep
(238) |
Oct
(179) |
Nov
(92) |
Dec
(76) |
| 2019 |
Jan
(199) |
Feb
(85) |
Mar
(100) |
Apr
(118) |
May
(80) |
Jun
(69) |
Jul
(91) |
Aug
(91) |
Sep
(137) |
Oct
(59) |
Nov
(82) |
Dec
(70) |
| 2020 |
Jan
(56) |
Feb
(70) |
Mar
(258) |
Apr
(385) |
May
(249) |
Jun
(344) |
Jul
(169) |
Aug
(362) |
Sep
(185) |
Oct
(416) |
Nov
(465) |
Dec
(267) |
| 2021 |
Jan
(279) |
Feb
(312) |
Mar
(378) |
Apr
(230) |
May
(150) |
Jun
(229) |
Jul
(358) |
Aug
(184) |
Sep
(155) |
Oct
(67) |
Nov
(98) |
Dec
(240) |
| 2022 |
Jan
(231) |
Feb
(215) |
Mar
(206) |
Apr
(144) |
May
(71) |
Jun
(18) |
Jul
(27) |
Aug
(66) |
Sep
(95) |
Oct
(65) |
Nov
(95) |
Dec
(76) |
| 2023 |
Jan
(149) |
Feb
(70) |
Mar
(84) |
Apr
(116) |
May
(218) |
Jun
(22) |
Jul
(15) |
Aug
(33) |
Sep
(93) |
Oct
(65) |
Nov
(43) |
Dec
(51) |
| 2024 |
Jan
(87) |
Feb
(84) |
Mar
(64) |
Apr
(33) |
May
(27) |
Jun
(107) |
Jul
(12) |
Aug
(16) |
Sep
(94) |
Oct
(472) |
Nov
(344) |
Dec
(185) |
| 2025 |
Jan
(244) |
Feb
(110) |
Mar
(135) |
Apr
(46) |
May
(50) |
Jun
(73) |
Jul
(74) |
Aug
(63) |
Sep
(55) |
Oct
(82) |
Nov
(39) |
Dec
(22) |
| 2026 |
Jan
(58) |
Feb
(47) |
Mar
(63) |
Apr
(89) |
May
(32) |
Jun
(33) |
Jul
(18) |
Aug
(13) |
Sep
|
Oct
|
Nov
|
Dec
|
|
From: <fli...@li...> - 2026-08-07 10:13:05
|
unknown user pushed a commit to branch next
in repository flightgear.
The following commit(s) were added to refs/heads/next by this push:
new 141fb82f9 Implement user sorting
141fb82f9 is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/141fb82f9c00be28c06b854884e84095ca032dcb/
Commit: 141fb82f9c00be28c06b854884e84095ca032dcb
Author: James Turner
Committer: James Turner
AuthorDate: Fri Aug 7 11:12:55 2026 +0100
Implement user sorting
---
src/GUI/AircraftFavouritesModel.cxx | 14 +-----
src/GUI/AircraftFavouritesModel.hxx | 3 --
src/GUI/AircraftFilterModel.cxx | 70 +++++++++++-----------------
src/GUI/AircraftFilterModel.hxx | 11 +----
src/GUI/AircraftInstalledModel.cxx | 14 +-----
src/GUI/AircraftInstalledModel.hxx | 5 +-
src/GUI/AircraftItemModel.hxx | 1 +
src/GUI/AircraftRatingsProxyModel.cxx | 33 +++++++++++++
src/GUI/AircraftRatingsProxyModel.hxx | 24 ++++++++++
src/GUI/AircraftUpdatesModel.cxx | 12 -----
src/GUI/AircraftUpdatesModel.hxx | 3 --
src/GUI/CMakeLists.txt | 2 +
src/GUI/LauncherController.cxx | 39 ++++++++++++++--
src/GUI/LauncherController.hxx | 7 +++
src/GUI/QmlStringListModel.cxx | 22 +++++++++
src/GUI/QmlStringListModel.hxx | 8 ++++
src/GUI/assets/mask-star-filled.png | Bin 479 -> 0 bytes
src/GUI/assets/mask-star-outline.png | Bin 544 -> 0 bytes
src/GUI/assets/tabler-mask-star-filled.svg | 3 ++
src/GUI/assets/tabler-mask-star-outline.svg | 3 ++
src/GUI/qml/AircraftCompactDelegate.qml | 35 ++++++++++----
src/GUI/qml/AircraftGridView.qml | 7 ++-
src/GUI/qml/AircraftListView.qml | 3 +-
src/GUI/qml/AircraftRating.qml | 63 +++++++++++++++----------
src/GUI/qml/AircraftRatingsPanel.qml | 17 +++++++
src/GUI/resources.qrc | 6 ++-
26 files changed, 262 insertions(+), 143 deletions(-)
diff --git a/src/GUI/AircraftFavouritesModel.cxx b/src/GUI/AircraftFavouritesModel.cxx
index d9b0c56aa..539b23366 100644
--- a/src/GUI/AircraftFavouritesModel.cxx
+++ b/src/GUI/AircraftFavouritesModel.cxx
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2020 James Turner
+// SPDX-FileCopyrightText: 2026 James Turner
// SPDX-License-Identifier: GPL-2.0-or-later
#include "AircraftFavouritesModel.hxx"
@@ -18,18 +18,6 @@ AircraftFavouritesModel::AircraftFavouritesModel(QObject* pr, QAbstractItemModel
[this]() { this->invalidate(); });
}
-int AircraftFavouritesModel::indexForURI(QUrl uri) const
-{
- auto srcIdx = qobject_cast<AircraftItemModel*>(sourceModel())->indexOfAircraftURI(uri);
- auto ourIdx = mapFromSource(srcIdx);
- return ourIdx.isValid() ? ourIdx.row() : -1;
-}
-
-void AircraftFavouritesModel::selectVariantForAircraftURI(QUrl uri)
-{
- qobject_cast<AircraftItemModel*>(sourceModel())->selectVariantForAircraftURI(uri);
-}
-
int AircraftFavouritesModel::count() const
{
return rowCount();
diff --git a/src/GUI/AircraftFavouritesModel.hxx b/src/GUI/AircraftFavouritesModel.hxx
index 77a901bdb..a3e7ff000 100644
--- a/src/GUI/AircraftFavouritesModel.hxx
+++ b/src/GUI/AircraftFavouritesModel.hxx
@@ -20,9 +20,6 @@ public:
Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_INVOKABLE int indexForURI(QUrl uri) const;
- Q_INVOKABLE void selectVariantForAircraftURI(QUrl uri);
-
int count() const;
signals:
diff --git a/src/GUI/AircraftFilterModel.cxx b/src/GUI/AircraftFilterModel.cxx
index 7b4bfc953..d6b7f471e 100644
--- a/src/GUI/AircraftFilterModel.cxx
+++ b/src/GUI/AircraftFilterModel.cxx
@@ -25,15 +25,23 @@ AircraftFilterModel::AircraftFilterModel(QObject* pr, QAbstractItemModel* source
AircraftItemModel* AircraftFilterModel::resolveItemModel() const
{
- auto* itemModel = qobject_cast<AircraftItemModel*>(sourceModel());
- if (!itemModel) {
- // Source is a proxy (e.g. AircraftSearchModel); look one level deeper.
- auto* proxySource = qobject_cast<QAbstractProxyModel*>(sourceModel());
- Q_ASSERT(proxySource);
- itemModel = qobject_cast<AircraftItemModel*>(proxySource->sourceModel());
+ auto m = sourceModel();
+ while (m) {
+ auto* itemModel = qobject_cast<AircraftItemModel*>(m);
+ if (itemModel) {
+ return itemModel;
+ }
+
+ auto pm = qobject_cast<QAbstractProxyModel*>(m);
+ if (!pm) {
+ break;
+ }
+
+ m = pm->sourceModel();
}
- Q_ASSERT(itemModel);
- return itemModel;
+
+ qFatal("AircraftFilterModel::resolveItemModel() failed to find AircraftItemModel in the source model chain");
+ return nullptr;
}
void AircraftFilterModel::setRatings(QList<int> ratings)
@@ -46,36 +54,6 @@ void AircraftFilterModel::setRatings(QList<int> ratings)
emit summaryTextChanged();
}
-int AircraftFilterModel::indexForURI(QUrl uri) const
-{
- auto* itemModel = qobject_cast<AircraftItemModel*>(sourceModel());
- QModelIndex sourceIdx;
-
- if (itemModel) {
- // Direct chain: AircraftItemModel → AircraftFilterModel
- sourceIdx = mapFromSource(itemModel->indexOfAircraftURI(uri));
- } else {
- // Indirect chain through a proxy (e.g. AircraftSearchModel)
- auto* proxySource = qobject_cast<QAbstractProxyModel*>(sourceModel());
- Q_ASSERT(proxySource);
- itemModel = qobject_cast<AircraftItemModel*>(proxySource->sourceModel());
- Q_ASSERT(itemModel);
- auto proxyIdx = proxySource->mapFromSource(itemModel->indexOfAircraftURI(uri));
- sourceIdx = mapFromSource(proxyIdx);
- }
-
- if (!sourceIdx.isValid()) {
- return -1;
- }
-
- return sourceIdx.row();
-}
-
-void AircraftFilterModel::selectVariantForAircraftURI(QUrl uri)
-{
- resolveItemModel()->selectVariantForAircraftURI(uri);
-}
-
void AircraftFilterModel::setRatingFilterEnabled(bool e)
{
if (e == m_ratingsFilter) {
@@ -179,7 +157,6 @@ void AircraftFilterModel::saveCompatibilityAndRatingsSettings()
vRatings.append(m_ratings.at(i));
}
settings.setValue("ratings-filter", vRatings);
- qInfo() << "Did save ratings";
}
int AircraftFilterModel::filteredOutCount() const
@@ -205,23 +182,32 @@ void AircraftFilterModel::setSorting(Sorting s)
void AircraftFilterModel::updateSorting()
{
+ auto order = Qt::AscendingOrder;
switch (m_sorting) {
case Sorting::SortByName:
setSortRole(AircraftVariantDescriptionRole);
setSortCaseSensitivity(Qt::CaseInsensitive);
+
break;
case Sorting::SortByRating:
- setSortRole(AircraftRatingRole);
- setSortCaseSensitivity(Qt::CaseSensitive); // doesn't matter, it's an int
+ setSortRole(AircraftCombinedRatingRole);
+ // highest-rated at the top
+ order = Qt::DescendingOrder;
break;
}
setDynamicSortFilter(true);
- sort(0);
+ sort(0, order);
}
bool AircraftFilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
{
+ if (m_sorting == Sorting::SortByRating) {
+ // use default impl
+ return QSortFilterProxyModel::lessThan(left, right);
+ }
+
+ // custom imply for SortByName
const QString variantLeft = left.data(AircraftVariantDescriptionRole).toString();
const QString variantRight = right.data(AircraftVariantDescriptionRole).toString();
diff --git a/src/GUI/AircraftFilterModel.hxx b/src/GUI/AircraftFilterModel.hxx
index 409e1a46b..b7133bb91 100644
--- a/src/GUI/AircraftFilterModel.hxx
+++ b/src/GUI/AircraftFilterModel.hxx
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2020 James Turner
+// SPDX-FileCopyrightText: 2026 James Turner
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -44,15 +44,6 @@ public:
Q_PROPERTY(Sorting sorting READ sorting WRITE setSorting NOTIFY sortingChanged)
- /**
- * Compute the row (index in QML / ListView speak) based on an aircraft URI.
- * Returns -1 if the URI is not present in the (filtered) model.
- * Handles both direct AircraftItemModel sources and proxy-chained sources.
- */
- Q_INVOKABLE int indexForURI(QUrl uri) const;
-
- Q_INVOKABLE void selectVariantForAircraftURI(QUrl uri);
-
Q_INVOKABLE void loadCompatibilityAndRatingsSettings();
Q_INVOKABLE void saveCompatibilityAndRatingsSettings();
diff --git a/src/GUI/AircraftInstalledModel.cxx b/src/GUI/AircraftInstalledModel.cxx
index 900ea2852..ada96c639 100644
--- a/src/GUI/AircraftInstalledModel.cxx
+++ b/src/GUI/AircraftInstalledModel.cxx
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2020 James Turner
+// SPDX-FileCopyrightText: 2026 James Turner
// SPDX-License-Identifier: GPL-2.0-or-later
#include "AircraftInstalledModel.hxx"
@@ -14,18 +14,6 @@ AircraftInstalledModel::AircraftInstalledModel(QObject* pr, QAbstractItemModel*
connect(this, &QAbstractItemModel::modelReset, this, &AircraftInstalledModel::countChanged);
}
-int AircraftInstalledModel::indexForURI(QUrl uri) const
-{
- auto srcIdx = qobject_cast<AircraftItemModel*>(sourceModel())->indexOfAircraftURI(uri);
- auto ourIdx = mapFromSource(srcIdx);
- return ourIdx.isValid() ? ourIdx.row() : -1;
-}
-
-void AircraftInstalledModel::selectVariantForAircraftURI(QUrl uri)
-{
- qobject_cast<AircraftItemModel*>(sourceModel())->selectVariantForAircraftURI(uri);
-}
-
int AircraftInstalledModel::count() const
{
return rowCount();
diff --git a/src/GUI/AircraftInstalledModel.hxx b/src/GUI/AircraftInstalledModel.hxx
index 2d1219478..4da0f7b11 100644
--- a/src/GUI/AircraftInstalledModel.hxx
+++ b/src/GUI/AircraftInstalledModel.hxx
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2020 James Turner
+// SPDX-FileCopyrightText: 2026 James Turner
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -19,9 +19,6 @@ public:
Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_INVOKABLE int indexForURI(QUrl uri) const;
- Q_INVOKABLE void selectVariantForAircraftURI(QUrl uri);
-
int count() const;
signals:
diff --git a/src/GUI/AircraftItemModel.hxx b/src/GUI/AircraftItemModel.hxx
index 44006dc93..5810dcd71 100644
--- a/src/GUI/AircraftItemModel.hxx
+++ b/src/GUI/AircraftItemModel.hxx
@@ -40,6 +40,7 @@ const int AircraftStatusRole = Qt::UserRole + 22;
const int AircraftCompatibleRole = Qt::UserRole + 23;
const int AircraftRatingRole = Qt::UserRole + 100;
+const int AircraftCombinedRatingRole = Qt::UserRole + 150;
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
class PackageDelegate;
diff --git a/src/GUI/AircraftRatingsProxyModel.cxx b/src/GUI/AircraftRatingsProxyModel.cxx
new file mode 100644
index 000000000..dc17c40f5
--- /dev/null
+++ b/src/GUI/AircraftRatingsProxyModel.cxx
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "AircraftRatingsProxyModel.hxx"
+
+#include "AircraftItemModel.hxx"
+
+AircraftRatingsProxyModel::AircraftRatingsProxyModel(QObject* parent)
+ : QSortFilterProxyModel(parent)
+{
+}
+
+QVariant AircraftRatingsProxyModel::data(const QModelIndex& index, int role) const
+{
+ if (role == AircraftCombinedRatingRole) {
+ QModelIndex srcIndex = mapToSource(index);
+ double sum = 0;
+ for (int i = 0; i < 4; ++i) {
+ QVariant v = sourceModel()->data(srcIndex, AircraftRatingRole + i);
+ sum += v.toDouble();
+ }
+ return sum / 4.0;
+ }
+
+ return QSortFilterProxyModel::data(index, role);
+}
+
+QHash<int, QByteArray> AircraftRatingsProxyModel::roleNames() const
+{
+ QHash<int, QByteArray> roles = QSortFilterProxyModel::roleNames();
+ roles[AircraftCombinedRatingRole] = "combinedRating";
+ return roles;
+}
diff --git a/src/GUI/AircraftRatingsProxyModel.hxx b/src/GUI/AircraftRatingsProxyModel.hxx
new file mode 100644
index 000000000..12b70157b
--- /dev/null
+++ b/src/GUI/AircraftRatingsProxyModel.hxx
@@ -0,0 +1,24 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <QSortFilterProxyModel>
+
+/**
+ * Proxy model that adds a combined/average rating to each aircraft row.
+ *
+ * The combined rating is computed from the four existing ratings
+ * (AircraftRatingRole .. AircraftRatingRole+3) and exposed via
+ * AircraftCombinedRatingRole.
+ */
+class AircraftRatingsProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ explicit AircraftRatingsProxyModel(QObject* parent = nullptr);
+
+ QVariant data(const QModelIndex& index, int role) const override;
+
+ QHash<int, QByteArray> roleNames() const override;
+};
diff --git a/src/GUI/AircraftUpdatesModel.cxx b/src/GUI/AircraftUpdatesModel.cxx
index ba57f2d2f..69cfae236 100644
--- a/src/GUI/AircraftUpdatesModel.cxx
+++ b/src/GUI/AircraftUpdatesModel.cxx
@@ -14,18 +14,6 @@ AircraftUpdatesModel::AircraftUpdatesModel(QObject* pr, QAbstractItemModel* sour
connect(this, &QAbstractItemModel::modelReset, this, &AircraftUpdatesModel::countChanged);
}
-int AircraftUpdatesModel::indexForURI(QUrl uri) const
-{
- auto srcIdx = qobject_cast<AircraftItemModel*>(sourceModel())->indexOfAircraftURI(uri);
- auto ourIdx = mapFromSource(srcIdx);
- return ourIdx.isValid() ? ourIdx.row() : -1;
-}
-
-void AircraftUpdatesModel::selectVariantForAircraftURI(QUrl uri)
-{
- qobject_cast<AircraftItemModel*>(sourceModel())->selectVariantForAircraftURI(uri);
-}
-
int AircraftUpdatesModel::count() const
{
return rowCount();
diff --git a/src/GUI/AircraftUpdatesModel.hxx b/src/GUI/AircraftUpdatesModel.hxx
index 34bef136d..fc7644608 100644
--- a/src/GUI/AircraftUpdatesModel.hxx
+++ b/src/GUI/AircraftUpdatesModel.hxx
@@ -19,9 +19,6 @@ public:
Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_INVOKABLE int indexForURI(QUrl uri) const;
- Q_INVOKABLE void selectVariantForAircraftURI(QUrl uri);
-
int count() const;
signals:
diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt
index a1c752f88..cf9021b4a 100644
--- a/src/GUI/CMakeLists.txt
+++ b/src/GUI/CMakeLists.txt
@@ -120,6 +120,8 @@ if (HAVE_QT)
AircraftFavouritesModel.hxx
AircraftFilterModel.cxx
AircraftFilterModel.hxx
+ AircraftRatingsProxyModel.cxx
+ AircraftRatingsProxyModel.hxx
AircraftInstalledModel.cxx
AircraftInstalledModel.hxx
AircraftSearchModel.cxx
diff --git a/src/GUI/LauncherController.cxx b/src/GUI/LauncherController.cxx
index 54cf1ff18..3a9d51598 100644
--- a/src/GUI/LauncherController.cxx
+++ b/src/GUI/LauncherController.cxx
@@ -41,8 +41,10 @@
#include "AircraftFavouritesModel.hxx"
#include "AircraftFilterModel.hxx"
#include "AircraftItemModel.hxx"
+#include "AircraftRatingsProxyModel.hxx"
#include "AircraftSearchModel.hxx"
#include "AircraftUpdatesModel.hxx"
+
#include "AirportDiagram.hxx"
#include "CarrierDiagram.hxx"
#include "CarriersLocationModel.hxx"
@@ -110,14 +112,16 @@ LauncherController::LauncherController(QObject *parent, QWindow* window) :
this, &LauncherController::summaryChanged);
m_aircraftModel = new AircraftItemModel(this);
+ auto ratingsProxy = new AircraftRatingsProxyModel(this);
+ ratingsProxy->setSourceModel(m_aircraftModel);
- m_aircraftInstalledModel = new AircraftInstalledModel(this, m_aircraftModel);
- m_aircraftWithUpdatesModel = new AircraftUpdatesModel(this, m_aircraftModel);
- m_favouriteAircraftModel = new AircraftFavouritesModel(this, m_aircraftModel);
+ m_aircraftInstalledModel = new AircraftInstalledModel(this, ratingsProxy);
+ m_aircraftWithUpdatesModel = new AircraftUpdatesModel(this, ratingsProxy);
+ m_favouriteAircraftModel = new AircraftFavouritesModel(this, ratingsProxy);
// m_aircraftSearchModel sits between the base model and the filter model,
// allowing text-based searching and rating/compat filtering to be separated.
- m_aircraftSearchModel = new AircraftSearchModel(this, m_aircraftModel);
+ m_aircraftSearchModel = new AircraftSearchModel(this, ratingsProxy);
// Single filter model; its source is swapped by setSelectedModel().
// Initial state is "installed" (the default QML tab).
@@ -1094,3 +1098,30 @@ void LauncherController::onReachabilityChanged()
emit networkAvailableChanged();
#endif
}
+
+int LauncherController::selectedAircraftIndex(QAbstractItemModel* model)
+{
+ if (!m_selectedAircraftInfo) {
+ return -1;
+ }
+
+ // hit the base case, stop descending
+ AircraftItemModel* itemModel = qobject_cast<AircraftItemModel*>(model);
+ if (itemModel) {
+ QModelIndex idx = itemModel->indexOfAircraftURI(m_selectedAircraft);
+ if (idx.isValid()) {
+ itemModel->selectVariantForAircraftURI(m_selectedAircraft);
+ return idx.row();
+ }
+
+ return -1;
+ }
+
+ auto* proxy = qobject_cast<QAbstractProxyModel*>(model);
+ if (!proxy) {
+ return -1; // should never happen
+ }
+
+ // recurse into the proxy
+ return selectedAircraftIndex(proxy->sourceModel());
+}
diff --git a/src/GUI/LauncherController.hxx b/src/GUI/LauncherController.hxx
index 03089fbc2..6ef007ae0 100644
--- a/src/GUI/LauncherController.hxx
+++ b/src/GUI/LauncherController.hxx
@@ -120,6 +120,13 @@ public:
Q_INVOKABLE bool matchesSearch(QString term, QStringList keywords) const;
+ /**
+ * given a (proxy) model, find the row which corresponds to selectedAircraft.
+ *
+ * Also sets the active variant of the underlying model
+ */
+ Q_INVOKABLE int selectedAircraftIndex(QAbstractItemModel* model);
+
bool isSearchActive() const;
QString settingsSearchTerm() const
diff --git a/src/GUI/QmlStringListModel.cxx b/src/GUI/QmlStringListModel.cxx
index 4f5aca6f4..61d81b057 100644
--- a/src/GUI/QmlStringListModel.cxx
+++ b/src/GUI/QmlStringListModel.cxx
@@ -20,6 +20,7 @@ void QmlStringListModel::setValues(QStringList v)
beginResetModel();
m_values = v;
endResetModel();
+ emit valuesChanged();
}
QStringList QmlStringListModel::values() const
@@ -27,6 +28,19 @@ QStringList QmlStringListModel::values() const
return m_values;
}
+void QmlStringListModel::setKeys(QVariantList v)
+{
+ beginResetModel();
+ m_keys = v;
+ endResetModel();
+ emit keysChanged();
+}
+
+QVariantList QmlStringListModel::keys() const
+{
+ return m_keys;
+}
+
int QmlStringListModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
@@ -53,10 +67,18 @@ void QmlStringListModel::clear()
{
beginResetModel();
m_values.clear();
+ m_keys.clear();
endResetModel();
+ emit valuesChanged();
+ emit keysChanged();
}
bool QmlStringListModel::empty() const
{
return m_values.isEmpty();
}
+
+int QmlStringListModel::indexOfKey(const QVariant& key) const
+{
+ return m_keys.indexOf(key);
+}
diff --git a/src/GUI/QmlStringListModel.hxx b/src/GUI/QmlStringListModel.hxx
index f39f6256b..ffb4205d7 100644
--- a/src/GUI/QmlStringListModel.hxx
+++ b/src/GUI/QmlStringListModel.hxx
@@ -14,6 +14,8 @@ class QmlStringListModel : public QAbstractListModel
Q_OBJECT
Q_PROPERTY(QStringList values READ values WRITE setValues NOTIFY valuesChanged)
+ Q_PROPERTY(QVariantList keys READ keys WRITE setKeys NOTIFY keysChanged)
+
Q_PROPERTY(bool empty READ empty NOTIFY valuesChanged)
public:
QmlStringListModel(QObject* parent = nullptr);
@@ -22,6 +24,8 @@ public:
void setValues(QStringList v);
QStringList values() const;
+ void setKeys(QVariantList v);
+ QVariantList keys() const;
int rowCount(const QModelIndex& parent) const override;
@@ -32,9 +36,13 @@ public:
void clear();
bool empty() const;
+
+ Q_INVOKABLE int indexOfKey(const QVariant& key) const;
signals:
void valuesChanged();
+ void keysChanged();
private:
QStringList m_values;
+ QVariantList m_keys;
};
diff --git a/src/GUI/assets/mask-star-filled.png b/src/GUI/assets/mask-star-filled.png
deleted file mode 100644
index 1ee4f8e53..000000000
Binary files a/src/GUI/assets/mask-star-filled.png and /dev/null differ
diff --git a/src/GUI/assets/mask-star-outline.png b/src/GUI/assets/mask-star-outline.png
deleted file mode 100644
index 6c9846e1d..000000000
Binary files a/src/GUI/assets/mask-star-outline.png and /dev/null differ
diff --git a/src/GUI/assets/tabler-mask-star-filled.svg b/src/GUI/assets/tabler-mask-star-filled.svg
new file mode 100644
index 000000000..937eceb30
--- /dev/null
+++ b/src/GUI/assets/tabler-mask-star-filled.svg
@@ -0,0 +1,3 @@
+<!-- SPDX-FileCopyrightText: Tabler Icons Contributors -->
+<!-- SPDX-License-Identifier: MIT -->
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="#ffffff" class="icon icon-tabler icons-tabler-filled icon-tabler-star"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M8.243 7.34l-6.38 .925l-.113 .023a1 1 0 0 0 -.44 1.684l4.622 4.499l-1.09 6.355l-.013 .11a1 1 0 0 0 1.464 .944l5.706 -3l5.693 3l.1 .046a1 1 0 0 0 1.352 -1.1l-1.091 -6.355l4.624 -4.5l.078 -.085a1 1 0 0 0 -.633 -1.62l-6.38 -.926l-2.852 -5.78a1 1 0 0 0 -1.794 0l-2.853 5.78z" [...]
diff --git a/src/GUI/assets/tabler-mask-star-outline.svg b/src/GUI/assets/tabler-mask-star-outline.svg
new file mode 100644
index 000000000..32f98ca1b
--- /dev/null
+++ b/src/GUI/assets/tabler-mask-star-outline.svg
@@ -0,0 +1,3 @@
+<!-- SPDX-FileCopyrightText: Tabler Icons Contributors -->
+<!-- SPDX-License-Identifier: MIT -->
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-star"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873l-6.158 -3.245" /></svg>
diff --git a/src/GUI/qml/AircraftCompactDelegate.qml b/src/GUI/qml/AircraftCompactDelegate.qml
index fb3c62713..3937d3c7a 100644
--- a/src/GUI/qml/AircraftCompactDelegate.qml
+++ b/src/GUI/qml/AircraftCompactDelegate.qml
@@ -147,16 +147,33 @@ Item {
visible: (model.description !== "") || root.__showAlternateText
}
- AircraftDownloadPanel
- {
- id: downloadPanel
- visible: (model.package !== undefined)
- packageSize: model.packageSizeBytes
- installStatus: model.packageStatus
- downloadedBytes: model.downloadedBytes
- uri: model.uri
+ Row {
width: parent.width
- compact: true
+ height: Math.max(combinedRating.height, downloadPanel.height)
+ spacing: Style.margin
+
+ AircraftRating
+ {
+ id: combinedRating
+ showValue: true
+ title: qsTr("Rating")
+ anchors.verticalCenter: parent.verticalCenter
+ value: model.combinedRating
+ }
+
+ AircraftDownloadPanel
+ {
+ id: downloadPanel
+ visible: (model.package !== undefined)
+ packageSize: model.packageSizeBytes
+ installStatus: model.packageStatus
+ downloadedBytes: model.downloadedBytes
+ uri: model.uri
+ compact: true
+
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width - (combinedRating.width + Style.margin)
+ }
}
} // of content column
diff --git a/src/GUI/qml/AircraftGridView.qml b/src/GUI/qml/AircraftGridView.qml
index 7676e4a2d..cd293912f 100644
--- a/src/GUI/qml/AircraftGridView.qml
+++ b/src/GUI/qml/AircraftGridView.qml
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2018 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
import QtQuick 2.0
import QtQuick.Controls 2.2
@@ -17,7 +20,7 @@ Item {
if (!model)
return;
- var row = model.indexForURI(_launcher.selectedAircraft);
+ var row = _launcher.findSelectedAircraftIndex(model)
if (row >= 0) {
view.currentIndex = row;
} else {
@@ -44,7 +47,7 @@ Item {
cellWidth: width / colCount
cellHeight: 128 + Style.strutSize
highlightMoveDuration: 0
-
+
ScrollBar.vertical: ScrollBar {}
readonly property int baseCellWidth: 172 + (Style.strutSize * 2)
diff --git a/src/GUI/qml/AircraftListView.qml b/src/GUI/qml/AircraftListView.qml
index ea7538b6e..20edd24db 100644
--- a/src/GUI/qml/AircraftListView.qml
+++ b/src/GUI/qml/AircraftListView.qml
@@ -20,8 +20,7 @@ Item {
if (!model)
return;
- model.selectVariantForAircraftURI(_launcher.selectedAircraft);
- var row = model.indexForURI(_launcher.selectedAircraft);
+ var row = _launcher.selectedAircraftIndex(model)
if (row >= 0) {
// sequence here is necessary so programmatic moves
// are instant
diff --git a/src/GUI/qml/AircraftRating.qml b/src/GUI/qml/AircraftRating.qml
index 24fb81c9f..4671e4e2b 100644
--- a/src/GUI/qml/AircraftRating.qml
+++ b/src/GUI/qml/AircraftRating.qml
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2018 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
import QtQuick 2.4
import FlightGear 1.0
@@ -5,38 +8,50 @@ Item {
id: root
property string title: ""
- property int value: 3
-
- implicitWidth: label.implicitWidth + ratingRow.implicitWidth + Style.margin
- implicitHeight: label.height
+ property double value: 3
- StyledText {
- id: label
- anchors.right: ratingRow.left
- anchors.rightMargin: Style.margin
- anchors.left: parent.left
+ property alias showValue: ratingValue.visible
- horizontalAlignment: Text.AlignRight
- text: root.title + ":"
- }
+ implicitWidth: childrenRect.width
+ implicitHeight: Math.max(label.height, 24)
Row {
- id: ratingRow
+ id: contentRow
+ spacing: Style.margin
+
+ StyledText {
+ id: label
+ anchors.verticalCenter: parent.verticalCenter
+
+ horizontalAlignment: Text.AlignRight
+ text: root.title + ":"
+ }
+
+ Row {
+ id: ratingRow
- spacing: 2
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
+ spacing: 0 // keep this really tight
+ anchors.verticalCenter: parent.verticalCenter
- Repeater {
- model: 5
+ Repeater {
+ model: 5
- delegate: Rectangle {
- color: ((model.index + 1) <= root.value) ? Style.themeColor : Style.disabledTextColor
- width: radius * 2
- height: radius * 2
- radius: Style.roundRadius
+ delegate: Image {
+ source: {
+ var b = (model.index + 1) <= root.value;
+ return b ? "image://colored-icon/star-filled?theme" : "image://colored-icon/star-outline?text";
+ }
+ }
}
}
- }
+ StyledText {
+ id: ratingValue
+ visible: false // hidden by default
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignLeft
+ text: "(" + Number(root.value).toLocaleString(null, 'f', 2) + ")"
+ width: Style.strutSize
+ }
+ }
}
diff --git a/src/GUI/qml/AircraftRatingsPanel.qml b/src/GUI/qml/AircraftRatingsPanel.qml
index a50004d74..1850f7774 100644
--- a/src/GUI/qml/AircraftRatingsPanel.qml
+++ b/src/GUI/qml/AircraftRatingsPanel.qml
@@ -35,6 +35,23 @@ Rectangle
anchors.horizontalCenter: parent.horizontalCenter
}
+ PopupChoice {
+ id: sortChoice
+ model: StringListModel{
+ values: [qsTr("By name"), qsTr("By rating")]
+ keys: [FG.AircraftFilterModel.SortByName, FG.AircraftFilterModel.SortByRating]
+ }
+
+ currentIndex: model.indexOfKey(_launcher.currentAircraftModel.sorting)
+ onCurrentIndexChanged: {
+ _launcher.currentAircraftModel.sorting = model.keys[currentIndex]
+ }
+
+ label: qsTr("Sort aircraft by: ")
+ width: parent.width - Style.inset
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
ToggleSwitch {
id: doCompatibilityCheck
checked: _launcher.currentAircraftModel.compatibilityFilterEnabled
diff --git a/src/GUI/resources.qrc b/src/GUI/resources.qrc
index c6b00e31f..af42ac147 100644
--- a/src/GUI/resources.qrc
+++ b/src/GUI/resources.qrc
@@ -151,8 +151,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="hide">assets/mask-hide.png</file>
<file alias="preview">assets/mask-preview.png</file>
<file alias="up-down">assets/mask-up-down.png</file>
- <file alias="star-filled">assets/mask-star-filled.png</file>
- <file alias="star-outline">assets/mask-star-outline.png</file>
+
<file alias="back">assets/mask-back.png</file>
<file alias="cancel-small">assets/mask-cancel-small.png</file>
<file alias="reorder-list">assets/mask-reorder-list.png</file>
@@ -180,5 +179,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="heart-filled">assets/tabler-mask-heart-filled.svg</file>
<file alias="heart-outline">assets/tabler-mask-heart-outline.svg</file>
<file alias="heart-plus">assets/tabler-mask-heart-plus.svg</file>
+
+ <file alias="star-filled">assets/tabler-mask-star-filled.svg</file>
+ <file alias="star-outline">assets/tabler-mask-star-outline.svg</file>
</qresource>
</RCC>
|
|
From: <fli...@li...> - 2026-08-06 19:13:38
|
unknown user pushed a change to annotated tag 2024.1.7-rc2
in repository fgmeta.
at 9a3d09c (tag)
tagging c9c1b68ab02a91723efbd26e1d40d015aabfb84d (commit)
replaces 2024.1.7-rc1
by Automatic Release Builder
on Thu Aug 6 20:12:28 2026 +0100
- Log -----------------------------------------------------------------
Release version 2024.1.7-rc2
-----------------------------------------------------------------------
No new revisions were added by this update.
|
|
From: <fli...@li...> - 2026-08-06 19:12:37
|
unknown user pushed a change to annotated tag 2024.1.7-rc
in repository fgmeta.
at 04c1bda (tag)
tagging c9c1b68ab02a91723efbd26e1d40d015aabfb84d (commit)
replaces 2024.1.7-rc1
by Automatic Release Builder
on Thu Aug 6 20:12:04 2026 +0100
- Log -----------------------------------------------------------------
Release version 2024.1.7-rc2
-----------------------------------------------------------------------
No new revisions were added by this update.
|
|
From: <fli...@li...> - 2026-08-06 19:11:16
|
unknown user pushed a change to annotated tag 2024.1.7-rc2
in repository flightgear.
*** WARNING: tag 2024.1.7-rc2 was modified! ***
from 84065c6d8 (tag)
to ac4adb111 (tag)
tagging 783e4f6e529bdaee6dfe1b5d3cf973f911a35fbb (commit)
replaces 2024.1.7-rc1
by Automatic Release Builder
on Thu Aug 6 20:10:57 2026 +0100
- Log -----------------------------------------------------------------
Version 2024.1.7-rc2
-----------------------------------------------------------------------
No new revisions were added by this update.
Summary of changes:
|
|
From: <fli...@li...> - 2026-08-06 13:24:31
|
unknown user pushed a change to annotated tag 2024.1.7-rc1
in repository fgmeta.
at a2602dc (tag)
tagging 9a895fb31fd75bc807b2e5025dacbbb8bb925d1b (commit)
replaces 2024.1.6
by Automatic Release Builder
on Sun Aug 2 13:18:52 2026 +0100
- Log -----------------------------------------------------------------
Release version 2024.1.7-rc1
-----------------------------------------------------------------------
No new revisions were added by this update.
|
|
From: <fli...@li...> - 2026-08-04 19:13:29
|
unknown user pushed a commit to branch release/2024.1
in repository simgear.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new c903a7b7 New version: 2024.1.7-rc1
c903a7b7 is described below
SF URL: http://sourceforge.net/p/flightgear/simgear/ci/c903a7b790473f14e196fbec91d5ecd828f7d386/
Commit: c903a7b790473f14e196fbec91d5ecd828f7d386
Author: Automatic Release Builder
Committer: Automatic Release Builder
AuthorDate: Sun Aug 2 13:17:27 2026 +0100
New version: 2024.1.7-rc1
---
simgear-version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/simgear-version b/simgear-version
index b39be9db..8fc88123 100644
--- a/simgear-version
+++ b/simgear-version
@@ -1 +1 @@
-2024.1.6
+2024.1.7
|
|
From: <fli...@li...> - 2026-08-04 13:07:42
|
unknown user pushed a change to branch release/2024.1
in repository fgmeta.
from 77ec202 Update submodules for 2024.1.7
new ee4ea3c Update submodules
new 9a895fb New version: 2024.1.7-rc1
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
fgdata | 2 +-
flightgear | 2 +-
getstart | 2 +-
simgear | 2 +-
version | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
|
|
From: <fli...@li...> - 2026-08-04 13:07:03
|
unknown user pushed a commit to branch release/2024.1
in repository fgmeta.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new 3aae3e8 Set correct auth env variables for clone
3aae3e8 is described below
SF URL: http://sourceforge.net/p/flightgear/fgmeta/ci/3aae3e8c390f985f0b9e278e8a0697eb6c4b7c4f/
Commit: 3aae3e8c390f985f0b9e278e8a0697eb6c4b7c4f
Author: James Turner
Committer: James Turner
AuthorDate: Mon Aug 3 10:48:52 2026 +0100
Set correct auth env variables for clone
---
release_builder/create_base_package.sh | 3 +++
1 file changed, 3 insertions(+)
diff --git a/release_builder/create_base_package.sh b/release_builder/create_base_package.sh
index 198d28e..434d7c9 100755
--- a/release_builder/create_base_package.sh
+++ b/release_builder/create_base_package.sh
@@ -73,6 +73,7 @@ _end_
# expose the Bunny secret under the name that rclone expects when using env_auth=true
export AWS_SECRET_ACCESS_KEY=$BUNNY_FGDATA_SECRET
+export AWS_ACCESS_KEY=terrasync-fgdata
# rsync current dir-indexes, so we don't create new ones if contents have not changed. This
# is important since new dir index files get a comment which changes their SHA sum
@@ -109,11 +110,13 @@ scp $ZIP_OUTPUT_NAME jm...@de...:/var/www/download-flightgear/r
# juggle keys back and forth for auth :(
export AWS_SECRET_ACCESS_KEY=$BUNNY_DLDATA_SECRET
+export AWS_ACCESS_KEY=fgdata-download
rclone copy --progress "$OUTPUT_NAME" bunny-dldata:$DOWNLOAD_BUCKET/$FGDATA_NAME/
echo "Done uploading TXZ, now sync-ing files to the CDN"
export AWS_SECRET_ACCESS_KEY=$BUNNY_FGDATA_SECRET
+export AWS_ACCESS_KEY=terrasync-fgdata
# `--checksum` arg is important so we don't touch / modify unchanged files on the server side.
rclone sync --checksum --progress staging/$FGDATA_NAME bunny-fgdata:terrasync-fgdata/$FGDATA_NAME
|
|
From: <fli...@li...> - 2026-08-03 11:13:01
|
unknown user pushed a commit to branch next
in repository simgear.
The following commit(s) were added to refs/heads/next by this push:
new a14dd266 Fix a race in TS::isDirSyncing
a14dd266 is described below
SF URL: http://sourceforge.net/p/flightgear/simgear/ci/a14dd266526ef13b39110e58e888a0d101dace1e/
Commit: a14dd266526ef13b39110e58e888a0d101dace1e
Author: James Turner
Committer: James Turner
AuthorDate: Thu Jul 30 11:55:06 2026 +0100
Fix a race in TS::isDirSyncing
---
simgear/scene/tsync/terrasync.cxx | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/simgear/scene/tsync/terrasync.cxx b/simgear/scene/tsync/terrasync.cxx
index 0d6e646a..8dabe062 100644
--- a/simgear/scene/tsync/terrasync.cxx
+++ b/simgear/scene/tsync/terrasync.cxx
@@ -623,17 +623,23 @@ void SGTerraSync::WorkerThread::updateSyncSlot(SyncSlot &slot)
}
// whatever happened, we're done with this repository instance
- slot.busy = false;
- slot.repository.reset();
- slot.pendingKBytes = 0;
- slot.pendingExtractKBytes = 0;
- slot.currentItem = {};
+ {
+ std::lock_guard<std::mutex> g(_stateLock);
+ slot.busy = false;
+ slot.repository.reset();
+ slot.pendingKBytes = 0;
+ slot.pendingExtractKBytes = 0;
+ slot.currentItem = {};
+ }
}
// init and start sync of the next repository
if (!slot.queue.empty()) {
- slot.currentItem = slot.queue.front();
- slot.queue.pop_front();
+ {
+ std::lock_guard<std::mutex> g(_stateLock);
+ slot.currentItem = slot.queue.front();
+ slot.queue.pop_front();
+ }
SGPath path(_local_dir);
path.append(slot.currentItem._dir);
@@ -904,7 +910,10 @@ void SGTerraSync::WorkerThread::drainWaitingTiles()
SyncItem next = waitingTiles.pop_front();
const auto slot = syncSlotForType(next._type);
SG_LOG(SG_TERRASYNC, SG_DEBUG, "adding to _syncSlots slot=" << slot);
- _syncSlots[slot].queue.push_back(next);
+ {
+ std::lock_guard<std::mutex> g(_stateLock);
+ _syncSlots[slot].queue.push_back(next);
+ }
}
}
|
|
From: <fli...@li...> - 2026-08-02 12:19:00
|
unknown user pushed a commit to branch release/2024.1 in repository fgmeta. SF URL: http://sourceforge.net/p/flightgear/fgmeta/ci/ee4ea3cb4e7b00d80f30655c5219deba6afac925/ Commit: ee4ea3cb4e7b00d80f30655c5219deba6afac925 Author: Automatic Release Builder Committer: Automatic Release Builder AuthorDate: Sun Aug 2 13:16:58 2026 +0100 Update submodules --- getstart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getstart b/getstart index 3d405c2..da739ae 160000 --- a/getstart +++ b/getstart @@ -1 +1 @@ -Subproject commit 3d405c2543009e176ae16bd53993768e14bb483f +Subproject commit da739ae0857305595530144ce7246d1cd0d04681 |
|
From: <fli...@li...> - 2026-08-02 12:12:07
|
unknown user pushed a commit to branch release/2024.1
in repository simgear.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new 4e1687e3 Upgrade to Expat 2.8.2
4e1687e3 is described below
SF URL: http://sourceforge.net/p/flightgear/simgear/ci/4e1687e3da03200a94a1ecc941336023788d4902/
Commit: 4e1687e3da03200a94a1ecc941336023788d4902
Author: James Turner
Committer: James Turner
AuthorDate: Sun Aug 2 09:38:34 2026 +0100
Upgrade to Expat 2.8.2
---
.clang-format-ignore | 4 +
3rdparty/.clang-format | 3 +
3rdparty/expat/CMakeLists.txt | 22 +-
3rdparty/expat/expat_config_cmake.in | 85 +-
3rdparty/expat/{winconfig.h => fallthrough.h} | 28 +-
3rdparty/expat/{winconfig.h => memory_sanitizer.h} | 30 +-
.../expat/{winconfig.h => random_arc4random.c} | 35 +-
.../expat/{winconfig.h => random_arc4random.h} | 18 +-
.../expat/{winconfig.h => random_arc4random_buf.c} | 26 +-
.../expat/{winconfig.h => random_arc4random_buf.h} | 18 +-
.../expat/{winconfig.h => random_dev_urandom.c} | 51 +-
.../expat/{winconfig.h => random_dev_urandom.h} | 19 +-
.../expat/{winconfig.h => random_getentropy.c} | 45 +-
.../expat/{winconfig.h => random_getentropy.h} | 19 +-
3rdparty/expat/random_getrandom.c | 95 +
3rdparty/expat/{winconfig.h => random_getrandom.h} | 19 +-
3rdparty/expat/random_rand_s.c | 88 +
3rdparty/expat/{winconfig.h => random_rand_s.h} | 20 +-
3rdparty/expat/sg_expat.h | 126 +-
3rdparty/expat/sg_expat_external.h | 127 +-
3rdparty/expat/{internal.h => sg_expat_internal.h} | 38 +-
3rdparty/expat/siphash.h | 28 +-
3rdparty/expat/winconfig.h | 7 +-
3rdparty/expat/{winconfig.h => xcsinc.c} | 35 +-
3rdparty/expat/xmlparse.c | 3521 +++++++++++++-------
3rdparty/expat/xmlrole.c | 12 +-
3rdparty/expat/xmlrole.h | 40 +-
3rdparty/expat/xmltok.c | 57 +-
3rdparty/expat/xmltok.h | 234 +-
3rdparty/expat/xmltok_impl.c | 47 +-
3rdparty/expat/xmltok_impl.h | 2 +-
3rdparty/expat/xmltok_ns.c | 5 +-
32 files changed, 3207 insertions(+), 1697 deletions(-)
diff --git a/.clang-format-ignore b/.clang-format-ignore
new file mode 100644
index 00000000..61820484
--- /dev/null
+++ b/.clang-format-ignore
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# SPDX-FileCopyrightText: 2026 James Turner
+
+/3rdparty/**
diff --git a/3rdparty/.clang-format b/3rdparty/.clang-format
new file mode 100644
index 00000000..36f022e4
--- /dev/null
+++ b/3rdparty/.clang-format
@@ -0,0 +1,3 @@
+{
+ "DisableFormat": true
+}
diff --git a/3rdparty/expat/CMakeLists.txt b/3rdparty/expat/CMakeLists.txt
index 4b232414..024dd0cc 100644
--- a/3rdparty/expat/CMakeLists.txt
+++ b/3rdparty/expat/CMakeLists.txt
@@ -1,3 +1,5 @@
+add_library(FGExpat STATIC)
+
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
check_cxx_source_compiles(
"#include <sys/random.h>
@@ -21,11 +23,13 @@ configure_file (
"${PROJECT_BINARY_DIR}/3rdparty/expat/simgear_expat_config.h"
)
-set(expat_sources
+target_sources(FGExpat PRIVATE
asciitab.h
+ fallthrough.h
hashtable.h
iasciitab.h
latin1tab.h
+ memory_sanitizer.h
nametab.h
utf8tab.h
xmldef.h
@@ -37,13 +41,22 @@ set(expat_sources
xmlparse.c
xmlrole.c
xmltok.c
- internal.h
+ sg_expat_internal.h
ascii.h
sg_expat.h
- sg_expat_external.h
+ sg_expat_external.h
)
-add_library(FGExpat STATIC ${expat_sources})
+if (WIN32)
+ target_sources(FGExpat PRIVATE random_rand_s.c random_rand_s.h)
+elseif(APPLE)
+ target_sources(FGExpat PRIVATE random_arc4random_buf.c random_arc4random_buf.h)
+elseif(HAVE_GETRANDOM)
+ target_sources(FGExpat PRIVATE random_getrandom.c random_getrandom.h)
+else()
+ # old Linux, BSD
+ target_sources(FGExpat PRIVATE random_dev_urandom.c random_dev_urandom.h)
+endif()
target_include_directories(FGExpat BEFORE PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
@@ -54,6 +67,7 @@ target_include_directories(FGExpat PRIVATE ${PROJECT_BINARY_DIR}/3rdparty/expat)
target_compile_definitions(FGExpat PUBLIC HAVE_SIMGEAR_EXPAT_CONFIG_H XML_STATIC)
+
# look like Expat found by find()
add_library(EXPAT::EXPAT ALIAS FGExpat)
diff --git a/3rdparty/expat/expat_config_cmake.in b/3rdparty/expat/expat_config_cmake.in
index b17e2e24..035edc96 100644
--- a/3rdparty/expat/expat_config_cmake.in
+++ b/3rdparty/expat/expat_config_cmake.in
@@ -1,16 +1,12 @@
+/* expat_config.h.cmake. Based upon generated expat_config.h.in. */
#ifndef EXPAT_CONFIG_H
-#define EXPAT_CONFIG_H
+# define EXPAT_CONFIG_H 1
#cmakedefine HAVE_WINDOWS_H
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#cmakedefine BYTEORDER @BYTEORDER@
-#ifdef HAVE_WINDOWS_H
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #undef WIN32_LEAN_AND_MEAN
-#endif
-
-#cmakedefine HAVE_GETRANDOM
#cmakedefine XML_DEV_URANDOM
// we can assume > 10.7 macOS so always set this
@@ -18,32 +14,83 @@
#define HAVE_ARC4RANDOM_BUF
#endif
-/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
-#define BYTEORDER 1234
+#cmakedefine HAVE_GETRANDOM
-/* Define to 1 if you have the `bcopy' function. */
-#cmakedefine HAVE_BCOPY
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine HAVE_DLFCN_H
-/* Define to 1 if you have the `memmove' function. */
-#define HAVE_MEMMOVE
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#cmakedefine HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getentropy' function. */
+#cmakedefine HAVE_GETENTROPY
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine HAVE_MEMORY_H
/* Define to 1 if you have a working `mmap' system call. */
#cmakedefine HAVE_MMAP
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine HAVE_STRING_H
+
+
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H
+
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H
+/* Define to 1 if you have the ANSI C header files. */
+# ifndef STDC_HEADERS
+#cmakedefine STDC_HEADERS
+# endif
+
/* whether byteorder is bigendian */
-#undef WORDS_BIGENDIAN
+#cmakedefine WORDS_BIGENDIAN
+
+/* Define to allow retrieving the byte offsets for attribute names and values.
+ */
+#cmakedefine XML_ATTR_INFO
/* Define to specify how much context to retain around the current parse
- point. */
+ point, 0 to disable. */
#define XML_CONTEXT_BYTES 1024
/* Define to make parameter entity parsing functionality available. */
-#define XML_DTD
+#define XML_DTD 1
+
+/* Define as 1/0 to enable/disable support for general entities. */
+#define XML_GE 1
/* Define to make XML Namespaces functionality available. */
-#define XML_NS
+#define XML_NS 1
+
+/* Define to __FUNCTION__ or "" if `__func__' does not conform to ANSI C. */
+# ifdef _MSC_VER
+# define __func__ __FUNCTION__
+# endif
+
+/* Define to `long' if <sys/types.h> does not define. */
+#cmakedefine off_t @off_t@
-#endif /* ifndef EXPAT_CONFIG_H */
+#endif // ndef EXPAT_CONFIG_H
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/fallthrough.h
similarity index 71%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/fallthrough.h
index 2ecd61b5..707dbdd4 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/fallthrough.h
@@ -6,10 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Nick Begg <ni...@st...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +29,21 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#ifndef FALLTHROUGH_H
+# define FALLTHROUGH_H 1
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+// Explicit fallthrough in switch case to avoid warnings
+// with compiler flag -Wimplicit-fallthrough.
-#include <memory.h>
-#include <string.h>
+# define EXPAT_FALLTHROUGH \
+ do { \
+ } while (0)
-#endif /* ndef WINCONFIG_H */
+# if defined(__has_attribute)
+# if __has_attribute(fallthrough)
+# undef EXPAT_FALLTHROUGH
+# define EXPAT_FALLTHROUGH __attribute__((fallthrough))
+# endif
+# endif
+
+#endif // FALLTHROUGH_H
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/memory_sanitizer.h
similarity index 68%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/memory_sanitizer.h
index 2ecd61b5..a8a8006c 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/memory_sanitizer.h
@@ -6,10 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Matthew Fernandez <mat...@gm...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +29,23 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#if ! defined(MEMORY_SANITIZER_H)
+# define MEMORY_SANITIZER_H 1
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+# if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+# include <sanitizer/msan_interface.h>
-#include <memory.h>
-#include <string.h>
+// inform Memory Sanitizer that [base, base + extent) is now initialized
+# define MSAN_UNPOISON(base, extent) __msan_unpoison((base), (extent))
-#endif /* ndef WINCONFIG_H */
+# endif
+# endif
+
+# if ! defined(MSAN_UNPOISON)
+# define MSAN_UNPOISON(base, extent) \
+ do { \
+ } while (0)
+# endif
+
+#endif // ! defined(MEMORY_SANITIZER_H)
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_arc4random.c
similarity index 66%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_arc4random.c
index 2ecd61b5..243fbbc8 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_arc4random.c
@@ -6,10 +6,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2017-2026 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Matthew Fernandez <mat...@gm...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +30,27 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#include "random_arc4random.h"
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+#if ! defined(_DEFAULT_SOURCE)
+# define _DEFAULT_SOURCE 1 /* for glibc */
+#endif
-#include <memory.h>
-#include <string.h>
+#include <stdint.h> // for uint32_t
+#include <stdlib.h> // for arc4random
+#include <string.h> // for memcpy
-#endif /* ndef WINCONFIG_H */
+void
+writeRandomBytes_arc4random(void *target, size_t count) {
+ size_t bytesWrittenTotal = 0;
+
+ while (bytesWrittenTotal < count) {
+ const uint32_t random32 = arc4random();
+
+ size_t toUse = count - bytesWrittenTotal;
+ if (toUse > sizeof(random32))
+ toUse = sizeof(random32);
+ memcpy((char *)target + bytesWrittenTotal, &random32, toUse);
+ bytesWrittenTotal += toUse;
+ }
+}
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_arc4random.h
similarity index 76%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_arc4random.h
index 2ecd61b5..54fbd4c4 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_arc4random.h
@@ -6,10 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Sebastian Pipping <seb...@pi...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +29,11 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#if ! defined(RANDOM_ACR4RANDOM_H)
+# define RANDOM_ACR4RANDOM_H 1
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+# include <stddef.h> // for size_t
-#include <memory.h>
-#include <string.h>
+void writeRandomBytes_arc4random(void *target, size_t count);
-#endif /* ndef WINCONFIG_H */
+#endif // ! defined(RANDOM_ACR4RANDOM_H)
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_arc4random_buf.c
similarity index 73%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_arc4random_buf.c
index 2ecd61b5..5212b9f1 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_arc4random_buf.c
@@ -6,10 +6,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Matthew Fernandez <mat...@gm...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +30,18 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#include "random_arc4random_buf.h"
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+#if ! defined(_DEFAULT_SOURCE)
+# define _DEFAULT_SOURCE 1 /* for glibc */
+#endif
-#include <memory.h>
-#include <string.h>
+#include "memory_sanitizer.h"
+#include <stdlib.h> // for arc4random_buf
-#endif /* ndef WINCONFIG_H */
+void
+writeRandomBytes_arc4random_buf(void *target, size_t count) {
+ arc4random_buf(target, count);
+ // MSan does not understand `arc4random_buf`, so explain its effects
+ MSAN_UNPOISON(target, count);
+}
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_arc4random_buf.h
similarity index 76%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_arc4random_buf.h
index 2ecd61b5..51f7a31f 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_arc4random_buf.h
@@ -6,10 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Sebastian Pipping <seb...@pi...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +29,11 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#if ! defined(RANDOM_ACR4RANDOM_BUF_H)
+# define RANDOM_ACR4RANDOM_BUF_H 1
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+# include <stddef.h> // for size_t
-#include <memory.h>
-#include <string.h>
+void writeRandomBytes_arc4random_buf(void *target, size_t count);
-#endif /* ndef WINCONFIG_H */
+#endif // ! defined(RANDOM_ACR4RANDOM_BUF_H)
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_dev_urandom.c
similarity index 55%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_dev_urandom.c
index 2ecd61b5..acae6ba4 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_dev_urandom.c
@@ -6,10 +6,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2017-2026 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Matthew Fernandez <mat...@gm...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +30,43 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#include "random_dev_urandom.h"
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+#if ! defined(_POSIX_C_SOURCE) \
+ || (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE < 200809L))
+# define _POSIX_C_SOURCE 200809L // for O_CLOEXEC
+#endif
-#include <memory.h>
-#include <string.h>
+#include <errno.h>
+#include <fcntl.h> // open
+#include <unistd.h> // close
-#endif /* ndef WINCONFIG_H */
+/* Extract entropy from /dev/urandom */
+bool
+writeRandomBytes_dev_urandom(void *target, size_t count) {
+ int success = false; /* full count bytes written? */
+ size_t bytesWrittenTotal = 0;
+
+ const int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ return false;
+ }
+
+ do {
+ void *const currentTarget = (char *)target + bytesWrittenTotal;
+ const size_t bytesToWrite = count - bytesWrittenTotal;
+
+ errno = 0;
+
+ const ssize_t bytesWrittenMore = read(fd, currentTarget, bytesToWrite);
+
+ if (bytesWrittenMore > 0) {
+ bytesWrittenTotal += bytesWrittenMore;
+ if (bytesWrittenTotal >= count)
+ success = true;
+ }
+ } while (! success && (errno == EINTR));
+
+ close(fd);
+ return success;
+}
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_dev_urandom.h
similarity index 76%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_dev_urandom.h
index 2ecd61b5..d9cf767b 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_dev_urandom.h
@@ -6,10 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Sebastian Pipping <seb...@pi...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +29,12 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#if ! defined(RANDOM_DEV_URANDOM_H)
+# define RANDOM_DEV_URANDOM_H 1
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+# include <stdbool.h>
+# include <stddef.h> // for size_t
-#include <memory.h>
-#include <string.h>
+bool writeRandomBytes_dev_urandom(void *target, size_t count);
-#endif /* ndef WINCONFIG_H */
+#endif // ! defined(RANDOM_DEV_URANDOM_H)
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_getentropy.c
similarity index 62%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_getentropy.c
index 2ecd61b5..5cea2d88 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_getentropy.c
@@ -6,10 +6,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Matthew Fernandez <mat...@gm...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +30,31 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-
-#include <memory.h>
-#include <string.h>
-
-#endif /* ndef WINCONFIG_H */
+#include "random_getentropy.h"
+
+// NOTE: Please keep this block in sync with its two siblings in files
+// `configure.ac` and `ConfigureChecks.cmake`!
+#if defined(__APPLE__)
+# include <sys/random.h>
+#else
+# if defined(__GLIBC__) && ! defined(_DEFAULT_SOURCE)
+# define _DEFAULT_SOURCE 1
+# endif
+# if ! defined(_GNU_SOURCE)
+# define _GNU_SOURCE 1 /* for musl */
+# endif
+# include <unistd.h>
+#endif // ! defined(__APPLE__)
+
+#include "memory_sanitizer.h"
+#include <errno.h>
+
+bool
+writeRandomBytes_getentropy(void *target, size_t count) {
+ errno = 0;
+ const bool success = getentropy(target, count);
+ // MSan does not understand `getentropy`, so explain its effects
+ if (success)
+ MSAN_UNPOISON(target, count);
+ return success;
+}
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_getentropy.h
similarity index 76%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_getentropy.h
index 2ecd61b5..a00b16bf 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_getentropy.h
@@ -6,10 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Sebastian Pipping <seb...@pi...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +29,12 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#if ! defined(RANDOM_GETENTROPY_H)
+# define RANDOM_GETENTROPY_H 1
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+# include <stdbool.h>
+# include <stddef.h> // for size_t
-#include <memory.h>
-#include <string.h>
+bool writeRandomBytes_getentropy(void *target, size_t count);
-#endif /* ndef WINCONFIG_H */
+#endif // ! defined(RANDOM_GETENTROPY_H)
diff --git a/3rdparty/expat/random_getrandom.c b/3rdparty/expat/random_getrandom.c
new file mode 100644
index 00000000..72e2cc70
--- /dev/null
+++ b/3rdparty/expat/random_getrandom.c
@@ -0,0 +1,95 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2017-2026 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2017 Chanho Park <cha...@sa...>
+ Copyright (c) 2022 Sean McBride <se...@ro...>
+ Copyright (c) 2026 Matthew Fernandez <mat...@gm...>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "expat_config.h" // for HAVE_GETRANDOM, HAVE_SYSCALL_GETRANDOM
+
+#include "random_getrandom.h"
+
+#if defined(HAVE_GETRANDOM)
+# include <sys/random.h> /* getrandom */
+#endif
+
+#if defined(HAVE_SYSCALL_GETRANDOM)
+# if ! defined(_GNU_SOURCE)
+# define _GNU_SOURCE 1 /* syscall prototype */
+# endif
+# include <unistd.h> /* syscall */
+# include <sys/syscall.h> /* SYS_getrandom */
+#endif // defined(HAVE_SYSCALL_GETRANDOM)
+
+#if ! defined(GRND_NONBLOCK)
+# define GRND_NONBLOCK 0x0001
+#endif /* defined(GRND_NONBLOCK) */
+
+#include "memory_sanitizer.h"
+#include <assert.h>
+#include <errno.h>
+#include <limits.h> // for INT_MAX
+
+/* Obtain entropy on Linux 3.17+ */
+bool
+writeRandomBytes_getrandom_nonblock(void *target, size_t count) {
+ int success = false; /* full count bytes written? */
+ size_t bytesWrittenTotal = 0;
+ const unsigned int getrandomFlags = GRND_NONBLOCK;
+
+ do {
+ void *const currentTarget = (char *)target + bytesWrittenTotal;
+ const size_t bytesToWrite = count - bytesWrittenTotal;
+
+ assert(bytesToWrite <= INT_MAX);
+
+ errno = 0;
+
+ const int bytesWrittenMore =
+#if defined(HAVE_GETRANDOM)
+ (int)getrandom(currentTarget, bytesToWrite, getrandomFlags);
+ // MSan understands `getrandom`, so does not need extra guidance
+#else
+ (int)syscall(SYS_getrandom, currentTarget, bytesToWrite,
+ getrandomFlags);
+ // MSan does not understand `syscall`, so explain its effects
+ if (bytesWrittenMore > 0)
+ MSAN_UNPOISON(currentTarget, bytesWrittenMore);
+#endif
+
+ if (bytesWrittenMore > 0) {
+ bytesWrittenTotal += bytesWrittenMore;
+ if (bytesWrittenTotal >= count)
+ success = true;
+ }
+ } while (! success && (errno == EINTR));
+
+ return success;
+}
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_getrandom.h
similarity index 76%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_getrandom.h
index 2ecd61b5..ed4d829c 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_getrandom.h
@@ -6,10 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2026 Sebastian Pipping <seb...@pi...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +29,12 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#if ! defined(RANDOM_GETRANDOM_H)
+# define RANDOM_GETRANDOM_H 1
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+# include <stdbool.h>
+# include <stddef.h> // for size_t
-#include <memory.h>
-#include <string.h>
+bool writeRandomBytes_getrandom_nonblock(void *target, size_t count);
-#endif /* ndef WINCONFIG_H */
+#endif // ! defined(RANDOM_GETRANDOM_H)
diff --git a/3rdparty/expat/random_rand_s.c b/3rdparty/expat/random_rand_s.c
new file mode 100644
index 00000000..46156563
--- /dev/null
+++ b/3rdparty/expat/random_rand_s.c
@@ -0,0 +1,88 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2019 David Loffredo <lof...@st...>
+ Copyright (c) 2019-2026 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2019 Ben Wagner <bun...@ch...>
+ Copyright (c) 2019 Vadim Zeitlin <va...@ze...>
+ Copyright (c) 2026 Matthew Fernandez <mat...@gm...>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "random_rand_s.h"
+
+/* force stdlib to define rand_s() */
+#if ! defined(_CRT_RAND_S)
+# define _CRT_RAND_S
+#endif
+
+// Workaround MinGW GCC trouble with recognizing `rand_s`, likely related
+// to return type `error_t`; the symptom was:
+// > error: implicit declaration of function ‘rand_s’
+#if defined(__MINGW32__)
+# include <errno.h>
+#endif
+
+#include <stdlib.h> // for rand_s
+#include <string.h> // for memcpy
+
+// Help clang-tidy out with prototype of function `rand_s`
+#if defined(XML_CLANG_TIDY)
+int rand_s(unsigned int *);
+#endif
+
+/* Provide declaration of rand_s() for MinGW-32 (not 64, which has it),
+ as it didn't declare it in its header prior to version 5.3.0 of its
+ runtime package (mingwrt, containing stdlib.h). The upstream fix
+ was introduced at https://osdn.net/projects/mingw/ticket/39658 . */
+#if defined(__MINGW32__) && defined(__MINGW32_VERSION) \
+ && __MINGW32_VERSION < 5003000L && ! defined(__MINGW64_VERSION_MAJOR)
+__declspec(dllimport) int rand_s(unsigned int *);
+#endif
+
+/* Obtain entropy on Windows using the rand_s() function which
+ * generates cryptographically secure random numbers. Internally it
+ * uses RtlGenRandom API which is present in Windows XP and later.
+ */
+bool
+writeRandomBytes_rand_s(void *target, size_t count) {
+ size_t bytesWrittenTotal = 0;
+
+ while (bytesWrittenTotal < count) {
+ unsigned int random32 = 0;
+
+ if (rand_s(&random32))
+ return false; /* failure */
+
+ size_t toUse = count - bytesWrittenTotal;
+ if (toUse > sizeof(random32))
+ toUse = sizeof(random32);
+ memcpy((char *)target + bytesWrittenTotal, &random32, toUse);
+ bytesWrittenTotal += toUse;
+ }
+ return true; /* success */
+}
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/random_rand_s.h
similarity index 76%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/random_rand_s.h
index 2ecd61b5..2b487d62 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/random_rand_s.h
@@ -6,10 +6,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2019 David Loffredo <lof...@st...>
+ Copyright (c) 2026 Sebastian Pipping <seb...@pi...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -32,14 +30,12 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WINCONFIG_H
-#define WINCONFIG_H
+#if ! defined(RANDOM_RAND_S_H)
+# define RANDOM_RAND_S_H 1
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
+# include <stdbool.h>
+# include <stddef.h> // for size_t
-#include <memory.h>
-#include <string.h>
+bool writeRandomBytes_rand_s(void *target, size_t count);
-#endif /* ndef WINCONFIG_H */
+#endif // ! defined(RANDOM_RAND_S_H)
diff --git a/3rdparty/expat/sg_expat.h b/3rdparty/expat/sg_expat.h
index 14c06f7b..0cd019ee 100644
--- a/3rdparty/expat/sg_expat.h
+++ b/3rdparty/expat/sg_expat.h
@@ -11,10 +11,15 @@
Copyright (c) 2000-2005 Fred L. Drake, Jr. <fd...@us...>
Copyright (c) 2001-2002 Greg Stein <gs...@us...>
Copyright (c) 2002-2016 Karl Waclawek <ka...@wa...>
- Copyright (c) 2016-2022 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2016-2026 Sebastian Pipping <seb...@pi...>
Copyright (c) 2016 Cristian Rodríguez <crr...@op...>
Copyright (c) 2016 Thomas Beutlich <tc...@tb...>
Copyright (c) 2017 Rhodri James <rh...@wi...>
+ Copyright (c) 2022 Thijs Schreijer <th...@th...>
+ Copyright (c) 2023 Hanno Böck <ha...@ge...>
+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <sn...@so...>
+ Copyright (c) 2024 Taichi Haradaguchi <200...@ym...>
+ Copyright (c) 2025 Matthew Fernandez <mat...@gm...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -37,22 +42,24 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef Expat_INCLUDED
-#define Expat_INCLUDED 1
+#ifndef SG_Expat_INCLUDED
+# define SG_Expat_INCLUDED 1
-#include <stdlib.h>
-#include "sg_expat_external.h"
+# include <stdint.h> // for uint8_t
+# include <stdlib.h>
-#ifdef __cplusplus
+# include "sg_expat_external.h"
+
+# ifdef __cplusplus
extern "C" {
-#endif
+# endif
struct XML_ParserStruct;
typedef struct XML_ParserStruct *XML_Parser;
typedef unsigned char XML_Bool;
-#define XML_TRUE ((XML_Bool)1)
-#define XML_FALSE ((XML_Bool)0)
+# define XML_TRUE ((XML_Bool)1)
+# define XML_FALSE ((XML_Bool)0)
/* The XML_Status enum gives the possible return values for several
API functions. The preprocessor #defines are included so this
@@ -69,11 +76,11 @@ typedef unsigned char XML_Bool;
*/
enum XML_Status {
XML_STATUS_ERROR = 0,
-#define XML_STATUS_ERROR XML_STATUS_ERROR
+# define XML_STATUS_ERROR XML_STATUS_ERROR
XML_STATUS_OK = 1,
-#define XML_STATUS_OK XML_STATUS_OK
+# define XML_STATUS_OK XML_STATUS_OK
XML_STATUS_SUSPENDED = 2
-#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED
+# define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED
};
enum XML_Error {
@@ -126,7 +133,9 @@ enum XML_Error {
/* Added in 2.3.0. */
XML_ERROR_NO_BUFFER,
/* Added in 2.4.0. */
- XML_ERROR_AMPLIFICATION_LIMIT_BREACH
+ XML_ERROR_AMPLIFICATION_LIMIT_BREACH,
+ /* Added in 2.6.4. */
+ XML_ERROR_NOT_STARTED,
};
enum XML_Content_Type {
@@ -174,8 +183,10 @@ struct XML_cp {
};
/* This is called for an element declaration. See above for
- description of the model argument. It's the caller's responsibility
- to free model when finished with it.
+ description of the model argument. It's the user code's responsibility
+ to free model when finished with it. See XML_FreeContentModel.
+ There is no need to free the model from the handler, it can be kept
+ around and freed at a later stage.
*/
typedef void(XMLCALL *XML_ElementDeclHandler)(void *userData,
const XML_Char *name,
@@ -237,6 +248,17 @@ XML_ParserCreate(const XML_Char *encoding);
and the local part will be concatenated without any separator.
It is a programming error to use the separator '\0' with namespace
triplets (see XML_SetReturnNSTriplet).
+ If a namespace separator is chosen that can be part of a URI or
+ part of an XML name, splitting an expanded name back into its
+ 1, 2 or 3 original parts on application level in the element handler
+ may end up vulnerable, so these are advised against; sane choices for
+ a namespace separator are e.g. '\n' (line feed) and '|' (pipe).
+
+ Note that Expat does not validate namespace URIs (beyond encoding)
+ against RFC 3986 today (and is not required to do so with regard to
+ the XML 1.0 namespaces specification) but it may start doing that
+ in future releases. Before that, an application using Expat must
+ be ready to receive namespace URIs containing non-URI characters.
*/
XMLPARSEAPI(XML_Parser)
XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
@@ -255,9 +277,9 @@ XML_ParserCreate_MM(const XML_Char *encoding,
const XML_Memory_Handling_Suite *memsuite,
const XML_Char *namespaceSeparator);
-/* Prepare a parser object to be re-used. This is particularly
+/* Prepare a parser object to be reused. This is particularly
valuable when memory allocation overhead is disproportionately high,
- such as when a large number of small documnents need to be parsed.
+ such as when a large number of small documents need to be parsed.
All handlers are cleared from the parser, except for the
unknownEncodingHandler. The parser's external state is re-initialized
except for the values of ns and ns_triplets.
@@ -317,7 +339,7 @@ typedef void(XMLCALL *XML_StartDoctypeDeclHandler)(void *userData,
const XML_Char *pubid,
int has_internal_subset);
-/* This is called for the start of the DOCTYPE declaration when the
+/* This is called for the end of the DOCTYPE declaration when the
closing > is encountered, but after processing any external
subset.
*/
@@ -661,7 +683,7 @@ XMLPARSEAPI(void)
XML_SetUserData(XML_Parser parser, void *userData);
/* Returns the last value set by XML_SetUserData or NULL. */
-#define XML_GetUserData(parser) (*(void **)(parser))
+# define XML_GetUserData(parser) (*(void **)(parser))
/* This is equivalent to supplying an encoding argument to
XML_ParserCreate. On success XML_SetEncoding returns non-zero,
@@ -733,7 +755,7 @@ XML_GetSpecifiedAttributeCount(XML_Parser parser);
XMLPARSEAPI(int)
XML_GetIdAttributeIndex(XML_Parser parser);
-#ifdef XML_ATTR_INFO
+# ifdef XML_ATTR_INFO
/* Source file byte offsets for the start and end of attribute names and values.
The value indices are exclusive of surrounding quotes; thus in a UTF-8 source
file an attribute value of "blah" will yield:
@@ -754,7 +776,7 @@ typedef struct {
*/
XMLPARSEAPI(const XML_AttrInfo *)
XML_GetAttributeInfo(XML_Parser parser);
-#endif
+# endif
/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is
detected. The last call to XML_Parse must have isFinal true; len
@@ -897,10 +919,21 @@ XML_SetParamEntityParsing(XML_Parser parser,
function behavior. This must be called before parsing is started.
Returns 1 if successful, 0 when called after parsing has started.
Note: If parser == NULL, the function will do nothing and return 0.
+ DEPRECATED since Expat 2.8.0.
*/
XMLPARSEAPI(int)
XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt);
+/* Sets the hash salt to use for internal hash calculations.
+ Helps in preventing DoS attacks based on predicting hash function behavior.
+ This must be called before parsing is started.
+ Returns XML_TRUE if successful, XML_FALSE when called after parsing has
+ started or when parser is NULL.
+ Added in Expat 2.8.0.
+*/
+XMLPARSEAPI(XML_Bool)
+XML_SetHashSalt16Bytes(XML_Parser parser, const uint8_t entropy[16]);
+
/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
XML_GetErrorCode returns information about the error.
*/
@@ -937,7 +970,7 @@ XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser);
XMLPARSEAPI(int)
XML_GetCurrentByteCount(XML_Parser parser);
-/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
+/* If XML_CONTEXT_BYTES is >=1, returns the input buffer, sets
the integer pointed to by offset to the offset within this buffer
of the current parse position, and sets the integer pointed to by size
to the size of this buffer (the number of input bytes). Otherwise
@@ -951,9 +984,9 @@ XMLPARSEAPI(const char *)
XML_GetInputContext(XML_Parser parser, int *offset, int *size);
/* For backwards compatibility with previous versions. */
-#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
-#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
-#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
+# define XML_GetErrorLineNumber XML_GetCurrentLineNumber
+# define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
+# define XML_GetErrorByteIndex XML_GetCurrentByteIndex
/* Frees the content model passed to the element declaration handler */
XMLPARSEAPI(void)
@@ -1011,7 +1044,12 @@ enum XML_FeatureEnum {
XML_FEATURE_ATTR_INFO,
/* Added in Expat 2.4.0. */
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
- XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
+ XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
+ /* Added in Expat 2.6.0. */
+ XML_FEATURE_GE,
+ /* Added in Expat 2.7.2. */
+ XML_FEATURE_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT,
+ XML_FEATURE_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT,
/* Additional features must be added to the end of this enum. */
};
@@ -1024,27 +1062,43 @@ typedef struct {
XMLPARSEAPI(const XML_Feature *)
XML_GetFeatureList(void);
-#ifdef XML_DTD
-/* Added in Expat 2.4.0. */
+# if defined(XML_DTD) || (defined(XML_GE) && XML_GE == 1)
+/* Added in Expat 2.4.0 for XML_DTD defined and
+ * added in Expat 2.6.0 for XML_GE == 1. */
XMLPARSEAPI(XML_Bool)
XML_SetBillionLaughsAttackProtectionMaximumAmplification(
XML_Parser parser, float maximumAmplificationFactor);
-/* Added in Expat 2.4.0. */
+/* Added in Expat 2.4.0 for XML_DTD defined and
+ * added in Expat 2.6.0 for XML_GE == 1. */
XMLPARSEAPI(XML_Bool)
XML_SetBillionLaughsAttackProtectionActivationThreshold(
XML_Parser parser, unsigned long long activationThresholdBytes);
-#endif
+
+/* Added in Expat 2.7.2. */
+XMLPARSEAPI(XML_Bool)
+XML_SetAllocTrackerMaximumAmplification(XML_Parser parser,
+ float maximumAmplificationFactor);
+
+/* Added in Expat 2.7.2. */
+XMLPARSEAPI(XML_Bool)
+XML_SetAllocTrackerActivationThreshold(
+ XML_Parser parser, unsigned long long activationThresholdBytes);
+# endif
+
+/* Added in Expat 2.6.0. */
+XMLPARSEAPI(XML_Bool)
+XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
/* Expat follows the semantic versioning convention.
- See http://semver.org.
+ See https://semver.org
*/
-#define XML_MAJOR_VERSION 2
-#define XML_MINOR_VERSION 4
-#define XML_MICRO_VERSION 4
+# define XML_MAJOR_VERSION 2
+# define XML_MINOR_VERSION 8
+# define XML_MICRO_VERSION 2
-#ifdef __cplusplus
+# ifdef __cplusplus
}
-#endif
+# endif
#endif /* not Expat_INCLUDED */
diff --git a/3rdparty/expat/sg_expat_external.h b/3rdparty/expat/sg_expat_external.h
index 8829f770..7f5c4c3a 100644
--- a/3rdparty/expat/sg_expat_external.h
+++ b/3rdparty/expat/sg_expat_external.h
@@ -12,9 +12,10 @@
Copyright (c) 2001-2002 Greg Stein <gs...@us...>
Copyright (c) 2002-2006 Karl Waclawek <ka...@wa...>
Copyright (c) 2016 Cristian Rodríguez <crr...@op...>
- Copyright (c) 2016-2019 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2016-2025 Sebastian Pipping <seb...@pi...>
Copyright (c) 2017 Rhodri James <rh...@wi...>
Copyright (c) 2018 Yury Gribov <tet...@gm...>
+ Copyright (c) 2026 Matthew Fernandez <mat...@gm...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -38,14 +39,14 @@
*/
#ifndef Expat_External_INCLUDED
-#define Expat_External_INCLUDED 1
+# define Expat_External_INCLUDED 1
/* External API definitions */
/* Expat tries very hard to make the API boundary very specifically
defined. There are two macros defined to control this boundary;
each of these can be defined before including this header to
- achieve some different behavior, but doing so it not recommended or
+ achieve some different behavior, but doing so is not recommended or
tested frequently.
XMLCALL - The calling convention to use for all calls across the
@@ -64,12 +65,12 @@
compiled with the cdecl calling convention as the default since
system headers may assume the cdecl convention.
*/
-#ifndef XMLCALL
-# if defined(_MSC_VER)
-# define XMLCALL __cdecl
-# elif defined(__GNUC__) && defined(__i386) && ! defined(__INTEL_COMPILER)
-# define XMLCALL __attribute__((cdecl))
-# else
+# ifndef XMLCALL
+# if defined(_MSC_VER)
+# define XMLCALL __cdecl
+# elif defined(__GNUC__) && defined(__i386) && ! defined(__INTEL_COMPILER)
+# define XMLCALL __attribute__((cdecl))
+# else
/* For any platform which uses this definition and supports more than
one calling convention, we need to extend this definition to
declare the convention used on that platform, if it's possible to
@@ -80,86 +81,86 @@
pre-processor and how to specify the same calling convention as the
platform's malloc() implementation.
*/
-# define XMLCALL
-# endif
-#endif /* not defined XMLCALL */
+# define XMLCALL
+# endif
+# endif /* not defined XMLCALL */
-#if ! defined(XML_STATIC) && ! defined(XMLIMPORT)
-# ifndef XML_BUILDING_EXPAT
+# if ! defined(XML_STATIC) && ! defined(XMLIMPORT)
+# ifndef XML_BUILDING_EXPAT
/* using Expat from an application */
-# if defined(_MSC_EXTENSIONS) && ! defined(__BEOS__) && ! defined(__CYGWIN__)
-# define XMLIMPORT __declspec(dllimport)
+# if defined(_MSC_VER) && ! defined(__BEOS__) && ! defined(__CYGWIN__)
+# define XMLIMPORT __declspec(dllimport)
+# endif
+
# endif
+# endif /* not defined XML_STATIC */
+# ifndef XML_ENABLE_VISIBILITY
+# define XML_ENABLE_VISIBILITY 0
# endif
-#endif /* not defined XML_STATIC */
-
-#ifndef XML_ENABLE_VISIBILITY
-# define XML_ENABLE_VISIBILITY 0
-#endif
-#if ! defined(XMLIMPORT) && XML_ENABLE_VISIBILITY
-# define XMLIMPORT __attribute__((visibility("default")))
-#endif
+# if ! defined(XMLIMPORT) && XML_ENABLE_VISIBILITY
+# define XMLIMPORT __attribute__((visibility("default")))
+# endif
/* If we didn't define it above, define it away: */
-#ifndef XMLIMPORT
-# define XMLIMPORT
-#endif
-
-#if defined(__GNUC__) \
- && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
-# define XML_ATTR_MALLOC __attribute__((__malloc__))
-#else
-# define XML_ATTR_MALLOC
-#endif
-
-#if defined(__GNUC__) \
- && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
-# define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
-#else
-# define XML_ATTR_ALLOC_SIZE(x)
-#endif
-
-#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+# ifndef XMLIMPORT
+# define XMLIMPORT
+# endif
+
+# if defined(__GNUC__) \
+ && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+# define XML_ATTR_MALLOC __attribute__((__malloc__))
+# else
+# define XML_ATTR_MALLOC
+# endif
-#ifdef XML_UNICODE_WCHAR_T
-# ifndef XML_UNICODE
-# define XML_UNICODE
+# if defined(__GNUC__) \
+ && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+# define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+# else
+# define XML_ATTR_ALLOC_SIZE(x)
# endif
-# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2)
-# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc"
+
+# define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
+
+# ifdef __cplusplus
+extern "C" {
# endif
-#endif
-#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
# ifdef XML_UNICODE_WCHAR_T
+# ifndef XML_UNICODE
+# define XML_UNICODE
+# endif
+# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2)
+# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc"
+# endif
+# endif
+
+# ifdef XML_UNICODE /* Information is UTF-16 encoded. */
+# ifdef XML_UNICODE_WCHAR_T
typedef wchar_t XML_Char;
typedef wchar_t XML_LChar;
-# else
+# else
typedef unsigned short XML_Char;
typedef char XML_LChar;
-# endif /* XML_UNICODE_WCHAR_T */
-#else /* Information is UTF-8 encoded. */
+# endif /* XML_UNICODE_WCHAR_T */
+# else /* Information is UTF-8 encoded. */
typedef char XML_Char;
typedef char XML_LChar;
-#endif /* XML_UNICODE */
+# endif /* XML_UNICODE */
-#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
+# ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
typedef long long XML_Index;
typedef unsigned long long XML_Size;
-#else
+# else
typedef long XML_Index;
typedef unsigned long XML_Size;
-#endif /* XML_LARGE_SIZE */
+# endif /* XML_LARGE_SIZE */
-#ifdef __cplusplus
+# ifdef __cplusplus
}
-#endif
+# endif
#endif /* not Expat_External_INCLUDED */
diff --git a/3rdparty/expat/internal.h b/3rdparty/expat/sg_expat_internal.h
similarity index 77%
rename from 3rdparty/expat/internal.h
rename to 3rdparty/expat/sg_expat_internal.h
index 28324db9..48866c3a 100644
--- a/3rdparty/expat/internal.h
+++ b/3rdparty/expat/sg_expat_internal.h
@@ -28,9 +28,11 @@
Copyright (c) 2002-2003 Fred L. Drake, Jr. <fd...@us...>
Copyright (c) 2002-2006 Karl Waclawek <ka...@wa...>
Copyright (c) 2003 Greg Stein <gs...@us...>
- Copyright (c) 2016-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2016-2026 Sebastian Pipping <seb...@pi...>
Copyright (c) 2018 Yury Gribov <tet...@gm...>
Copyright (c) 2019 David Loffredo <lof...@st...>
+ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <sn...@so...>
+ Copyright (c) 2024 Taichi Haradaguchi <200...@ym...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -106,8 +108,12 @@
#endif
#include <limits.h> // ULONG_MAX
+#include <stddef.h> // size_t
-#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO)
+#if defined(_WIN32) \
+ && (! defined(__USE_MINGW_ANSI_STDIO) \
+ || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0))
+# define EXPAT_FMT_LLX(midpart) "%" midpart "I64x"
# define EXPAT_FMT_ULL(midpart) "%" midpart "I64u"
# if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
@@ -117,12 +123,16 @@
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
# endif
#else
+# define EXPAT_FMT_LLX(midpart) "%" midpart "llx"
# define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
# if ! defined(ULONG_MAX)
# error Compiler did not define ULONG_MAX for us
# elif ULONG_MAX == 18446744073709551615u // 2^64-1
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
+# elif defined(__wasm32__) // 32bit mode Emscripten or WASI SDK
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "zu"
# else
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
@@ -141,6 +151,16 @@
100.0f
#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \
8388608 // 8 MiB, 2^23
+
+#define EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT 100.0f
+#define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \
+ 67108864 // 64 MiB, 2^26
+
+// NOTE: If function expat_alloc was user facing, EXPAT_MALLOC_ALIGNMENT would
+// have to take sizeof(long double) into account
+#define EXPAT_MALLOC_ALIGNMENT sizeof(long long) // largest parser (sub)member
+#define EXPAT_MALLOC_PADDING ((EXPAT_MALLOC_ALIGNMENT) - sizeof(size_t))
+
/* NOTE END */
#include "sg_expat.h" // so we can use type XML_Parser below
@@ -152,12 +172,24 @@ extern "C" {
void _INTERNAL_trim_to_complete_utf8_characters(const char *from,
const char **fromLimRef);
-#if defined(XML_DTD)
+#if defined(XML_GE) && XML_GE == 1
unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
const char *unsignedCharToPrintable(unsigned char c);
#endif
+extern
+#if ! defined(XML_TESTING)
+ const
+#endif
+ XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c
+#if defined(XML_TESTING)
+void *expat_malloc(XML_Parser parser, size_t size, int sourceLine);
+void expat_free(XML_Parser parser, void *ptr, int sourceLine);
+void *expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine);
+extern unsigned int g_bytesScanned; // used for testing only
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/3rdparty/expat/siphash.h b/3rdparty/expat/siphash.h
index e5406d7e..be216b40 100644
--- a/3rdparty/expat/siphash.h
+++ b/3rdparty/expat/siphash.h
@@ -100,13 +100,14 @@
#include <stddef.h> /* size_t */
#include <stdint.h> /* uint64_t uint32_t uint8_t */
+#include "fallthrough.h"
/*
* Workaround to not require a C++11 compiler for using ULL suffix
* if this code is included and compiled as C++; related GCC warning is:
* warning: use of C++11 long long integer constant [-Wlong-long]
*/
-#define _SIP_ULL(high, low) (((uint64_t)high << 32) | low)
+#define SIP_ULL(high, low) ((((uint64_t)high) << 32) | (low))
#define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
@@ -126,8 +127,7 @@
| ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) \
| ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
-#define SIPHASH_INITIALIZER \
- { 0, 0, 0, 0, {0}, 0, 0 }
+#define SIPHASH_INITIALIZER {0, 0, 0, 0, {0}, 0, 0}
struct siphash {
uint64_t v0, v1, v2, v3;
@@ -190,10 +190,10 @@ sip_round(struct siphash *H, const int rounds) {
static struct siphash *
sip24_init(struct siphash *H, const struct sipkey *key) {
- H->v0 = _SIP_ULL(0x736f6d65U, 0x70736575U) ^ key->k[0];
- H->v1 = _SIP_ULL(0x646f7261U, 0x6e646f6dU) ^ key->k[1];
- H->v2 = _SIP_ULL(0x6c796765U, 0x6e657261U) ^ key->k[0];
- H->v3 = _SIP_ULL(0x74656462U, 0x79746573U) ^ key->k[1];
+ H->v0 = SIP_ULL(0x736f6d65U, 0x70736575U) ^ key->k[0];
+ H->v1 = SIP_ULL(0x646f7261U, 0x6e646f6dU) ^ key->k[1];
+ H->v2 = SIP_ULL(0x6c796765U, 0x6e657261U) ^ key->k[0];
+ H->v3 = SIP_ULL(0x74656462U, 0x79746573U) ^ key->k[1];
H->p = H->buf;
H->c = 0;
@@ -235,25 +235,25 @@ sip24_final(struct siphash *H) {
switch (left) {
case 7:
b |= (uint64_t)H->buf[6] << 48;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 6:
b |= (uint64_t)H->buf[5] << 40;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 5:
b |= (uint64_t)H->buf[4] << 32;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 4:
b |= (uint64_t)H->buf[3] << 24;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 3:
b |= (uint64_t)H->buf[2] << 16;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 2:
b |= (uint64_t)H->buf[1] << 8;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 1:
b |= (uint64_t)H->buf[0] << 0;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 0:
break;
}
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/winconfig.h
index 2ecd61b5..05805514 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/winconfig.h
@@ -9,7 +9,8 @@
Copyright (c) 2000 Clark Cooper <coo...@us...>
Copyright (c) 2002 Greg Stein <gs...@us...>
Copyright (c) 2005 Karl Waclawek <ka...@wa...>
- Copyright (c) 2017-2021 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2017-2023 Sebastian Pipping <seb...@pi...>
+ Copyright (c) 2023 Orgad Shaneh <org...@au...>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -35,7 +36,9 @@
#ifndef WINCONFIG_H
#define WINCONFIG_H
-#define WIN32_LEAN_AND_MEAN
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
diff --git a/3rdparty/expat/winconfig.h b/3rdparty/expat/xcsinc.c
similarity index 75%
copy from 3rdparty/expat/winconfig.h
copy to 3rdparty/expat/xcsinc.c
index 2ecd61b5..3597c248 100644
--- a/3rdparty/expat/winconfig.h
+++ b/3rdparty/expat/xcsinc.c
@@ -1,4 +1,4 @@
-/*
+/* This file is included from other .c files!
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -6,10 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2000 Clark Cooper <coo...@us...>
- Copyright (c) 2002 Greg Stein <gs...@us...>
- Copyright (c) 2005 Karl Waclawek <...
[truncated message content] |
|
From: <fli...@li...> - 2026-08-02 04:21:12
|
unknown user pushed a commit to branch release/2024.1
in repository fgmeta.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new e8c5e9e Also upload FGData to Storage
e8c5e9e is described below
SF URL: http://sourceforge.net/p/flightgear/fgmeta/ci/e8c5e9e32a2f597fa45f75dfa597dfa77ad26553/
Commit: e8c5e9e32a2f597fa45f75dfa597dfa77ad26553
Author: James Turner
Committer: James Turner
AuthorDate: Sat Aug 1 16:01:36 2026 +0100
Also upload FGData to Storage
---
release_builder/create_base_package.sh | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/release_builder/create_base_package.sh b/release_builder/create_base_package.sh
index 4a6a794..198d28e 100755
--- a/release_builder/create_base_package.sh
+++ b/release_builder/create_base_package.sh
@@ -25,10 +25,8 @@ VERSION=`cat fgdata/version`
SCENERY_PACK_AIRPORT=BIKF
SCENERY_PACK_URI="https://sourceforge.net/projects/flightgear/files/scenery/SceneryPack.${SCENERY_PACK_AIRPORT}.tgz/download"
FGDATA_NAME="fgdata_2024_1"
-STORAGE_BUCKET="terrasync-fgdata"
-
-# Expose the Bunny secret under the name that rclone expects when using env_auth=true
-AWS_SECRET_ACCESS_KEY=$BUNNY_FGDATA_SECRET
+TERRSASYNC_BUCKET="terrasync-fgdata"
+DOWNLOAD_BUCKET="fgdata-download"
echo "Assembling base package for $VERSION"
cd $WORKSPACE
@@ -73,11 +71,14 @@ cat << _end_ > "staging/$FGDATA_NAME/base_package.json"
}
_end_
+# expose the Bunny secret under the name that rclone expects when using env_auth=true
+export AWS_SECRET_ACCESS_KEY=$BUNNY_FGDATA_SECRET
+
# rsync current dir-indexes, so we don't create new ones if contents have not changed. This
# is important since new dir index files get a comment which changes their SHA sum
# TODO: remove `.dirindex` include once new files exist
-rclone copy --include "**/.dirindex" --include "**/dirindex.txt" bunny-fgdata:terrasync-fgdata/$FGDATA_NAME/ previous-dirindex/
+rclone copy --include "**/.dirindex" --include "**/dirindex.txt" bunny-fgdata:$TERRSASYNC_BUCKET/$FGDATA_NAME/ previous-dirindex/
echo "Computing dir-indexes"
.venv/bin/create_dirindex.py --date=now --old-dir="previous-dirindex/$FGDATA_NAME" --legacy-indices "staging/$FGDATA_NAME"
@@ -85,9 +86,8 @@ echo "Computing dir-indexes"
# Creating full base package TXZ
# import we re-apply excludes here, so that the root dirindex is skipped
-export XZ_OPT="-T0" # multiple threads
OUTPUT_NAME=output/FlightGear-$VERSION-data.txz
-tar -cJf "${WORKSPACE}/$OUTPUT_NAME" --exclude-from=release_builder/base_package_excludes --directory staging $FGDATA_NAME
+tar -cf "${WORKSPACE}/$OUTPUT_NAME" --use-compress-program="xz -T0" --exclude-from=release_builder/base_package_excludes --directory staging $FGDATA_NAME
echo "Done, data TXZs are in output/"
@@ -107,9 +107,15 @@ scp $OUTPUT_NAME jm...@de...:/var/www/download-flightgear/relea
# zip file only goes to download.flightgear.org
scp $ZIP_OUTPUT_NAME jm...@de...:/var/www/download-flightgear/release-2024.1/
+# juggle keys back and forth for auth :(
+export AWS_SECRET_ACCESS_KEY=$BUNNY_DLDATA_SECRET
+
+rclone copy --progress "$OUTPUT_NAME" bunny-dldata:$DOWNLOAD_BUCKET/$FGDATA_NAME/
echo "Done uploading TXZ, now sync-ing files to the CDN"
+export AWS_SECRET_ACCESS_KEY=$BUNNY_FGDATA_SECRET
+
# `--checksum` arg is important so we don't touch / modify unchanged files on the server side.
-rclone sync --checksum staging/$FGDATA_NAME bunny-fgdata:terrasync-fgdata/$FGDATA_NAME --progress
+rclone sync --checksum --progress staging/$FGDATA_NAME bunny-fgdata:terrasync-fgdata/$FGDATA_NAME
echo "Finished"
|
|
From: <fli...@li...> - 2026-08-01 15:16:48
|
unknown user pushed a commit to branch next
in repository flightgear.
The following commit(s) were added to refs/heads/next by this push:
new fbd67a9b4 Missed review feedback from Stuart
fbd67a9b4 is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/fbd67a9b4feb64e4cde4b52aec1400b0bf330476/
Commit: fbd67a9b4feb64e4cde4b52aec1400b0bf330476
Author: James Turner
Committer: James Turner
AuthorDate: Sat Aug 1 16:14:03 2026 +0100
Missed review feedback from Stuart
---
src/GUI/LauncherController.hxx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/GUI/LauncherController.hxx b/src/GUI/LauncherController.hxx
index cec80476a..03089fbc2 100644
--- a/src/GUI/LauncherController.hxx
+++ b/src/GUI/LauncherController.hxx
@@ -313,10 +313,10 @@ private:
AircraftFilterModel* m_aircraftFilterModel = nullptr;
AircraftInstalledModel* m_aircraftInstalledModel = nullptr;
- AircraftItemModel* m_aircraftModel;
- AircraftSearchModel* m_aircraftSearchModel;
- AircraftUpdatesModel* m_aircraftWithUpdatesModel;
- AircraftFavouritesModel* m_favouriteAircraftModel;
+ AircraftItemModel* m_aircraftModel = nullptr;
+ AircraftSearchModel* m_aircraftSearchModel = nullptr;
+ AircraftUpdatesModel* m_aircraftWithUpdatesModel = nullptr;
+ AircraftFavouritesModel* m_favouriteAircraftModel = nullptr ;
MPServersModel* m_serversModel = nullptr;
LocationController* m_location = nullptr;
|
|
From: <fli...@li...> - 2026-07-31 22:29:53
|
unknown user pushed a commit to branch release/2024.1
in repository simgear.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new 6611ebac Fix a race in TS::isDirSyncing
6611ebac is described below
SF URL: http://sourceforge.net/p/flightgear/simgear/ci/6611ebac8246523bccf6970a46f92cab1c674e48/
Commit: 6611ebac8246523bccf6970a46f92cab1c674e48
Author: James Turner
Committer: James Turner
AuthorDate: Thu Jul 30 09:12:36 2026 +0100
Fix a race in TS::isDirSyncing
---
simgear/scene/tsync/terrasync.cxx | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/simgear/scene/tsync/terrasync.cxx b/simgear/scene/tsync/terrasync.cxx
index 65dc93c8..f3f1c24e 100644
--- a/simgear/scene/tsync/terrasync.cxx
+++ b/simgear/scene/tsync/terrasync.cxx
@@ -616,17 +616,23 @@ void SGTerraSync::WorkerThread::updateSyncSlot(SyncSlot &slot)
}
// whatever happened, we're done with this repository instance
- slot.busy = false;
- slot.repository.reset();
- slot.pendingKBytes = 0;
- slot.pendingExtractKBytes = 0;
- slot.currentItem = {};
+ {
+ std::lock_guard<std::mutex> g(_stateLock);
+ slot.busy = false;
+ slot.repository.reset();
+ slot.pendingKBytes = 0;
+ slot.pendingExtractKBytes = 0;
+ slot.currentItem = {};
+ }
}
// init and start sync of the next repository
if (!slot.queue.empty()) {
- slot.currentItem = slot.queue.front();
- slot.queue.pop_front();
+ {
+ std::lock_guard<std::mutex> g(_stateLock);
+ slot.currentItem = slot.queue.front();
+ slot.queue.pop_front();
+ }
SGPath path(_local_dir);
path.append(slot.currentItem._dir);
@@ -898,7 +904,10 @@ void SGTerraSync::WorkerThread::drainWaitingTiles()
SyncItem next = waitingTiles.pop_front();
const auto slot = syncSlotForType(next._type);
SG_LOG(SG_TERRASYNC, SG_DEBUG, "adding to _syncSlots slot=" << slot);
- _syncSlots[slot].queue.push_back(next);
+ {
+ std::lock_guard<std::mutex> g(_stateLock);
+ _syncSlots[slot].queue.push_back(next);
+ }
}
}
|
|
From: <fli...@li...> - 2026-07-31 22:26:58
|
unknown user pushed a commit to branch next
in repository flightgear.
The following commit(s) were added to refs/heads/next by this push:
new 5e15864c1 Tests for Phi/WebSocket backends
5e15864c1 is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/5e15864c15cde751bbb2eeaf07c61a7b56f452fb/
Commit: 5e15864c15cde751bbb2eeaf07c61a7b56f452fb
Author: James Turner
Committer: James Turner
AuthorDate: Wed Jul 29 14:08:20 2026 +0100
Tests for Phi/WebSocket backends
---
src/Network/http/MirrorPropertyTreeWebsocket.cxx | 19 +--
test_suite/unit_tests/Network/CMakeLists.txt | 12 +-
test_suite/unit_tests/Network/TestSuite.cxx | 10 +-
test_suite/unit_tests/Network/httpTestHelpers.hxx | 66 ++++++++
.../unit_tests/Network/test_JsonUriHandler.cxx | 71 +++++++++
.../unit_tests/Network/test_JsonUriHandler.hxx | 31 ++++
.../Network/test_MirrorPropertyTreeWebsocket.cxx | 167 +++++++++++++++++++++
.../Network/test_MirrorPropertyTreeWebsocket.hxx | 47 ++++++
.../Network/test_PropertyChangeWebsocket.cxx | 115 ++++++++++++++
.../Network/test_PropertyChangeWebsocket.hxx | 42 ++++++
10 files changed, 569 insertions(+), 11 deletions(-)
diff --git a/src/Network/http/MirrorPropertyTreeWebsocket.cxx b/src/Network/http/MirrorPropertyTreeWebsocket.cxx
index 144a93dca..e34a197fb 100644
--- a/src/Network/http/MirrorPropertyTreeWebsocket.cxx
+++ b/src/Network/http/MirrorPropertyTreeWebsocket.cxx
@@ -201,12 +201,13 @@ using std::string;
auto it = idHash.find(child);
if (it != idHash.end()) {
- removedNodes.insert(it->second);
+ const auto id = it->second; // save before erase invalidates the iterator
+ removedNodes.insert(id);
idHash.erase(it);
// record so we can map removed+add of the same property into
// a simple value change (this happens commonly with the canvas
// due to lazy Nasal scripting)
- recentlyRemoved.emplace_back(child, it->second);
+ recentlyRemoved.emplace_back(child, id);
#if defined (MIRROR_DEBUG)
SG_LOG(SG_NETWORK, SG_INFO, "adding RR:" << recentlyRemoved.back().path);
#endif
@@ -374,16 +375,16 @@ static void handleExecCommand(cJSON* json)
}
#endif
-MirrorPropertyTreeWebsocket::MirrorPropertyTreeWebsocket(const std::string& path) :
- _rootPath(path),
- _listener(new MirrorTreeListener),
- _minSendInterval(100)
-{
- checkNodeExists();
-}
+ MirrorPropertyTreeWebsocket::MirrorPropertyTreeWebsocket(const std::string& path) : _rootPath(path),
+ _listener(new MirrorTreeListener),
+ _minSendInterval(fgGetInt("/sim/http/mirror-websocket/update-interval-ms", 100))
+ {
+ checkNodeExists();
+ }
MirrorPropertyTreeWebsocket::~MirrorPropertyTreeWebsocket()
{
+ close();
}
void MirrorPropertyTreeWebsocket::close()
diff --git a/test_suite/unit_tests/Network/CMakeLists.txt b/test_suite/unit_tests/Network/CMakeLists.txt
index d0bc758ff..95f39fda7 100644
--- a/test_suite/unit_tests/Network/CMakeLists.txt
+++ b/test_suite/unit_tests/Network/CMakeLists.txt
@@ -1,7 +1,17 @@
# SPDX-FileCopyrightText: 2016 Edward d'Auvergne
# SPDX-License-Identifier: GPL-2.0-or-later
-target_sources(fgfs_test_suite PRIVATE TestSuite.cxx)
+target_sources(fgfs_test_suite PRIVATE
+ TestSuite.cxx
+ httpTestHelpers.hxx
+ test_JsonUriHandler.cxx test_JsonUriHandler.hxx
+ test_PropertyChangeWebsocket.cxx test_PropertyChangeWebsocket.hxx
+ test_MirrorPropertyTreeWebsocket.cxx test_MirrorPropertyTreeWebsocket.hxx
+)
+
+fg_add_test_suite(JsonUriHandlerTests u)
+fg_add_test_suite(PropertyChangeWebsocketTests u)
+fg_add_test_suite(MirrorPropertyTreeWebsocketTests u)
if(ENABLE_SWIFT)
target_sources(fgfs_test_suite PRIVATE
diff --git a/test_suite/unit_tests/Network/TestSuite.cxx b/test_suite/unit_tests/Network/TestSuite.cxx
index 217dcda57..984de7d5c 100644
--- a/test_suite/unit_tests/Network/TestSuite.cxx
+++ b/test_suite/unit_tests/Network/TestSuite.cxx
@@ -5,6 +5,14 @@
#include "config.h"
+#include "test_JsonUriHandler.hxx"
+#include "test_MirrorPropertyTreeWebsocket.hxx"
+#include "test_PropertyChangeWebsocket.hxx"
+
+// HTTP handler and websocket unit tests
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(JsonUriHandlerTests, "Unit tests");
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(PropertyChangeWebsocketTests, "Unit tests");
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(MirrorPropertyTreeWebsocketTests, "Unit tests");
#if defined(ENABLE_SWIFT)
#include "test_swiftAircraftManager.hxx"
@@ -14,4 +22,4 @@
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SwiftAircraftManagerTest, "Unit tests");
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SwiftServiceTest, "Unit tests");
-#endif
\ No newline at end of file
+#endif
diff --git a/test_suite/unit_tests/Network/httpTestHelpers.hxx b/test_suite/unit_tests/Network/httpTestHelpers.hxx
new file mode 100644
index 000000000..e640e72d3
--- /dev/null
+++ b/test_suite/unit_tests/Network/httpTestHelpers.hxx
@@ -0,0 +1,66 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#include <Network/http/HTTPRequest.hxx>
+#include <Network/http/Websocket.hxx>
+#include <Network/http/urihandler.hxx>
+
+#include <string>
+#include <vector>
+
+namespace FGTestApi {
+namespace http {
+
+/**
+ * Captures every frame written to a websocket during a test.
+ * Only text (opcode 1) and binary (opcode 2) frames are stored;
+ * control frames (ping/pong/close) are silently acknowledged.
+ */
+class MockWebsocketWriter : public flightgear::http::WebsocketWriter
+{
+public:
+ int writeToWebsocket(int opcode, const char* data, size_t len) override
+ {
+ if (opcode == 1 || opcode == 2) {
+ frames.emplace_back(data, len);
+ }
+ return static_cast<int>(len);
+ }
+
+ std::vector<std::string> frames;
+};
+
+/**
+ * Minimal Connection stub for URI handler tests.
+ * Stores key/value connection data (via the base class map) and
+ * captures any raw bytes written via write().
+ */
+class MockConnection : public flightgear::http::Connection
+{
+public:
+ void write(const char* data, size_t len) override
+ {
+ written.append(data, len);
+ }
+
+ std::string written;
+};
+
+/**
+ * Convenience factory for building HTTPRequest objects in tests.
+ */
+inline flightgear::http::HTTPRequest buildRequest(
+ const std::string& method,
+ const std::string& uri,
+ const std::string& content = {})
+{
+ flightgear::http::HTTPRequest req;
+ req.Method = method;
+ req.Uri = uri;
+ req.Content = content;
+ return req;
+}
+
+} // namespace http
+} // namespace FGTestApi
diff --git a/test_suite/unit_tests/Network/test_JsonUriHandler.cxx b/test_suite/unit_tests/Network/test_JsonUriHandler.cxx
new file mode 100644
index 000000000..00435c04c
--- /dev/null
+++ b/test_suite/unit_tests/Network/test_JsonUriHandler.cxx
@@ -0,0 +1,71 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "test_JsonUriHandler.hxx"
+#include "httpTestHelpers.hxx"
+
+#include "test_suite/FGTestApi/testGlobals.hxx"
+
+#include <Main/fg_props.hxx>
+#include <Network/http/HTTPResponse.hxx>
+#include <Network/http/JsonUriHandler.hxx>
+
+#include <nlohmann/json.hpp>
+
+using namespace flightgear::http;
+using namespace FGTestApi::http;
+
+void JsonUriHandlerTests::setUp()
+{
+ FGTestApi::setUp::initTestGlobals("JsonUriHandler");
+}
+
+void JsonUriHandlerTests::tearDown()
+{
+ FGTestApi::tearDown::shutdownTestGlobals();
+}
+
+// ---------------------------------------------------------------------------
+
+void JsonUriHandlerTests::testGetExistingProperty()
+{
+ fgSetString("/test/aircraft", "c172p");
+
+ JsonUriHandler handler("/json/");
+ auto req = buildRequest("GET", "/json/test/aircraft");
+ HTTPResponse resp;
+
+ bool handled = handler.handleRequest(req, resp, nullptr);
+ CPPUNIT_ASSERT(handled);
+ CPPUNIT_ASSERT_EQUAL(200, resp.StatusCode);
+
+ auto json = nlohmann::json::parse(resp.Content);
+ CPPUNIT_ASSERT_EQUAL(std::string("c172p"), json.at("value").get<std::string>());
+ CPPUNIT_ASSERT_EQUAL(std::string("/test/aircraft"), json.at("path").get<std::string>());
+}
+
+void JsonUriHandlerTests::testGetMissingProperty()
+{
+ JsonUriHandler handler("/json/");
+ auto req = buildRequest("GET", "/json/this/does/not/exist");
+ HTTPResponse resp;
+
+ bool handled = handler.handleRequest(req, resp, nullptr);
+ CPPUNIT_ASSERT(handled);
+ CPPUNIT_ASSERT_EQUAL(404, resp.StatusCode);
+}
+
+void JsonUriHandlerTests::testPostProperty()
+{
+ fgSetString("/test/writable", "original");
+
+ JsonUriHandler handler("/json/");
+ // The JSON body uses {"value":...} to update the node at the URI directly
+ auto req = buildRequest("POST", "/json/test/writable", R"({"value":"updated"})");
+ HTTPResponse resp;
+
+ bool handled = handler.handleRequest(req, resp, nullptr);
+ CPPUNIT_ASSERT(handled);
+ CPPUNIT_ASSERT_EQUAL(200, resp.StatusCode);
+ CPPUNIT_ASSERT_EQUAL(std::string("updated"), std::string(fgGetString("/test/writable")));
+}
diff --git a/test_suite/unit_tests/Network/test_JsonUriHandler.hxx b/test_suite/unit_tests/Network/test_JsonUriHandler.hxx
new file mode 100644
index 000000000..95f090791
--- /dev/null
+++ b/test_suite/unit_tests/Network/test_JsonUriHandler.hxx
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+/**
+ * Tests for JsonUriHandler — the plain HTTP GET/POST interface to the
+ * property tree. These tests exercise the synchronous request/response
+ * path without any real HTTP server.
+ */
+class JsonUriHandlerTests : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(JsonUriHandlerTests);
+ CPPUNIT_TEST(testGetExistingProperty);
+ CPPUNIT_TEST(testGetMissingProperty);
+ CPPUNIT_TEST(testPostProperty);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp();
+ void tearDown();
+
+ // GET an existing property node → 200 with JSON value
+ void testGetExistingProperty();
+ // GET a path that has no property node → 404
+ void testGetMissingProperty();
+ // POST a new JSON value → property updated in the tree
+ void testPostProperty();
+};
diff --git a/test_suite/unit_tests/Network/test_MirrorPropertyTreeWebsocket.cxx b/test_suite/unit_tests/Network/test_MirrorPropertyTreeWebsocket.cxx
new file mode 100644
index 000000000..0e4d873d2
--- /dev/null
+++ b/test_suite/unit_tests/Network/test_MirrorPropertyTreeWebsocket.cxx
@@ -0,0 +1,167 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "test_MirrorPropertyTreeWebsocket.hxx"
+#include "httpTestHelpers.hxx"
+
+#include "test_suite/FGTestApi/testGlobals.hxx"
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Network/http/MirrorPropertyTreeWebsocket.hxx>
+
+#include <simgear/props/props.hxx>
+
+#include <nlohmann/json.hpp>
+
+using namespace flightgear::http;
+using namespace FGTestApi::http;
+
+// Helper: drain the initial "created" frame emitted when a websocket first
+// registers a pre-existing sub-tree, then clear the frame list.
+static void drainInitialFrame(MirrorPropertyTreeWebsocket& ws, MockWebsocketWriter& writer)
+{
+ ws.poll(writer);
+ writer.frames.clear();
+}
+
+void MirrorPropertyTreeWebsocketTests::setUp()
+{
+ FGTestApi::setUp::initTestGlobals("MirrorPropertyTreeWebsocket");
+ // Disable the send-rate throttle so every poll() fires immediately.
+ // This value is read by the MirrorPropertyTreeWebsocket constructor.
+ fgSetInt("/sim/http/mirror-websocket/update-interval-ms", 0);
+
+ // Production code sets VALUE_CHANGED_DOWN on /sim so that value changes
+ // on any descendant propagate up to ancestor listeners. Replicate that
+ // for the /test namespace used by these tests.
+ fgGetNode("/test", true)->setAttribute(SGPropertyNode::VALUE_CHANGED_DOWN, true);
+}
+
+void MirrorPropertyTreeWebsocketTests::tearDown()
+{
+ FGTestApi::tearDown::shutdownTestGlobals();
+}
+
+// ---------------------------------------------------------------------------
+
+void MirrorPropertyTreeWebsocketTests::testInitialSubtreeSent()
+{
+ // Build the sub-tree before constructing the websocket so the listener
+ // picks it up via registerSubtree() in checkNodeExists().
+ fgSetString("/test/mirror/name", "FlightGear");
+ fgSetDouble("/test/mirror/altitude", 10000.0);
+
+ MirrorPropertyTreeWebsocket ws("/test/mirror");
+ MockWebsocketWriter writer;
+
+ ws.poll(writer);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), writer.frames.size());
+ auto json = nlohmann::json::parse(writer.frames.front());
+
+ // The initial frame must contain a "created" array with our nodes
+ CPPUNIT_ASSERT(json.contains("created"));
+ CPPUNIT_ASSERT(!json.at("created").empty());
+}
+
+void MirrorPropertyTreeWebsocketTests::testNewChildSent()
+{
+ fgSetString("/test/mirror2/existing", "here");
+
+ MirrorPropertyTreeWebsocket ws("/test/mirror2");
+ MockWebsocketWriter writer;
+ drainInitialFrame(ws, writer);
+
+ // Add a new child after the websocket is already connected
+ fgSetDouble("/test/mirror2/newchild", 42.0);
+ ws.poll(writer);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), writer.frames.size());
+ auto json = nlohmann::json::parse(writer.frames.front());
+
+ CPPUNIT_ASSERT(json.contains("created"));
+ const auto& created = json.at("created");
+ bool found = false;
+ for (const auto& entry : created) {
+ if (entry.value("path", std::string{}) == "/test/mirror2/newchild") {
+ found = true;
+ break;
+ }
+ }
+ CPPUNIT_ASSERT_MESSAGE("new child not found in 'created'", found);
+}
+
+void MirrorPropertyTreeWebsocketTests::testValueChangeSent()
+{
+ fgSetDouble("/test/mirror3/speed", 100.0);
+
+ MirrorPropertyTreeWebsocket ws("/test/mirror3");
+ MockWebsocketWriter writer;
+ drainInitialFrame(ws, writer);
+
+ // Change the value; the listener will pick this up synchronously
+ fgSetDouble("/test/mirror3/speed", 250.0);
+ ws.poll(writer);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), writer.frames.size());
+ auto json = nlohmann::json::parse(writer.frames.front());
+
+ // A "changed" array should be present — it contains [id, newValue] pairs
+ CPPUNIT_ASSERT(json.contains("changed"));
+ CPPUNIT_ASSERT(!json.at("changed").empty());
+}
+
+void MirrorPropertyTreeWebsocketTests::testRemovedChildSent()
+{
+ fgSetString("/test/mirror4/child", "toremove");
+
+ MirrorPropertyTreeWebsocket ws("/test/mirror4");
+ MockWebsocketWriter writer;
+ drainInitialFrame(ws, writer);
+
+ // Remove the child node
+ SGPropertyNode_ptr root = globals->get_props()->getNode("/test/mirror4");
+ CPPUNIT_ASSERT(root != nullptr);
+ root->removeChild("child", 0);
+
+ ws.poll(writer);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), writer.frames.size());
+ auto json = nlohmann::json::parse(writer.frames.front());
+
+ // A "removed" array of integer IDs should be present
+ CPPUNIT_ASSERT(json.contains("removed"));
+ CPPUNIT_ASSERT(!json.at("removed").empty());
+}
+
+void MirrorPropertyTreeWebsocketTests::testDeleteAndReAddAppearsAsChange()
+{
+ // This simulates the Nasal pattern where a property is deleted and
+ // immediately re-created (e.g. by a Nasal timer) between two polls.
+ // The listener keeps a recentlyRemoved list so it can recognise the
+ // re-add as a recycled node and emit only a "changed" entry rather
+ // than a "removed" + "created" pair.
+ fgSetString("/test/mirror5/item", "original");
+
+ MirrorPropertyTreeWebsocket ws("/test/mirror5");
+ MockWebsocketWriter writer;
+ drainInitialFrame(ws, writer);
+
+ // Remove then immediately re-create the child, all before the next poll.
+ SGPropertyNode_ptr root = globals->get_props()->getNode("/test/mirror5");
+ CPPUNIT_ASSERT(root != nullptr);
+ root->removeChild("item", 0);
+ fgSetString("/test/mirror5/item", "updated"); // same path, new value
+
+ ws.poll(writer);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), writer.frames.size());
+ auto json = nlohmann::json::parse(writer.frames.front());
+
+ // The recycled node must appear as a value change, not a remove/create pair.
+ CPPUNIT_ASSERT_MESSAGE("unexpected 'removed' entry", !json.contains("removed"));
+ CPPUNIT_ASSERT_MESSAGE("unexpected 'created' entry", !json.contains("created"));
+ CPPUNIT_ASSERT(json.contains("changed"));
+ CPPUNIT_ASSERT(!json.at("changed").empty());
+}
diff --git a/test_suite/unit_tests/Network/test_MirrorPropertyTreeWebsocket.hxx b/test_suite/unit_tests/Network/test_MirrorPropertyTreeWebsocket.hxx
new file mode 100644
index 000000000..622a65a2b
--- /dev/null
+++ b/test_suite/unit_tests/Network/test_MirrorPropertyTreeWebsocket.hxx
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+/**
+ * Tests for MirrorPropertyTreeWebsocket — the websocket that mirrors an
+ * entire property sub-tree to a connected client.
+ *
+ * The test pattern mirrors the server's update loop:
+ * 1. Build a property sub-tree.
+ * 2. Construct MirrorPropertyTreeWebsocket (registers a recursive listener).
+ * 3. Call ws.poll() — the listener accumulates changes and the websocket
+ * serialises them as a JSON frame via MockWebsocketWriter.
+ * 4. Mutate the sub-tree and call ws.poll() again to check delta frames.
+ *
+ * The send-rate throttle is disabled by setting
+ * /sim/http/mirror-websocket/update-interval-ms = 0 before constructing.
+ */
+class MirrorPropertyTreeWebsocketTests : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(MirrorPropertyTreeWebsocketTests);
+ CPPUNIT_TEST(testInitialSubtreeSent);
+ CPPUNIT_TEST(testNewChildSent);
+ CPPUNIT_TEST(testValueChangeSent);
+ CPPUNIT_TEST(testRemovedChildSent);
+ CPPUNIT_TEST(testDeleteAndReAddAppearsAsChange);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp();
+ void tearDown();
+
+ // On first poll after construction the whole existing sub-tree is sent
+ void testInitialSubtreeSent();
+ // A child added after construction appears in the next poll frame
+ void testNewChildSent();
+ // A value change in the sub-tree appears in the next poll frame
+ void testValueChangeSent();
+ // A child removed from the sub-tree appears in the next poll frame
+ void testRemovedChildSent();
+ // A child removed and immediately re-added appears as a value change,
+ // not as a separate remove + create pair
+ void testDeleteAndReAddAppearsAsChange();
+};
diff --git a/test_suite/unit_tests/Network/test_PropertyChangeWebsocket.cxx b/test_suite/unit_tests/Network/test_PropertyChangeWebsocket.cxx
new file mode 100644
index 000000000..95b0340b6
--- /dev/null
+++ b/test_suite/unit_tests/Network/test_PropertyChangeWebsocket.cxx
@@ -0,0 +1,115 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "test_PropertyChangeWebsocket.hxx"
+#include "httpTestHelpers.hxx"
+
+#include "test_suite/FGTestApi/testGlobals.hxx"
+
+#include <Main/fg_props.hxx>
+#include <Network/http/PropertyChangeObserver.hxx>
+#include <Network/http/PropertyChangeWebsocket.hxx>
+
+#include <nlohmann/json.hpp>
+
+using namespace flightgear::http;
+using namespace FGTestApi::http;
+
+void PropertyChangeWebsocketTests::setUp()
+{
+ FGTestApi::setUp::initTestGlobals("PropertyChangeWebsocket");
+ // Disable the per-poll rate throttle so every poll() fires unconditionally.
+ // This value is read by the PropertyChangeWebsocket constructor.
+ fgSetDouble("/sim/http/property-websocket/update-interval-secs", 0.0);
+}
+
+void PropertyChangeWebsocketTests::tearDown()
+{
+ FGTestApi::tearDown::shutdownTestGlobals();
+}
+
+// ---------------------------------------------------------------------------
+
+void PropertyChangeWebsocketTests::testAddListenerAndPoll()
+{
+ fgSetString("/test/pcws/value", "hello");
+
+ PropertyChangeObserver observer;
+ PropertyChangeWebsocket ws(&observer);
+ MockWebsocketWriter writer;
+
+ // addListener registers the observation; initial _changed flag is true so
+ // the very first poll() will emit the current value without needing check()
+ auto req = buildRequest("GET", "/PropertyListener",
+ R"({"command":"addListener","node":"/test/pcws/value"})");
+ ws.handleRequest(req, writer);
+ ws.poll(writer);
+
+ CPPUNIT_ASSERT(!writer.frames.empty());
+ auto json = nlohmann::json::parse(writer.frames.back());
+ CPPUNIT_ASSERT_EQUAL(std::string("/test/pcws/value"), json.at("path").get<std::string>());
+ CPPUNIT_ASSERT_EQUAL(std::string("hello"), json.at("value").get<std::string>());
+}
+
+void PropertyChangeWebsocketTests::testGetCommand()
+{
+ fgSetDouble("/test/pcws/altitude", 5000.0);
+
+ PropertyChangeObserver observer;
+ PropertyChangeWebsocket ws(&observer);
+ MockWebsocketWriter writer;
+
+ // get returns the value immediately, without registering a listener
+ auto req = buildRequest("GET", "/PropertyListener",
+ R"({"command":"get","node":"/test/pcws/altitude"})");
+ ws.handleRequest(req, writer);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), writer.frames.size());
+ auto json = nlohmann::json::parse(writer.frames.front());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(5000.0, json.at("value").get<double>(), 1.0);
+}
+
+void PropertyChangeWebsocketTests::testSetCommand()
+{
+ fgSetDouble("/test/pcws/heading", 90.0);
+
+ PropertyChangeObserver observer;
+ PropertyChangeWebsocket ws(&observer);
+ MockWebsocketWriter writer;
+
+ auto req = buildRequest("GET", "/PropertyListener",
+ R"({"command":"set","node":"/test/pcws/heading","value":180.0})");
+ ws.handleRequest(req, writer);
+
+ // set writes to the property tree; no frame is emitted
+ CPPUNIT_ASSERT(writer.frames.empty());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(180.0, fgGetDouble("/test/pcws/heading"), 0.01);
+}
+
+void PropertyChangeWebsocketTests::testNoChangePollEmitsNothing()
+{
+ fgSetString("/test/pcws/stable", "constant");
+
+ PropertyChangeObserver observer;
+ PropertyChangeWebsocket ws(&observer);
+ MockWebsocketWriter writer;
+
+ auto req = buildRequest("GET", "/PropertyListener",
+ R"({"command":"addListener","node":"/test/pcws/stable"})");
+ ws.handleRequest(req, writer);
+
+ // The observer's _prevValue starts empty, so two full check/poll/uncheck
+ // cycles are needed before it stabilises on the current value.
+ for (int i = 0; i < 2; ++i) {
+ observer.check();
+ ws.poll(writer);
+ observer.uncheck();
+ }
+
+ // Third cycle: value is unchanged → poll must be silent
+ observer.check();
+ writer.frames.clear();
+ ws.poll(writer);
+
+ CPPUNIT_ASSERT(writer.frames.empty());
+}
diff --git a/test_suite/unit_tests/Network/test_PropertyChangeWebsocket.hxx b/test_suite/unit_tests/Network/test_PropertyChangeWebsocket.hxx
new file mode 100644
index 000000000..2129622bb
--- /dev/null
+++ b/test_suite/unit_tests/Network/test_PropertyChangeWebsocket.hxx
@@ -0,0 +1,42 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+/**
+ * Tests for PropertyChangeWebsocket — the websocket interface for watching
+ * individual property nodes for value changes.
+ *
+ * The test pattern for websocket handlers:
+ * 1. Create a MockWebsocketWriter to capture emitted JSON frames.
+ * 2. Call ws.handleRequest() to deliver a JSON command (addListener / get / set).
+ * 3. Drive the check/poll/uncheck cycle that the HTTP server normally runs.
+ * 4. Assert the frames captured by the mock writer.
+ *
+ * Rate throttling is disabled by setting
+ * /sim/http/property-websocket/update-interval-secs = 0 in setUp().
+ */
+class PropertyChangeWebsocketTests : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(PropertyChangeWebsocketTests);
+ CPPUNIT_TEST(testAddListenerAndPoll);
+ CPPUNIT_TEST(testGetCommand);
+ CPPUNIT_TEST(testSetCommand);
+ CPPUNIT_TEST(testNoChangePollEmitsNothing);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp();
+ void tearDown();
+
+ // addListener then poll → initial value frame emitted
+ void testAddListenerAndPoll();
+ // get command → value frame returned immediately
+ void testGetCommand();
+ // set command → property tree updated, no frame emitted
+ void testSetCommand();
+ // addListener, stabilise, no change → poll is silent
+ void testNoChangePollEmitsNothing();
+};
|
|
From: <fli...@li...> - 2026-07-31 22:16:56
|
unknown user pushed a commit to branch release/2024.1
in repository flightgear.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new c9b51b88f Attempt to fix FGVoiceMgr::shutdown crashes
c9b51b88f is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/c9b51b88f271b0473b2368392c25444cdf9857a2/
Commit: c9b51b88f271b0473b2368392c25444cdf9857a2
Author: James Turner
Committer: James Turner
AuthorDate: Thu Jul 30 16:40:18 2026 +0100
Attempt to fix FGVoiceMgr::shutdown crashes
---
src/Sound/flitevoice.cxx | 2 +-
src/Sound/voice.cxx | 18 +++++++++++++++++-
src/Sound/voice.hxx | 6 +++++-
3 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/src/Sound/flitevoice.cxx b/src/Sound/flitevoice.cxx
index 9499cbad5..7b122f1ba 100644
--- a/src/Sound/flitevoice.cxx
+++ b/src/Sound/flitevoice.cxx
@@ -47,7 +47,7 @@ FGFLITEVoice::FGFLITEVoice(FGVoiceMgr * mgr, const SGPropertyNode_ptr node, cons
_sgr = smgr->find(sampleGroupRefName, true);
_sgr->tie_to_listener();
- node->getNode("text", true)->addChangeListener(this);
+ listenOnTextNode(node->getNode("text", true));
SG_LOG(SG_SOUND, SG_DEBUG, "FLITEVoice initialized for sample-group '" << sampleGroupRefName
<< "'. Samples will be named '" << _sampleName << "' "
diff --git a/src/Sound/voice.cxx b/src/Sound/voice.cxx
index 441ba6370..225e68d7a 100644
--- a/src/Sound/voice.cxx
+++ b/src/Sound/voice.cxx
@@ -104,6 +104,10 @@ void FGVoiceMgr::shutdown()
for( std::vector<FGVoice*>::iterator it = _voices.begin(); it != _voices.end(); ++it )
delete *it;
+
+ // avoid dangling pointers/double-delete if shutdown() is ever called again
+ // (e.g. SGSubsystemGroup::shutdown() has no reentrancy guard)
+ _voices.clear();
}
@@ -168,7 +172,7 @@ FGFestivalVoice::FGFestivalVoice(FGVoiceMgr *mgr, const SGPropertyNode_ptr node)
setPitch(_pitch = _pitchNode->getDoubleValue());
setSpeed(_speed = _speedNode->getDoubleValue());
- node->getNode("text", true)->addChangeListener(this);
+ listenOnTextNode(node->getNode("text", true));
}
@@ -179,6 +183,18 @@ FGFestivalVoice::~FGFestivalVoice()
}
+FGVoiceMgr::FGVoice::~FGVoice()
+{
+ if (_textNode)
+ _textNode->removeChangeListener(this);
+}
+
+void FGVoiceMgr::FGVoice::listenOnTextNode(SGPropertyNode_ptr node)
+{
+ _textNode = node;
+ _textNode->addChangeListener(this);
+}
+
void FGVoiceMgr::FGVoice::pushMessage( const string & m)
{
_msg.push(m);
diff --git a/src/Sound/voice.hxx b/src/Sound/voice.hxx
index 60b73644b..873499c92 100644
--- a/src/Sound/voice.hxx
+++ b/src/Sound/voice.hxx
@@ -99,7 +99,7 @@ class FGVoiceMgr::FGVoice : public SGPropertyChangeListener
{
public:
FGVoice(FGVoiceMgr * mgr ) : _mgr(mgr) {}
- virtual ~FGVoice() {}
+ virtual ~FGVoice();
virtual void speak( const std::string & msg ) = 0;
virtual void update(double dt) = 0;
void pushMessage( const std::string & m);
@@ -107,8 +107,12 @@ public:
protected:
void valueChanged(SGPropertyNode *node);
+ // register as change listener on the given node, and remember it so the
+ // listener can be removed again in ~FGVoice()
+ void listenOnTextNode(SGPropertyNode_ptr node);
FGVoiceMgr *_mgr;
+ SGPropertyNode_ptr _textNode;
#if defined(ENABLE_THREADS)
SGLockedQueue<std::string> _msg;
|
|
From: <fli...@li...> - 2026-07-31 13:09:28
|
unknown user pushed a commit to branch next
in repository flightgear.
The following commit(s) were added to refs/heads/next by this push:
new b8c238376 Fix a crash when closing many props channels
b8c238376 is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/b8c23837639164854e19a61ba47a4660fb4e10e0/
Commit: b8c23837639164854e19a61ba47a4660fb4e10e0
Author: James Turner
Committer: James Turner
AuthorDate: Wed Jul 29 13:10:03 2026 +0100
Fix a crash when closing many props channels
---
src/Network/propsProtocol.cxx | 14 +++++++++-----
src/Network/propsProtocol.hxx | 6 +++---
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/Network/propsProtocol.cxx b/src/Network/propsProtocol.cxx
index 15ff67410..271d87125 100644
--- a/src/Network/propsProtocol.cxx
+++ b/src/Network/propsProtocol.cxx
@@ -819,11 +819,15 @@ bool FGProps::close()
// guard this, since NetChannelPoller::removeChannel must be symmetric
if (is_enabled()) {
SG_LOG(SG_IO, SG_INFO, "closing FGProps");
- for (auto channel : _activeChannels) {
+ // Swap out _activeChannels before iterating: ~PropsChannel calls removeChannel()
+ // which would otherwise modify _activeChannels during the range-for loop,
+ // causing iterator invalidation and potential use-after-free with 3+ connections.
+ std::vector<PropsChannel*> toClose;
+ std::swap(toClose, _activeChannels);
+ for (auto channel : toClose) {
channel->close();
delete channel;
}
- _activeChannels.clear();
poller.removeChannel(this);
set_enabled(false);
@@ -864,9 +868,9 @@ void FGProps::handleAccept()
void FGProps::removeChannel(FGProps::PropsChannel* channel)
{
auto it = std::find(_activeChannels.begin(), _activeChannels.end(), channel);
- if (it == _activeChannels.end()) {
- SG_LOG(SG_IO, SG_WARN, "FGProps::removeChannel: unknown channel");
- } else {
+ if (it != _activeChannels.end()) {
_activeChannels.erase(it);
}
+ // not finding the channel is expected when called from ~PropsChannel
+ // during FGProps::close(), since _activeChannels has been swapped out
}
diff --git a/src/Network/propsProtocol.hxx b/src/Network/propsProtocol.hxx
index 14733f194..9d51e7fe8 100644
--- a/src/Network/propsProtocol.hxx
+++ b/src/Network/propsProtocol.hxx
@@ -39,7 +39,7 @@ private:
public:
/**
* Create a new TCP server.
- *
+ *
* @param tokens Tokenized configuration parameters
*/
FGProps(const std::vector<std::string>& tokens);
@@ -47,7 +47,7 @@ public:
/**
* Destructor.
*/
- ~FGProps();
+ virtual ~FGProps();
/**
* Start the telnet server.
@@ -60,7 +60,7 @@ public:
bool process() override;
/**
- *
+ *
*/
bool close() override;
|
|
From: <fli...@li...> - 2026-07-30 21:32:06
|
unknown user pushed a commit to branch next
in repository flightgear.
The following commit(s) were added to refs/heads/next by this push:
new 3c25427a3 Attempt to fix FGVoiceMgr::shutdown crashes
3c25427a3 is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/3c25427a395f9231742d0c4a65dc22a130f15a8c/
Commit: 3c25427a395f9231742d0c4a65dc22a130f15a8c
Author: James Turner
Committer: James Turner
AuthorDate: Thu Jul 30 22:31:57 2026 +0100
Attempt to fix FGVoiceMgr::shutdown crashes
---
src/Sound/flitevoice.cxx | 2 +-
src/Sound/voice.cxx | 18 +++++++++++++++++-
src/Sound/voice.hxx | 6 +++++-
3 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/src/Sound/flitevoice.cxx b/src/Sound/flitevoice.cxx
index 35e7fead3..7ab4dc803 100644
--- a/src/Sound/flitevoice.cxx
+++ b/src/Sound/flitevoice.cxx
@@ -31,7 +31,7 @@ FGFLITEVoice::FGFLITEVoice(FGVoiceMgr * mgr, const SGPropertyNode_ptr node, cons
_sgr = smgr->find(sampleGroupRefName, true);
_sgr->tie_to_listener();
- node->getNode("text", true)->addChangeListener(this);
+ listenOnTextNode(node->getNode("text", true));
SG_LOG(SG_SOUND, SG_DEBUG, "FLITEVoice initialized for sample-group '" << sampleGroupRefName
<< "'. Samples will be named '" << _sampleName << "' "
diff --git a/src/Sound/voice.cxx b/src/Sound/voice.cxx
index 4d8fb04cd..1bded0709 100644
--- a/src/Sound/voice.cxx
+++ b/src/Sound/voice.cxx
@@ -102,6 +102,10 @@ void FGVoiceMgr::shutdown()
for( std::vector<FGVoice*>::iterator it = _voices.begin(); it != _voices.end(); ++it )
delete *it;
+
+ // avoid dangling pointers/double-delete if shutdown() is ever called again
+ // (e.g. SGSubsystemGroup::shutdown() has no reentrancy guard)
+ _voices.clear();
}
@@ -166,7 +170,7 @@ FGFestivalVoice::FGFestivalVoice(FGVoiceMgr *mgr, const SGPropertyNode_ptr node)
setPitch(_pitch = _pitchNode->getDoubleValue());
setSpeed(_speed = _speedNode->getDoubleValue());
- node->getNode("text", true)->addChangeListener(this);
+ listenOnTextNode(node->getNode("text", true));
}
@@ -177,6 +181,18 @@ FGFestivalVoice::~FGFestivalVoice()
}
+FGVoiceMgr::FGVoice::~FGVoice()
+{
+ if (_textNode)
+ _textNode->removeChangeListener(this);
+}
+
+void FGVoiceMgr::FGVoice::listenOnTextNode(SGPropertyNode_ptr node)
+{
+ _textNode = node;
+ _textNode->addChangeListener(this);
+}
+
void FGVoiceMgr::FGVoice::pushMessage( const string & m)
{
_msg.push(m);
diff --git a/src/Sound/voice.hxx b/src/Sound/voice.hxx
index 60861c485..1eb575b78 100644
--- a/src/Sound/voice.hxx
+++ b/src/Sound/voice.hxx
@@ -84,7 +84,7 @@ class FGVoiceMgr::FGVoice : public SGPropertyChangeListener
{
public:
FGVoice(FGVoiceMgr * mgr ) : _mgr(mgr) {}
- virtual ~FGVoice() {}
+ virtual ~FGVoice();
virtual void speak( const std::string & msg ) = 0;
virtual void update(double dt) = 0;
void pushMessage( const std::string & m);
@@ -92,8 +92,12 @@ public:
protected:
void valueChanged(SGPropertyNode *node);
+ // register as change listener on the given node, and remember it so the
+ // listener can be removed again in ~FGVoice()
+ void listenOnTextNode(SGPropertyNode_ptr node);
FGVoiceMgr *_mgr;
+ SGPropertyNode_ptr _textNode;
#if defined(ENABLE_THREADS)
SGLockedQueue<std::string> _msg;
|
|
From: <fli...@li...> - 2026-07-30 09:49:23
|
unknown user pushed a commit to branch release/2024.1
in repository flightgear.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new 45b0e0498 FGCom: Add some extra checks to xmit
45b0e0498 is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/45b0e04983c8013fc2f3b6a749a51b21f195d7df/
Commit: 45b0e04983c8013fc2f3b6a749a51b21f195d7df
Author: James Turner
Committer: James Turner
AuthorDate: Thu Jul 30 10:49:15 2026 +0100
FGCom: Add some extra checks to xmit
---
3rdparty/iaxclient/lib/libiax2/src/iax.c | 42 ++++++++++++++++++++------------
1 file changed, 26 insertions(+), 16 deletions(-)
diff --git a/3rdparty/iaxclient/lib/libiax2/src/iax.c b/3rdparty/iaxclient/lib/libiax2/src/iax.c
index 37b0171cc..619e7c4bc 100644
--- a/3rdparty/iaxclient/lib/libiax2/src/iax.c
+++ b/3rdparty/iaxclient/lib/libiax2/src/iax.c
@@ -857,6 +857,10 @@ static int get_sample_cnt(struct iax_event *e)
static int iax_xmit_frame(struct iax_frame *f)
{
int res;
+ if (!f->session) {
+ IAXERROR "No session in iax_xmit_frame");
+ return -1;
+ }
#ifdef DEBUG_SUPPORT
if (debug) {
struct ast_iax2_full_hdr *h = (struct ast_iax2_full_hdr *)f->data;
@@ -868,10 +872,6 @@ static int iax_xmit_frame(struct iax_frame *f)
f->datalen - sizeof(struct ast_iax2_full_hdr));
}
#endif
- if (!f->session) {
- IAXERROR "No session in iax_xmit_frame");
- return -1;
- }
/* Send the frame raw */
res = f->session->sendto(netfd, (const char *) f->data, f->datalen,
@@ -898,6 +898,7 @@ static int iax_reliable_xmit(struct iax_frame *f)
if (!fc->data || !fc->datalen) {
IAXERROR "No frame data?");
DEBU(G "No frame data?\n");
+ free(fc);
return -1;
} else {
fc->data = (char *)malloc(fc->datalen);
@@ -930,8 +931,8 @@ int iax_init(int preferredportno)
{
int portno = preferredportno;
#ifndef _MSC_VER // avoid compare of address of imported function
- /* MSVC only - In certain circumstances the addresses placed in iax_sendto and iax_recvfrom
- can be an offset to a jump table, making a compare of the current address to the address
+ /* MSVC only - In certain circumstances the addresses placed in iax_sendto and iax_recvfrom
+ can be an offset to a jump table, making a compare of the current address to the address
of the actual imported function fail. */
if (iax_recvfrom == (iax_recvfrom_t)recvfrom)
#endif // !_MSC_VER
@@ -1149,7 +1150,7 @@ static int iax_send(struct iax_session *pvt, struct ast_frame *f, unsigned int t
now = 0;
sendmini = 0;
}
-
+
/* Allocate an iax_frame */
if (now)
{
@@ -1163,7 +1164,7 @@ static int iax_send(struct iax_session *pvt, struct ast_frame *f, unsigned int t
return -1;
}
}
-
+
/* Copy our prospective frame into our immediate or retransmitted wrapper */
iax_frame_wrap(fr, f);
@@ -2303,7 +2304,7 @@ static int forward_match(struct sockaddr_in *sin, short callno, short dcallno, s
if (cur->peercallno == 0) {
cur->peercallno = callno;
}
- else if ( cur->peercallno != callno )
+ else if ( cur->peercallno != callno )
{
// print a warning when the callno's don't match
fprintf( stderr, "WARNING: peercallno does not match callno"
@@ -2677,8 +2678,8 @@ static struct iax_event *iax_header_to_event(struct iax_session *session, struct
/* If it's not an ACK packet, it's out of order. */
DEBU(G "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n",
session->iseqno, fh->oseqno, fh->type, subclass);
-
- /*
+
+ /*
* Check if session->iseqno > fh->oseqno, accounting for possible wrap around
* This is correct if the two values are not equal (which, in this case, is guaranteed)
*/
@@ -3363,16 +3364,25 @@ struct iax_event *iax_get_event(int blocking)
frame->retrytime = 1000;
fh = (struct ast_iax2_full_hdr *)(frame->data);
fh->dcallno = htons(IAX_FLAG_RETRANS | frame->dcallno);
- iax_xmit_frame(frame);
- /* Schedule another retransmission */
- DEBU(G "Scheduling retransmission %d\n", frame->retries);
- iax_sched_add(NULL, frame, NULL, NULL, frame->retrytime);
+ if (iax_session_valid(frame->session)) {
+ iax_xmit_frame(frame);
+ /* Schedule another retransmission */
+ DEBU(G "Scheduling retransmission %d\n", frame->retries);
+ iax_sched_add(NULL, frame, NULL, NULL, frame->retrytime);
+ } else {
+ if (frame->data)
+ free(frame->data);
+ free(frame);
+ free(cur);
+ cur = NULL;
+ }
}
} else if (cur->func)
{
cur->func(cur->arg);
}
- free(cur);
+ if (cur)
+ free(cur);
}
/* get jitterbuffer-scheduled events */
|
|
From: <fli...@li...> - 2026-07-29 09:11:12
|
unknown user pushed a commit to branch release/2024.1
in repository flightgear.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new ceb1a5de8 Fix a crash when closing many props channels
ceb1a5de8 is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/ceb1a5de81f295d84a449e4409b69910d9c7a016/
Commit: ceb1a5de81f295d84a449e4409b69910d9c7a016
Author: James Turner
Committer: James Turner
AuthorDate: Wed Jul 29 09:16:08 2026 +0100
Fix a crash when closing many props channels
---
src/Network/propsProtocol.cxx | 14 +++++++++-----
src/Network/propsProtocol.hxx | 6 +++---
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/Network/propsProtocol.cxx b/src/Network/propsProtocol.cxx
index edc403f27..90a0b1282 100644
--- a/src/Network/propsProtocol.cxx
+++ b/src/Network/propsProtocol.cxx
@@ -819,11 +819,15 @@ bool FGProps::close()
// guard this, since NetChannelPoller::removeChannel must be symmetric
if (is_enabled()) {
SG_LOG(SG_IO, SG_INFO, "closing FGProps");
- for (auto channel : _activeChannels) {
+ // Swap out _activeChannels before iterating: ~PropsChannel calls removeChannel()
+ // which would otherwise modify _activeChannels during the range-for loop,
+ // causing iterator invalidation and potential use-after-free with 3+ connections.
+ std::vector<PropsChannel*> toClose;
+ std::swap(toClose, _activeChannels);
+ for (auto channel : toClose) {
channel->close();
delete channel;
}
- _activeChannels.clear();
poller.removeChannel(this);
set_enabled(false);
@@ -864,9 +868,9 @@ void FGProps::handleAccept()
void FGProps::removeChannel(FGProps::PropsChannel* channel)
{
auto it = std::find(_activeChannels.begin(), _activeChannels.end(), channel);
- if (it == _activeChannels.end()) {
- SG_LOG(SG_IO, SG_WARN, "FGProps::removeChannel: unknown channel");
- } else {
+ if (it != _activeChannels.end()) {
_activeChannels.erase(it);
}
+ // not finding the channel is expected when called from ~PropsChannel
+ // during FGProps::close(), since _activeChannels has been swapped out
}
diff --git a/src/Network/propsProtocol.hxx b/src/Network/propsProtocol.hxx
index 14733f194..9d51e7fe8 100644
--- a/src/Network/propsProtocol.hxx
+++ b/src/Network/propsProtocol.hxx
@@ -39,7 +39,7 @@ private:
public:
/**
* Create a new TCP server.
- *
+ *
* @param tokens Tokenized configuration parameters
*/
FGProps(const std::vector<std::string>& tokens);
@@ -47,7 +47,7 @@ public:
/**
* Destructor.
*/
- ~FGProps();
+ virtual ~FGProps();
/**
* Start the telnet server.
@@ -60,7 +60,7 @@ public:
bool process() override;
/**
- *
+ *
*/
bool close() override;
|
|
From: <fli...@li...> - 2026-07-29 07:21:09
|
unknown user pushed a commit to branch release/2024.1
in repository simgear.
The following commit(s) were added to refs/heads/release/2024.1 by this push:
new 8f6d8817 Use dirindex.txt for TerraSync
8f6d8817 is described below
SF URL: http://sourceforge.net/p/flightgear/simgear/ci/8f6d88172ab8d8f6497b24032db096a7dfda3c6d/
Commit: 8f6d88172ab8d8f6497b24032db096a7dfda3c6d
Author: James Turner
Committer: James Turner
AuthorDate: Mon Jul 27 16:24:49 2026 +0100
Use dirindex.txt for TerraSync
---
simgear/io/HTTPRepository.cxx | 121 ++++++++++++++-------
simgear/io/test_repository.cxx | 239 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 321 insertions(+), 39 deletions(-)
diff --git a/simgear/io/HTTPRepository.cxx b/simgear/io/HTTPRepository.cxx
index 3024ac73..2c66c835 100644
--- a/simgear/io/HTTPRepository.cxx
+++ b/simgear/io/HTTPRepository.cxx
@@ -62,6 +62,10 @@ using namespace std::string_literals;
namespace {
+const auto DIR_INDEX_FILENAME = "dirindex.txt"s;
+const auto LEGACY_DIR_INDEX_FILENAME = ".dirindex"s;
+const auto DIR_HASH_FILENAME = ".dirhash"s;
+
std::string innerResultCodeAsString(HTTPRepository::ResultCode code) {
switch (code) {
case HTTPRepository::REPO_NO_ERROR:
@@ -229,9 +233,7 @@ public:
didCheck();
- SGPath fpath(absolutePath());
- fpath.append(".dirindex");
- updatedFileContents(fpath, "SELF", hash);
+ updatedFileContents(indexFilePath(true), "SELF", hash);
children.clear();
parseDirIndex(children);
@@ -241,6 +243,22 @@ public:
_repository->lastUpdatedDir = _relativePath;
}
+ SGPath indexFilePath(bool forceNewName) const
+ {
+ SGPath p = absolutePath() / DIR_INDEX_FILENAME;
+ if (forceNewName) {
+ return p;
+ }
+
+ if (p.exists()) {
+ return p;
+ }
+
+ // legacy file name
+ p = absolutePath() / LEGACY_DIR_INDEX_FILENAME;
+ return p;
+ }
+
void failedToUpdate(HTTPRepository::ResultCode status, const std::string& details)
{
if (_relativePath.empty()) {
@@ -418,7 +436,7 @@ public:
_repository->scheduleUpdateOfChildren(childDir);
}
}
- } // of repository-defined (well, .dirIndex) children iteration
+ } // of repository-defined (well, dirIndex) children iteration
// allow the filtering of orphans; this is important so that a filter
// can be used to preserve non-repo files in a directory,
@@ -471,8 +489,15 @@ public:
void removeOrphans(const PathList orphans)
{
for (const auto& o : orphans) {
- if (o.file() == ".dirindex"s) continue;
- if (o.file() == ".dirhash"s) continue;
+ // Never treat either index-file name as an orphan: during the
+ // migration period a directory may have both 'dirindex.txt' (newly
+ // written) and '.dirindex' (left over from an older client) present
+ // at the same time. Deleting the legacy file here would be safe,
+ // but is deliberately deferred so that the transition can be rolled
+ // back without data loss.
+ if (o.file() == DIR_INDEX_FILENAME) continue;
+ if (o.file() == LEGACY_DIR_INDEX_FILENAME) continue;
+ if (o.file() == DIR_HASH_FILENAME) continue;
removeChild(o);
}
}
@@ -761,7 +786,7 @@ private:
bool parseDirIndex(ChildInfoList& children)
{
- const SGPath p = absolutePath() / ".dirindex";
+ const auto p = indexFilePath(false);
if (!p.exists()) {
return false;
}
@@ -787,13 +812,13 @@ private:
if( typeData == "version" ) {
if( tokens.size() < 2 ) {
- SG_LOG(SG_TERRASYNC, SG_WARN, "malformed .dirindex file: missing version number in line '" << line << "'"
- << "\n\tparsing:" << p.utf8Str());
+ SG_LOG(SG_TERRASYNC, SG_WARN, "malformed dirindex file: missing version number in line '" << line << "'"
+ << "\n\tparsing:" << p.utf8Str());
break;
}
if( tokens[1] != "1" ) {
- SG_LOG(SG_TERRASYNC, SG_WARN, "invalid .dirindex file: wrong version number '" << tokens[1] << "' (expected 1)"
- << "\n\tparsing:" << p.utf8Str());
+ SG_LOG(SG_TERRASYNC, SG_WARN, "invalid dirindex file: wrong version number '" << tokens[1] << "' (expected 1)"
+ << "\n\tparsing:" << p.utf8Str());
break;
}
continue; // version is good, continue
@@ -804,27 +829,27 @@ private:
}
if( typeData == "time" && tokens.size() > 1 ) {
- // SG_LOG(SG_TERRASYNC, SG_INFO, ".dirindex at '" << p.str() << "' timestamp: " << tokens[1] );
+ // SG_LOG(SG_TERRASYNC, SG_INFO, "dirindex at '" << p.str() << "' timestamp: " << tokens[1] );
continue;
}
if( tokens.size() < 3 ) {
- SG_LOG(SG_TERRASYNC, SG_WARN, "malformed .dirindex file: not enough tokens in line '" << line << "' (ignoring line)"
- << "\n\tparsing:" << p.utf8Str());
+ SG_LOG(SG_TERRASYNC, SG_WARN, "malformed dirindex file: not enough tokens in line '" << line << "' (ignoring line)"
+ << "\n\tparsing:" << p.utf8Str());
continue;
}
if (typeData != "f" && typeData != "d" && typeData != "t" ) {
- SG_LOG(SG_TERRASYNC, SG_WARN, "malformed .dirindex file: invalid type in line '" << line << "', expected 't', 'd' or 'f', (ignoring line)"
- << "\n\tparsing:" << p.utf8Str());
+ SG_LOG(SG_TERRASYNC, SG_WARN, "malformed dirindex file: invalid type in line '" << line << "', expected 't', 'd' or 'f', (ignoring line)"
+ << "\n\tparsing:" << p.utf8Str());
continue;
}
// security: prevent writing outside the repository via ../../.. filenames
- // (valid filenames never contain / - subdirectories have their own .dirindex)
+ // (valid filenames never contain / - subdirectories have their own dirindex)
if ((tokens[1] == "..") || (tokens[1].find_first_of("/\\") != std::string::npos)) {
- SG_LOG(SG_TERRASYNC, SG_WARN, "malformed .dirindex file: invalid filename in line '" << line << "', (ignoring line)"
- << "\n\tparsing:" << p.utf8Str());
+ SG_LOG(SG_TERRASYNC, SG_WARN, "malformed dirindex file: invalid filename in line '" << line << "', (ignoring line)"
+ << "\n\tparsing:" << p.utf8Str());
continue;
}
@@ -869,7 +894,10 @@ private:
{
SGPath p(child.path);
if (child.type == HTTPRepository::DirectoryType) {
- p.append(".dirindex");
+ p.append(DIR_INDEX_FILENAME);
+ if (!p.exists()) {
+ p = child.path / LEGACY_DIR_INDEX_FILENAME;
+ }
}
return hashForPath(p, child.name);
}
@@ -879,7 +907,7 @@ private:
* Previously we encoded the file absolute path, but this is annoying when files
* are relocated on disk. Now we store just the relative file name, and special value
* 'SELF' for the directory itself.
- *
+ *
* @param path candidate path from existing dirhash entry
* @return std::string updated hask entry key
*/
@@ -961,7 +989,7 @@ private:
// to the file in the future if needed
continue;
}
-
+
const auto nameData = fixupEntryName(simgear::strutils::strip(tokens[0]));
const std::string timeData = simgear::strutils::strip(tokens[1]);
const std::string sizeData = simgear::strutils::strip(tokens[2]);
@@ -1413,6 +1441,16 @@ void HTTPRepoGetRequest::cancel()
_directory->didCheck();
_directory->updateChildrenAfterRefresh();
} else if (responseCode() == 404) {
+ // temporary, remove once all servers / mirrors have the new names for the index files
+ if (!_didTryLegacyName) {
+ _didTryLegacyName = true;
+ // go around again, with the fallback URL
+ setUrl(_directory->url() + "/" + LEGACY_DIR_INDEX_FILENAME);
+ SG_LOG(SG_TERRASYNC, SG_INFO, "TerraSync: falling back to legacy dir-index name for:" << url());
+ _directory->repository()->finishedRequest(this, HTTPRepoPrivate::RequestFinish::Retry);
+ return;
+ }
+
_directory->failedToUpdate(
HTTPRepository::REPO_ERROR_FILE_NOT_FOUND, "Server returned 404/NOT FOUND");
} else if (responseCode() == 304) {
@@ -1427,36 +1465,43 @@ void HTTPRepoGetRequest::cancel()
this, HTTPRepoPrivate::RequestFinish::Done);
}
- void onFail() override {
- SG_LOG(SG_TERRASYNC, SG_ALERT, "onFail(): url()=" << url() << " _directory=" << _directory
- << " responseCode()=" << responseCode());
- HTTPRepository::ResultCode code = HTTPRepository::REPO_ERROR_SOCKET;
- if (responseCode() == -1) {
- code = HTTPRepository::REPO_ERROR_CANCELLED;
- }
+ void onFail() override
+ {
+ const auto rc = responseCode();
+ SG_LOG(SG_TERRASYNC, SG_ALERT, "onFail(): url()=" << url() << " _directory=" << _directory << " responseCode()=" << rc);
+ HTTPRepository::ResultCode code = HTTPRepository::REPO_ERROR_SOCKET;
+ if (rc == -1) {
+ code = HTTPRepository::REPO_ERROR_CANCELLED;
+ }
- if (_directory) {
- _directory->failedToUpdate(code, "HTTP layer failed request for:"s + url());
- const auto doRetry = HTTPRepoPrivate::RequestFinish::Done;
- _directory->repository()->finishedRequest(this, doRetry);
- }
+ if (_directory) {
+ _directory->failedToUpdate(code, "HTTP layer failed request for:"s + url());
+ const auto doRetry = HTTPRepoPrivate::RequestFinish::Done;
+ _directory->repository()->finishedRequest(this, doRetry);
+ }
}
private:
static std::string makeUrl(HTTPDirectory* d)
{
- return d->url() + "/.dirindex";
+ return d->url() + "/" + DIR_INDEX_FILENAME;
}
SGPath pathInRepo() const
{
- SGPath p(_directory->absolutePath());
- p.append(".dirindex");
- return p;
+ // always use the new name, not the legacy name here, so we write
+ // downloaded data to the correct location.
+ return _directory->indexFilePath(true);
}
simgear::sha1nfo hashContext;
std::string body;
+ // Tracks whether we have already retried this request with the legacy
+ // '.dirindex' URL after a 404 on 'dirindex.txt'. Not reset by
+ // prepareForRetry() intentionally: on a socket-failure retry the URL
+ // is preserved as-is, so a subsequent 404 on the legacy URL correctly
+ // reports NOT_FOUND rather than triggering another fallback attempt.
+ bool _didTryLegacyName = false;
bool _isRootDir; ///< is this the repository root?
std::string _targetHash;
};
diff --git a/simgear/io/test_repository.cxx b/simgear/io/test_repository.cxx
index c1ad9a34..c33db42a 100644
--- a/simgear/io/test_repository.cxx
+++ b/simgear/io/test_repository.cxx
@@ -59,6 +59,10 @@ std::string hashForData(const std::string& d)
class TestRepoEntry;
using AccessCallback = std::function<void(TestRepoEntry &entry)>;
+enum class DirIndexServerMode { NewStyle,
+ LegacyStyle };
+DirIndexServerMode g_dirIndexMode = DirIndexServerMode::NewStyle;
+
class TestRepoEntry
{
public:
@@ -261,7 +265,7 @@ public:
std::string repoPath = path.substr(6);
bool lookingForDir = false;
- std::string::size_type suffix = repoPath.find(".dirindex");
+ std::string::size_type suffix = repoPath.find(g_dirIndexMode == DirIndexServerMode::LegacyStyle ? ".dirindex" : "dirindex.txt");
if (suffix != std::string::npos) {
lookingForDir = true;
if (suffix > 0) {
@@ -380,6 +384,62 @@ void verifyFileNotPresent(const SGPath& fsRoot, const std::string& relPath)
}
}
+// Check that a directory within a local repo clone has the expected index file
+// name. Pass expectNewName=true to assert 'dirindex.txt' is present, or false
+// to assert the legacy '.dirindex' is present.
+void verifyIndexFileName(const SGPath& fsRoot, const std::string& relDir, bool expectNewName)
+{
+ SGPath dirPath(fsRoot);
+ if (!relDir.empty()) {
+ dirPath.append(relDir);
+ }
+
+ const SGPath newNamePath = dirPath / "dirindex.txt";
+ const SGPath oldNamePath = dirPath / ".dirindex";
+ const std::string label = relDir.empty() ? "(root)" : relDir;
+
+ if (expectNewName) {
+ if (!newNamePath.exists()) {
+ throw sg_error("Expected dirindex.txt but not found in dir", label);
+ }
+ } else {
+ if (!oldNamePath.exists()) {
+ throw sg_error("Expected .dirindex but not found in dir", label);
+ }
+ // Also assert the new name has NOT been written, so that tests which
+ // check "this directory was not re-fetched" are not vacuously satisfied
+ // by a bug that writes dirindex.txt everywhere.
+ if (newNamePath.exists()) {
+ throw sg_error("Found unexpected dirindex.txt in dir expected to keep legacy name", label);
+ }
+ }
+}
+
+// Recursively rename every 'dirindex.txt' to '.dirindex' and delete every
+// '.dirhash' under 'path'. Used to simulate a local clone that was last
+// written by an older client that stored index files with the legacy name.
+void convertToLegacyIndexFiles(const SGPath& path)
+{
+ SGPath newIndex = path / "dirindex.txt";
+ SGPath oldIndex = path / ".dirindex";
+ SGPath hashFile = path / ".dirhash";
+
+ if (newIndex.exists()) {
+ if (!newIndex.rename(oldIndex)) {
+ throw sg_io_exception("convertToLegacyIndexFiles: failed to rename dirindex.txt", path);
+ }
+ }
+ if (hashFile.exists()) {
+ hashFile.remove();
+ }
+
+ simgear::Dir d(path);
+ PathList subdirs = d.children(Dir::TYPE_DIR | Dir::NO_DOT_OR_DOTDOT);
+ for (const auto& subdir : subdirs) {
+ convertToLegacyIndexFiles(subdir);
+ }
+}
+
void verifyRequestCount(const std::string& relPath, int count)
{
TestRepoEntry* entry = global_repo->findEntry(relPath);
@@ -832,6 +892,7 @@ void testRetryAfterSocketFailure(HTTP::Client *cl) {
int aaFailsRemaining = 2;
int subdirBAFailsRemaining = 2;
+
TestApi::setResponseDoneCallback(
cl, [&aaFailsRemaining, &subdirBAFailsRemaining](int curlResult,
HTTP::Request_ptr req) {
@@ -871,6 +932,176 @@ void testRetryAfterSocketFailure(HTTP::Client *cl) {
verifyRequestCount("dirB/subdirA/fileBAC", 1);
}
+// Scenario 1: old server (serves .dirindex), new client code, fresh clone.
+// The client falls back from the new name to the legacy name on the wire, but
+// always persists the downloaded index under the new 'dirindex.txt' name.
+void testLegacyServerFreshClone(HTTP::Client* cl)
+{
+ global_repo->clearRequestCounts();
+ global_repo->clearFailFlags();
+ g_dirIndexMode = DirIndexServerMode::LegacyStyle;
+
+ SGPath p(simgear::Dir::current().path());
+ p.append("http_repo_legacy_server_fresh");
+ simgear::Dir pd(p);
+ if (pd.exists()) {
+ pd.removeChildren();
+ }
+
+ std::unique_ptr<HTTPRepository> repo(new HTTPRepository(p, cl));
+ repo->setBaseUrl("http://localhost:2000/repo");
+ repo->update();
+ waitForUpdateComplete(cl, repo.get());
+
+ g_dirIndexMode = DirIndexServerMode::NewStyle;
+
+ if (repo->failure() != HTTPRepository::REPO_NO_ERROR) {
+ throw sg_exception("Legacy server fresh clone failed with error: " +
+ HTTPRepository::resultCodeAsString(repo->failure()));
+ }
+
+ verifyFileState(p, "fileA");
+ verifyFileState(p, "dirB/subdirA/fileBAA");
+ verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA");
+
+ // Even though the server only served .dirindex, the client must save the
+ // index under the new name at all directory levels.
+ verifyIndexFileName(p, "", true);
+ verifyIndexFileName(p, "dirA", true);
+ verifyIndexFileName(p, "dirB", true);
+ verifyIndexFileName(p, "dirB/subdirA", true);
+ verifyIndexFileName(p, "dirC", true);
+
+ std::cout << "Passed test: legacy server fresh clone uses new local index file names" << std::endl;
+}
+
+// Scenario 2: existing local clone that has old-style '.dirindex' files.
+// After an update in which some directories change, those directories have
+// their index file migrated to the new name; unchanged directories keep the
+// legacy name.
+void testLegacyLocalFilesUpdate(HTTP::Client* cl)
+{
+ global_repo->clearRequestCounts();
+ global_repo->clearFailFlags();
+
+ SGPath p(simgear::Dir::current().path());
+ p.append("http_repo_legacy_local_update");
+ simgear::Dir pd(p);
+ if (pd.exists()) {
+ pd.removeChildren();
+ }
+
+ // Step 1: fresh clone with new-style server to populate the local tree.
+ {
+ std::unique_ptr<HTTPRepository> repo(new HTTPRepository(p, cl));
+ repo->setBaseUrl("http://localhost:2000/repo");
+ repo->update();
+ waitForUpdateComplete(cl, repo.get());
+
+ if (repo->failure() != HTTPRepository::REPO_NO_ERROR) {
+ throw sg_exception("Initial clone in legacy local files test failed");
+ }
+ }
+ cl->clearAllConnections();
+
+ // Step 2: simulate a clone that was last written by an old client by
+ // renaming all index files to the legacy name and clearing hash caches.
+ // Without clearing the caches the stale entries for 'dirindex.txt' would
+ // make every directory look out-of-date regardless of actual content.
+ convertToLegacyIndexFiles(p);
+
+ verifyIndexFileName(p, "", false);
+ verifyIndexFileName(p, "dirA", false);
+ verifyIndexFileName(p, "dirB/subdirA", false);
+
+ // Step 3: modify a subset of the server-side repo.
+ global_repo->findEntry("dirB/subdirA/fileBAA")->revision++;
+ global_repo->defineFile("dirC/fileCX");
+ global_repo->clearRequestCounts();
+
+ // Step 4: update using the legacy server. The client first tries
+ // 'dirindex.txt' (404), then falls back to '.dirindex' (200) for every
+ // directory it actually fetches. The downloaded content is always saved
+ // under the new name.;
+ g_dirIndexMode = DirIndexServerMode::LegacyStyle;
+
+ {
+ std::unique_ptr<HTTPRepository> repo(new HTTPRepository(p, cl));
+ repo->setBaseUrl("http://localhost:2000/repo");
+ repo->update();
+ waitForUpdateComplete(cl, repo.get());
+
+ // Reset before any assertions that can throw.
+ g_dirIndexMode = DirIndexServerMode::NewStyle;
+
+ if (repo->failure() != HTTPRepository::REPO_NO_ERROR) {
+ throw sg_exception("Update in legacy local files test failed");
+ }
+ }
+
+ // Clean up the repo entry added for this test before the assertions so it
+ // also runs on failure paths where assertions throw. Note: verifyFileState
+ // reads from global_repo, so fileCX must still be present when we call it.
+ // We verify it first, then clean up.
+ verifyFileState(p, "dirB/subdirA/fileBAA");
+ verifyFileState(p, "dirC/fileCX");
+
+ // Directories whose content changed were re-fetched and must now have the
+ // new index file name.
+ verifyIndexFileName(p, "", true); // root: dirB and dirC hashes changed
+ verifyIndexFileName(p, "dirB", true); // subdirA hash changed
+ verifyIndexFileName(p, "dirB/subdirA", true); // fileBAA was bumped
+ verifyIndexFileName(p, "dirC", true); // fileCX was added
+
+ // Directories that were not touched keep the legacy name (and must NOT
+ // have had dirindex.txt written — verifyIndexFileName checks both sides
+ // when expectNewName=false).
+ verifyIndexFileName(p, "dirA", false);
+ verifyIndexFileName(p, "dirB/subdirB", false);
+
+ // Clean up the repo entry added for this test to avoid polluting later tests.
+ global_repo->findEntry("dirC")->removeChild("fileCX");
+
+ std::cout << "Passed test: update with legacy local index files migrates changed dirs to new name" << std::endl;
+}
+
+// Scenario 3: new server (serves dirindex.txt), fresh clone. The happy path:
+// index files must be stored under the new name at every level.
+void testNewServerFreshClone(HTTP::Client* cl)
+{
+ global_repo->clearRequestCounts();
+ global_repo->clearFailFlags();
+
+ SGPath p(simgear::Dir::current().path());
+ p.append("http_repo_new_server_fresh");
+ simgear::Dir pd(p);
+ if (pd.exists()) {
+ pd.removeChildren();
+ }
+
+ // g_serverMode is already NewStyle
+ std::unique_ptr<HTTPRepository> repo(new HTTPRepository(p, cl));
+ repo->setBaseUrl("http://localhost:2000/repo");
+ repo->update();
+ waitForUpdateComplete(cl, repo.get());
+
+ if (repo->failure() != HTTPRepository::REPO_NO_ERROR) {
+ throw sg_exception("New server fresh clone failed");
+ }
+
+ verifyFileState(p, "fileA");
+ verifyFileState(p, "dirB/subdirA/fileBAA");
+ verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA");
+
+ verifyIndexFileName(p, "", true);
+ verifyIndexFileName(p, "dirA", true);
+ verifyIndexFileName(p, "dirB", true);
+ verifyIndexFileName(p, "dirB/subdirA", true);
+ verifyIndexFileName(p, "dirC", true);
+
+ std::cout << "Passed test: new server fresh clone uses new index file names" << std::endl;
+}
+
void testPersistentSocketFailure(HTTP::Client *cl) {
global_repo->clearRequestCounts();
global_repo->clearFailFlags();
@@ -952,6 +1183,12 @@ int main(int argc, char* argv[])
testServer.disconnectAll();
cl.clearAllConnections();
+ testLegacyServerFreshClone(&cl);
+ testLegacyLocalFilesUpdate(&cl);
+ testNewServerFreshClone(&cl);
+
+ cl.clearAllConnections();
+
testServerModifyDuringSync(&cl);
testDestroyDuringSync(&cl);
|
|
From: <fli...@li...> - 2026-07-29 01:05:53
|
unknown user pushed a commit to branch next
in repository simgear.
The following commit(s) were added to refs/heads/next by this push:
new 9e4012eb Raise macOS deployment version to 11.0
9e4012eb is described below
SF URL: http://sourceforge.net/p/flightgear/simgear/ci/9e4012eb3530dd9a4822147751fee01aeaf4b30a/
Commit: 9e4012eb3530dd9a4822147751fee01aeaf4b30a
Author: James Turner
Committer: James Turner
AuthorDate: Mon Jul 27 14:23:10 2026 +0100
Raise macOS deployment version to 11.0
---
CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 215dbb2b..28f1cf18 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,7 +36,7 @@ include (GenerateExportHeader)
set(CMAKE_OSX_RPATH 1)
# macOS 10.13 needed for C++17 libc++
-set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
+set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
|
From: <fli...@li...> - 2026-07-28 07:16:42
|
unknown user pushed a commit to branch next
in repository flightgear.
The following commit(s) were added to refs/heads/next by this push:
new 0b5fab77a Add missing POSIX includes for macOS
0b5fab77a is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/0b5fab77a18ba12e2a41bd06431a3dc268b4c2fa/
Commit: 0b5fab77a18ba12e2a41bd06431a3dc268b4c2fa
Author: James Turner
Committer: James Turner
AuthorDate: Mon Jul 27 15:25:55 2026 +0100
Add missing POSIX includes for macOS
---
CMakeLists.txt | 2 +-
src/Network/ATC-Main.cxx | 13 +++++++------
src/Viewer/fg_os_osgviewer.cxx | 2 ++
3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1ee493db9..a521a9256 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -53,7 +53,7 @@ endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
-set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
+set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version")
project(FlightGear)
diff --git a/src/Network/ATC-Main.cxx b/src/Network/ATC-Main.cxx
index 6bfbe7f8b..9143ff49d 100644
--- a/src/Network/ATC-Main.cxx
+++ b/src/Network/ATC-Main.cxx
@@ -9,15 +9,16 @@
#include <simgear/compiler.h>
-#include <stdlib.h> // atoi() atof() abs()
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
-
-#include <stdio.h> //snprintf
+#include <fcntl.h>
+#include <stdio.h> //snprintf
+#include <stdlib.h> // atoi() atof() abs()
+#include <sys/stat.h>
+#include <sys/types.h>
#ifdef _WIN32
# include <io.h> //lseek, read, write
+#else
+ #include <unistd.h> //lseek, read, write
#endif
#include <string>
diff --git a/src/Viewer/fg_os_osgviewer.cxx b/src/Viewer/fg_os_osgviewer.cxx
index 35caf65b7..2129d7ade 100755
--- a/src/Viewer/fg_os_osgviewer.cxx
+++ b/src/Viewer/fg_os_osgviewer.cxx
@@ -53,6 +53,8 @@
#if defined(SG_WINDOWS)
#include <process.h> // _getpid()
+#else
+ #include <unistd.h>
#endif
using namespace std;
|
|
From: <fli...@li...> - 2026-07-27 10:06:25
|
unknown user pushed a commit to branch next
in repository simgear.
The following commit(s) were added to refs/heads/next by this push:
new 13363ac5 Refactoring: Replace boost library dependency by reimplementation
13363ac5 is described below
SF URL: http://sourceforge.net/p/flightgear/simgear/ci/13363ac5052ee70edab99a17d4135335409eff80/
Commit: 13363ac5052ee70edab99a17d4135335409eff80
Author: Thorsten Hackbarth
Committer: James Turner
AuthorDate: Mon Jul 27 11:18:36 2026 +0200
Refactoring: Replace boost library dependency by reimplementation
---
.gitlab-ci.yml | 3 +-
CMakeLists.txt | 9 +-
CMakeModules/BoostTestTargets.cmake | 260 ----------
CMakeModules/BoostTestTargetsDynamic.h | 13 -
CMakeModules/BoostTestTargetsIncluded.h | 7 -
CMakeModules/BoostTestTargetsStatic.h | 7 -
CMakeModules/ConfigureMsvc3rdParty.cmake | 22 -
simgear/CMakeLists.txt | 3 -
simgear/canvas/elements/CMakeLists.txt | 5 +-
simgear/canvas/elements/canvas_element_test.cpp | 39 +-
simgear/canvas/events/CMakeLists.txt | 5 +-
simgear/canvas/events/KeyboardEvent.cxx | 18 +-
simgear/canvas/events/event_test.cpp | 48 +-
simgear/canvas/layout/CMakeLists.txt | 5 +-
simgear/canvas/layout/canvas_layout_test.cxx | 535 +++++++++++----------
.../embedded_resources/embedded_resources_test.cxx | 48 +-
simgear/emesary/CMakeLists.txt | 2 +
simgear/misc/CMakeLists.txt | 15 +-
simgear/misc/CSSBorder.cxx | 48 +-
simgear/misc/SVGpreserveAspectRatio.cxx | 18 +-
simgear/misc/SVGpreserveAspectRatio_test.cxx | 77 ++-
simgear/misc/argparse_test.cxx | 10 +-
simgear/misc/hash_utils.hxx | 42 ++
simgear/misc/hash_utils_test.cxx | 133 +++++
simgear/misc/lru_cache.hxx | 21 +-
simgear/misc/strutils.cxx | 15 +-
simgear/misc/strutils.hxx | 1 +
simgear/misc/strutils_test.cxx | 69 +--
simgear/misc/test_macros.hxx | 38 ++
simgear/misc/type_utils.hxx | 20 +
simgear/misc/type_utils_test.cxx | 56 +++
simgear/misc/utf8tolatin1_test.cxx | 28 +-
simgear/nasal/cppbind/CMakeLists.txt | 23 +-
simgear/nasal/cppbind/Ghost.hxx | 39 +-
simgear/nasal/cppbind/NasalContext.hxx | 20 +-
simgear/nasal/cppbind/NasalHash.hxx | 116 +++--
simgear/nasal/cppbind/detail/to_nasal_helper.hxx | 4 +-
simgear/nasal/cppbind/test/TestContext.hxx | 9 +-
simgear/nasal/cppbind/test/cppbind_test.cxx | 342 ++++++-------
simgear/nasal/cppbind/test/cppbind_test_ghost.cxx | 166 ++++---
simgear/nasal/cppbind/test/nasal_gc_test.cxx | 100 ++--
simgear/nasal/cppbind/test/nasal_num_test.cxx | 89 ++--
simgear/nasal/cppbind/to_nasal.hxx | 12 +-
simgear/package/CatalogTest.cxx | 7 +-
simgear/props/propertyObject_test.cxx | 16 +-
simgear/props/props.cxx | 323 +++++++------
simgear/props/props.hxx | 1 -
simgear/scene/material/Effect.cxx | 33 +-
simgear/scene/material/Effect.hxx | 11 +-
simgear/scene/material/EffectBuilder.hxx | 142 ++++--
simgear/scene/material/EffectGeode.hxx | 85 ++--
simgear/scene/material/Technique.cxx | 22 +-
simgear/scene/model/ModelRegistry.cxx | 4 +-
simgear/scene/model/SGPickAnimation.cxx | 2 +-
simgear/scene/model/modellib.cxx | 9 +-
simgear/scene/tgdb/SGTileDetailsCallback.hxx | 26 +-
simgear/scene/util/OsgSingleton.hxx | 8 +-
simgear/structure/CMakeLists.txt | 6 +-
simgear/structure/Singleton.hxx | 6 +-
simgear/structure/StringTable.hxx | 15 +-
simgear/structure/function_list_test.cxx | 39 +-
simgear/structure/singleton.hpp | 102 ----
simgear/structure/subsystem_test.cxx | 8 +-
63 files changed, 1621 insertions(+), 1784 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fb026dfc..891ce06d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -197,7 +197,6 @@ windows-build:
# relocate our upstream deps outside the source dir, otherwise
# CMake gets sad.
- - Move-Item -Path $CI_PROJECT_DIR\boost $WIN_FG_DIR\boost
- Move-Item -Path $CI_PROJECT_DIR\msvc140 $WIN_FG_DIR\msvc140
# This is for ccache.exe.
- $Env:PATH += ";$CI_PROJECT_DIR"
@@ -243,7 +242,7 @@ macos-build:
before_script:
- export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
- export HOMEBREW_NO_INSTALL_CLEANUP=1
- - brew install ninja cmake boost c-ares ccache
+ - brew install ninja cmake c-ares ccache
- !reference [.ccache-pre_non-windows, before_script]
script:
- >
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 00ec241a..215dbb2b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -143,9 +143,8 @@ endif()
find_package(Threads REQUIRED)
-find_package(Boost REQUIRED)
-set (BOOST_CXX_FLAGS "-DBOOST_BIMAP_DISABLE_SERIALIZATION -DBOOST_NO_STDLIB_CONFIG -DBOOST_NO_AUTO_PTR -DBOOST_NO_CXX98_BINDERS")
-include(BoostTestTargets)
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+
set(SG_SOUND_USES_OPENALSOFT OFF) # default to off
@@ -190,6 +189,7 @@ else()
include(CreateOSGImportedTargets)
endif(SIMGEAR_HEADLESS)
+if(NOT SIMGEAR_HEADLESS)
# Ensure that we are using the right version of OSG
# This should probably be done by modifying FindOpenSceneGraph.cmake, but this
# is easier/faster and only requires minimal changes to OSG.
@@ -237,6 +237,7 @@ if (NOT SIMGEAR_OSG_CORRECT_VERSION)
"Please ensure that you are using the correct branch of the OSG fork."
)
endif()
+endif(NOT SIMGEAR_HEADLESS)
if(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
# As of 2020-08-01, OpenBSD's system zlib is slightly old, but it's usable
@@ -444,7 +445,7 @@ endif()
# TODO: should this be special-cased for multi-config as well?
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
include(CheckCXXFeatures)
diff --git a/CMakeModules/BoostTestTargets.cmake b/CMakeModules/BoostTestTargets.cmake
deleted file mode 100644
index 54f6d6fa..00000000
--- a/CMakeModules/BoostTestTargets.cmake
+++ /dev/null
@@ -1,260 +0,0 @@
-# SPDX-License-Identifier: BSL-1.0
-# SPDX-FileCopyrightText: 2009-2010 Iowa State University
-
-# - Add tests using boost::test
-#
-# Add this line to your test files in place of including a basic boost test header:
-# #include <BoostTestTargetConfig.h>
-#
-# If you cannot do that and must use the included form for a given test,
-# include the line
-# // OVERRIDE_BOOST_TEST_INCLUDED_WARNING
-# in the same file with the boost test include.
-#
-# include(BoostTestTargets)
-# add_boost_test(<testdriver_name> SOURCES <source1> [<more sources...>]
-# [FAIL_REGULAR_EXPRESSION <additional fail regex>]
-# [LAUNCHER <generic launcher script>]
-# [LIBRARIES <library> [<library>...]]
-# [RESOURCES <resource> [<resource>...]]
-# [TESTS <testcasename> [<testcasename>...]])
-#
-# If for some reason you need access to the executable target created,
-# it can be found in ${${testdriver_name}_TARGET_NAME} as specified when
-# you called add_boost_test
-#
-# Requires CMake 2.6 or newer (uses the 'function' command)
-#
-# Requires:
-# GetForceIncludeDefinitions
-# CopyResourcesToBuildTree
-#
-# Original Author:
-# 2009-2010 Ryan Pavlik <rp...@ia...> <ab...@ry...>
-# http://academic.cleardefinition.com
-# Iowa State University HCI Graduate Program/VRAC
-
-if(__add_boost_test)
- return()
-endif()
-set(__add_boost_test YES)
-
-set(BOOST_TEST_TARGET_PREFIX "test")
-
-if(NOT Boost_FOUND)
- find_package(Boost 1.34.0 QUIET)
-endif()
-
-if (NOT Boost_VERSION_MACRO)
- # Compatibility with pre CMP0093 (CMake 3.15)
- set(Boost_VERSION_MACRO ${Boost_VERSION})
-endif()
-
-if("${Boost_VERSION_MACRO}0" LESS "1034000")
- set(_shared_msg
- "NOTE: boost::test-based targets and tests cannot "
- "be added: boost >= 1.34.0 required but not found. "
- "(found: '${Boost_VERSION_MACRO}'; want >=103400) ")
- if(ENABLE_TESTS)
- message(FATAL_ERROR
- ${_shared_msg}
- "You may disable ENABLE_TESTS to continue without the "
- "tests.")
- else()
- message(STATUS
- ${_shared_msg}
- "ENABLE_TESTS disabled, so continuing anyway.")
- endif()
-endif()
-
-include(GetForceIncludeDefinitions)
-include(CopyResourcesToBuildTree)
-
-if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000")
- set(_boosttesttargets_libs)
- set(_boostConfig "BoostTestTargetsIncluded.h")
- if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
- find_package(Boost 1.34.0 QUIET COMPONENTS unit_test_framework)
- endif()
- if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
- set(_boosttesttargets_libs "${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}")
- if(Boost_USE_STATIC_LIBS)
- set(_boostConfig "BoostTestTargetsStatic.h")
- else()
- set(_boostConfig "BoostTestTargetsDynamic.h")
- endif()
- endif()
- get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
- configure_file("${_moddir}/${_boostConfig}"
- "${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h"
- COPYONLY)
- include_directories("${CMAKE_CURRENT_BINARY_DIR}")
-endif()
-
-function(add_boost_test _name)
- if(NOT ENABLE_TESTS)
- return()
- endif()
-
- # parse arguments
- set(_nowhere)
- set(_curdest _nowhere)
- set(_val_args
- SOURCES
- FAIL_REGULAR_EXPRESSION
- LAUNCHER
- LIBRARIES
- RESOURCES
- TESTS)
- set(_bool_args
- USE_COMPILED_LIBRARY)
- foreach(_arg ${_val_args} ${_bool_args})
- set(${_arg})
- endforeach()
- foreach(_element ${ARGN})
- list(FIND _val_args "${_element}" _val_arg_find)
- list(FIND _bool_args "${_element}" _bool_arg_find)
- if("${_val_arg_find}" GREATER "-1")
- set(_curdest "${_element}")
- elseif("${_bool_arg_find}" GREATER "-1")
- set("${_element}" ON)
- set(_curdest _nowhere)
- else()
- list(APPEND ${_curdest} "${_element}")
- endif()
- endforeach()
-
- if(_nowhere)
- message(FATAL_ERROR "Syntax error in use of add_boost_test!")
- endif()
-
- if(NOT SOURCES)
- message(FATAL_ERROR
- "Syntax error in use of add_boost_test: at least one source file required!")
- endif()
-
- if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000")
-
- include_directories(${Boost_INCLUDE_DIRS})
-
- set(includeType)
- foreach(src ${SOURCES})
- file(READ ${src} thefile)
- if("${thefile}" MATCHES ".*BoostTestTargetConfig.h.*")
- set(includeType CONFIGURED)
- set(includeFileLoc ${src})
- break()
- elseif("${thefile}" MATCHES ".*boost/test/included/unit_test.hpp.*")
- set(includeType INCLUDED)
- set(includeFileLoc ${src})
- set(_boosttesttargets_libs) # clear this out - linking would be a bad idea
- if(NOT
- "${thefile}"
- MATCHES
- ".*OVERRIDE_BOOST_TEST_INCLUDED_WARNING.*")
- message("Please replace the include line in ${src} with this alternate include line instead:")
- message(" \#include <BoostTestTargetConfig.h>")
- message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)")
- endif()
- break()
- endif()
- endforeach()
-
- if(NOT _boostTestTargetsNagged${_name} STREQUAL "${includeType}")
- if("${includeType}" STREQUAL "CONFIGURED")
- message(STATUS
- "Test '${_name}' uses the CMake-configurable form of the boost test framework - congrats! (Including File: ${includeFileLoc})")
- elseif("${includeType}" STREQUAL "INCLUDED")
- message("In test '${_name}': ${includeFileLoc} uses the 'included' form of the boost unit test framework.")
- else()
- message("In test '${_name}': Didn't detect the CMake-configurable boost test include.")
- message("Please replace your existing boost test include in that test with the following:")
- message(" \#include <BoostTestTargetConfig.h>")
- message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)")
- endif()
- endif()
- set(_boostTestTargetsNagged${_name}
- "${includeType}"
- CACHE
- INTERNAL
- ""
- FORCE)
-
-
- if(RESOURCES)
- list(APPEND SOURCES ${RESOURCES})
- endif()
-
- # Generate a unique target name, using the relative binary dir
- # and provided name. (transform all / into _ and remove all other
- # non-alphabet characters)
- file(RELATIVE_PATH
- targetpath
- "${CMAKE_BINARY_DIR}"
- "${CMAKE_CURRENT_BINARY_DIR}")
- string(REGEX REPLACE "[^A-Za-z/_]" "" targetpath "${targetpath}")
- string(REPLACE "/" "_" targetpath "${targetpath}")
-
- set(_target_name ${BOOST_TEST_TARGET_PREFIX}-${targetpath}-${_name})
- set(${_name}_TARGET_NAME "${_target_name}" PARENT_SCOPE)
-
- # Build the test.
- add_executable(${_target_name} ${SOURCES})
-
- list(APPEND LIBRARIES ${_boosttesttargets_libs})
-
- if(LIBRARIES)
- target_link_libraries(${_target_name} ${LIBRARIES})
- endif()
-
- if(RESOURCES)
- set_property(TARGET ${_target_name} PROPERTY RESOURCE ${RESOURCES})
- copy_resources_to_build_tree(${_target_name})
- endif()
-
- if(NOT Boost_TEST_FLAGS)
-# set(Boost_TEST_FLAGS --catch_system_error=yes --output_format=XML)
- set(Boost_TEST_FLAGS --catch_system_error=yes)
- endif()
-
- # TODO: Figure out why only recent boost handles individual test running properly
-
- if(LAUNCHER)
- set(_test_command ${LAUNCHER} "\$<TARGET_FILE:${_target_name}>")
- else()
- set(_test_command ${_target_name})
- endif()
-
- if(TESTS AND ( "${Boost_VERSION_MACRO}" VERSION_GREATER "103799" ))
- foreach(_test ${TESTS})
- add_test(
- ${_name}-${_test}
- ${_test_command} --run_test=${_test} ${Boost_TEST_FLAGS}
- )
- if(FAIL_REGULAR_EXPRESSION)
- set_tests_properties(${_name}-${_test}
- PROPERTIES
- FAIL_REGULAR_EXPRESSION
- "${FAIL_REGULAR_EXPRESSION}")
- endif()
- endforeach()
- else()
- add_test(
- ${_name}-boost_test
- ${_test_command} ${Boost_TEST_FLAGS}
- )
- if(FAIL_REGULAR_EXPRESSION)
- set_tests_properties(${_name}-boost_test
- PROPERTIES
- FAIL_REGULAR_EXPRESSION
- "${FAIL_REGULAR_EXPRESSION}")
- endif()
- endif()
-
- # CppCheck the test if we can.
- if(COMMAND add_cppcheck)
- add_cppcheck(${_target_name} STYLE UNUSED_FUNCTIONS)
- endif()
-
- endif()
-endfunction()
diff --git a/CMakeModules/BoostTestTargetsDynamic.h b/CMakeModules/BoostTestTargetsDynamic.h
deleted file mode 100644
index fd28cf91..00000000
--- a/CMakeModules/BoostTestTargetsDynamic.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1-or-later
-// SPDX-FileCopyrightText: 2014 Thomas Geymayer
-
-// Small header computed by CMake to set up boost test.
-// include AFTER #define BOOST_TEST_MODULE whatever
-// but before any other boost test includes.
-
-// Using the Boost UTF dynamic library
-
-#ifndef BOOST_TEST_DYN_LINK
- #define BOOST_TEST_DYN_LINK
-#endif
-#include <boost/test/unit_test.hpp>
diff --git a/CMakeModules/BoostTestTargetsIncluded.h b/CMakeModules/BoostTestTargetsIncluded.h
deleted file mode 100644
index 253133ce..00000000
--- a/CMakeModules/BoostTestTargetsIncluded.h
+++ /dev/null
@@ -1,7 +0,0 @@
-// Small header computed by CMake to set up boost test.
-// include AFTER #define BOOST_TEST_MODULE whatever
-// but before any other boost test includes.
-
-// Using the Boost UTF included framework
-
-#include <boost/test/included/unit_test.hpp>
diff --git a/CMakeModules/BoostTestTargetsStatic.h b/CMakeModules/BoostTestTargetsStatic.h
deleted file mode 100644
index dd3cddae..00000000
--- a/CMakeModules/BoostTestTargetsStatic.h
+++ /dev/null
@@ -1,7 +0,0 @@
-// Small header computed by CMake to set up boost test.
-// include AFTER #define BOOST_TEST_MODULE whatever
-// but before any other boost test includes.
-
-// Using the Boost UTF static library
-
-#include <boost/test/unit_test.hpp>
diff --git a/CMakeModules/ConfigureMsvc3rdParty.cmake b/CMakeModules/ConfigureMsvc3rdParty.cmake
index 8d5e7b1c..334222ad 100644
--- a/CMakeModules/ConfigureMsvc3rdParty.cmake
+++ b/CMakeModules/ConfigureMsvc3rdParty.cmake
@@ -13,14 +13,12 @@
# - path to an architecture specific subdir, eg -DMSVC_3RDPARTY_ROOT=C:\FGFS\windows-3rd-party\msvc140\3rdparty.x64
set(_FOUND_3RDPARTY_DIR "NOTFOUND")
-set(_FOUND_BOOST_INCLUDE_DIR "NOTFOUND")
# try various suffixes of a base directory, and
# set the variables above on success
function(_check_candidate_msvc_path pathToCheck)
unset (_freeTypeHeader CACHE )
unset (_zlibDll CACHE )
- unset (_boostHeaders CACHE )
find_path(_freeTypeHeader include/ft2build.h
PATHS
@@ -42,18 +40,9 @@ function(_check_candidate_msvc_path pathToCheck)
NO_DEFAULT_PATH
)
- find_path(_boostHeaders boost/atomic.hpp
- PATHS
- ${pathToCheck}
- NO_DEFAULT_PATH
- )
-
if (_freeTypeHeader AND _zlibDll)
set(_FOUND_3RDPARTY_DIR "${_freeTypeHeader}" PARENT_SCOPE)
- if (_boostHeaders)
- set(_FOUND_BOOST_INCLUDE_DIR "${_boostHeaders}" PARENT_SCOPE)
- endif()
endif()
endfunction()
@@ -121,15 +110,4 @@ if (MSVC AND _FOUND_3RDPARTY_DIR)
message(STATUS "3rdparty files located in ${_FOUND_3RDPARTY_DIR}")
list(APPEND CMAKE_PREFIX_PATH ${_FOUND_3RDPARTY_DIR})
set(FINAL_MSVC_3RDPARTY_DIR ${_FOUND_3RDPARTY_DIR})
-
- if (CMAKE_CL_64)
- set( BOOST_LIB lib64 )
- else (CMAKE_CL_64)
- set( BOOST_LIB lib )
- endif (CMAKE_CL_64)
-
- if(NOT BOOST_INCLUDEDIR AND _FOUND_BOOST_INCLUDE_DIR)
- set(BOOST_INCLUDEDIR ${_FOUND_BOOST_INCLUDE_DIR})
- message(STATUS "found Boost headers at ${_FOUND_BOOST_INCLUDE_DIR}")
- endif()
endif ()
diff --git a/simgear/CMakeLists.txt b/simgear/CMakeLists.txt
index c24938f3..1da1ece6 100644
--- a/simgear/CMakeLists.txt
+++ b/simgear/CMakeLists.txt
@@ -76,9 +76,6 @@ target_include_directories(SimGearCore PRIVATE ${PROJECT_BINARY_DIR}/simgear)
target_include_directories(SimGearCore INTERFACE
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>)
-target_include_directories(SimGearCore PUBLIC
- ${Boost_INCLUDE_DIRS})
-
if (MSVC)
message(WARNING "FIXME: setting _HAS_STD_BYTE=0 for SimGear build, this needs to be fixed.")
target_compile_definitions(SimGearCore PRIVATE _HAS_STD_BYTE=0)
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 4be0545a..a3cee9ae 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -22,7 +22,4 @@ if (TARGET SimGearScene)
install(FILES ${HEADERS} DESTINATION include/simgear/canvas/elements)
endif()
-add_boost_test(canvas_element
- SOURCES canvas_element_test.cpp
- LIBRARIES SimGearScene
-)
+add_simgear_scene_autotest(canvas_element canvas_element_test.cpp)
diff --git a/simgear/canvas/elements/canvas_element_test.cpp b/simgear/canvas/elements/canvas_element_test.cpp
index ce3216b3..efc9cd1f 100644
--- a/simgear/canvas/elements/canvas_element_test.cpp
+++ b/simgear/canvas/elements/canvas_element_test.cpp
@@ -1,20 +1,19 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2014 Thomas Geymayer <to...@gm...>
/// Unit tests for canvas::Element
-#define BOOST_TEST_MODULE canvas
-#include <BoostTestTargetConfig.h>
-
#include "CanvasElement.hxx"
#include "CanvasGroup.hxx"
+#include <simgear/misc/test_macros.hxx>
namespace sc = simgear::canvas;
-BOOST_AUTO_TEST_CASE( attr_data )
+void test_attr_data()
{
// http://www.w3.org/TR/html5/dom.html#attr-data-*
-#define SG_CHECK_ATTR2PROP(attr, prop)\
- BOOST_CHECK_EQUAL(sc::Element::attrToDataPropName(attr), prop)
+#define SG_CHECK_ATTR2PROP(attr, prop) \
+ SG_CHECK_EQUAL(sc::Element::attrToDataPropName(attr), std::string(prop))
// If name starts with "data-", for each "-" (U+002D) character in the name
// that is followed by a lowercase ASCII letter, remove the "-" (U+002D)
@@ -28,8 +27,8 @@ BOOST_AUTO_TEST_CASE( attr_data )
#undef SG_CHECK_ATTR2PROP
-#define SG_CHECK_PROP2ATTR(prop, attr)\
- BOOST_CHECK_EQUAL(sc::Element::dataPropToAttrName(prop), attr)
+#define SG_CHECK_PROP2ATTR(prop, attr) \
+ SG_CHECK_EQUAL(sc::Element::dataPropToAttrName(prop), std::string(attr))
// If name contains a "-" (U+002D) character followed by a lowercase ASCII
// letter, throw a SyntaxError exception (empty string) and abort these steps.
@@ -51,18 +50,24 @@ BOOST_AUTO_TEST_CASE( attr_data )
sc::Element::create<sc::Group>(sc::CanvasWeakPtr(), node);
el->setDataProp("myData", 3);
- BOOST_CHECK_EQUAL( el->getDataProp<int>("myData"), 3 );
- BOOST_CHECK_EQUAL( node->getIntValue("data-my-data"), 3 );
+ SG_CHECK_EQUAL(el->getDataProp<int>("myData"), 3);
+ SG_CHECK_EQUAL(node->getIntValue("data-my-data"), 3);
SGPropertyNode* prop = el->getDataProp<SGPropertyNode*>("notExistingProp");
- BOOST_CHECK( !prop );
+ SG_VERIFY(!prop);
prop = el->getDataProp<SGPropertyNode*>("myData");
- BOOST_CHECK( prop );
- BOOST_CHECK_EQUAL( prop->getParent(), node );
- BOOST_CHECK_EQUAL( prop->getIntValue(), 3 );
+ SG_VERIFY(prop);
+ SG_CHECK_EQUAL(prop->getParent(), node);
+ SG_CHECK_EQUAL(prop->getIntValue(), 3);
- BOOST_CHECK( el->hasDataProp("myData") );
+ SG_VERIFY(el->hasDataProp("myData"));
el->removeDataProp("myData");
- BOOST_CHECK( !el->hasDataProp("myData") );
- BOOST_CHECK_EQUAL( el->getDataProp("myData", 5), 5 );
+ SG_VERIFY(!el->hasDataProp("myData"));
+ SG_CHECK_EQUAL(el->getDataProp("myData", 5), 5);
+}
+
+int main()
+{
+ test_attr_data();
+ return 0;
}
diff --git a/simgear/canvas/events/CMakeLists.txt b/simgear/canvas/events/CMakeLists.txt
index 32519fa6..87e8716f 100644
--- a/simgear/canvas/events/CMakeLists.txt
+++ b/simgear/canvas/events/CMakeLists.txt
@@ -20,10 +20,7 @@ if (TARGET SimGearScene)
install(FILES ${HEADERS} DESTINATION include/simgear/canvas/events)
endif()
-add_boost_test(canvas_event
- SOURCES event_test.cpp
- LIBRARIES SimGearScene
-)
+add_simgear_scene_autotest(canvas_event event_test.cpp)
add_simgear_test(input_event_demo input_event_demo.cxx)
target_link_libraries(input_event_demo
diff --git a/simgear/canvas/events/KeyboardEvent.cxx b/simgear/canvas/events/KeyboardEvent.cxx
index 9b6cf3ed..85c32a69 100644
--- a/simgear/canvas/events/KeyboardEvent.cxx
+++ b/simgear/canvas/events/KeyboardEvent.cxx
@@ -12,14 +12,8 @@
#include <osgGA/GUIEventAdapter>
-#include <boost/version.hpp>
-#if BOOST_VERSION >= 104800
-# include <boost/container/flat_map.hpp>
-# include <boost/container/flat_set.hpp>
-#else
-# include <map>
-# include <set>
-#endif
+#include <map>
+#include <set>
#include <iterator>
@@ -31,7 +25,7 @@ namespace canvas
// TODO check Win/Mac keycode for altgr/ISO Level3 Shift
const uint32_t KEY_AltGraph = 0xfe03;
-
+
//----------------------------------------------------------------------------
KeyboardEvent::KeyboardEvent():
@@ -99,14 +93,8 @@ namespace canvas
// system.
typedef std::pair<const char*, uint8_t> InternalKeyInfo;
-#if BOOST_VERSION >= 104800
- typedef boost::container::flat_map<int, InternalKeyInfo> InternalKeyMap;
- typedef boost::container::flat_set<int> KeyList;
-#else
-# warning "Use Boost >= 1.48 for faster and more memory efficient key lookup"
typedef std::map<int, InternalKeyInfo> InternalKeyMap;
typedef std::set<int> KeyList;
-#endif
static InternalKeyMap key_map;
static KeyList num_pad_keys;
diff --git a/simgear/canvas/events/event_test.cpp b/simgear/canvas/events/event_test.cpp
index 8cdb9687..6a692bd3 100644
--- a/simgear/canvas/events/event_test.cpp
+++ b/simgear/canvas/events/event_test.cpp
@@ -1,38 +1,42 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2014 Thomas Geymayer <to...@gm...>
-/// Unit tests for reference counting and smart pointer classes
-#define BOOST_TEST_MODULE structure
-#include <BoostTestTargetConfig.h>
-
-#include "MouseEvent.hxx"
#include "CustomEvent.hxx"
+#include "MouseEvent.hxx"
+#include <simgear/misc/test_macros.hxx>
namespace sc = simgear::canvas;
-BOOST_AUTO_TEST_CASE( canvas_event_types )
+void test_canvas_event_types()
{
// Register type
- BOOST_REQUIRE_EQUAL( sc::Event::strToType("test"),
- sc::Event::UNKNOWN );
- BOOST_REQUIRE_EQUAL( sc::Event::getOrRegisterType("test"),
- sc::Event::CUSTOM_EVENT );
- BOOST_REQUIRE_EQUAL( sc::Event::strToType("test"),
- sc::Event::CUSTOM_EVENT );
- BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(sc::Event::CUSTOM_EVENT),
- "test" );
+ SG_CHECK_EQUAL_NOSTREAM(sc::Event::strToType("test"),
+ sc::Event::UNKNOWN);
+ SG_CHECK_EQUAL_NOSTREAM(sc::Event::getOrRegisterType("test"),
+ sc::Event::CUSTOM_EVENT);
+ SG_CHECK_EQUAL_NOSTREAM(sc::Event::strToType("test"),
+ sc::Event::CUSTOM_EVENT);
+ SG_CHECK_EQUAL(sc::Event::typeToStr(sc::Event::CUSTOM_EVENT),
+ std::string("test"));
// Basic internal type
- BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(sc::Event::MOUSE_DOWN),
- "mousedown" );
- BOOST_REQUIRE_EQUAL( sc::Event::strToType("mousedown"),
- sc::Event::MOUSE_DOWN );
+ SG_CHECK_EQUAL(sc::Event::typeToStr(sc::Event::MOUSE_DOWN),
+ std::string("mousedown"));
+ SG_CHECK_EQUAL_NOSTREAM(sc::Event::strToType("mousedown"),
+ sc::Event::MOUSE_DOWN);
// Unknown type
- BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(123),
- "unknown" );
+ SG_CHECK_EQUAL(sc::Event::typeToStr(123),
+ std::string("unknown"));
// Register type through custom event instance
sc::CustomEvent e("blub");
- BOOST_REQUIRE_EQUAL( e.getTypeString(), "blub" );
- BOOST_REQUIRE_NE( e.getType(), sc::Event::UNKNOWN );
+ SG_CHECK_EQUAL(e.getTypeString(), std::string("blub"));
+ SG_CHECK_NE_NOSTREAM(e.getType(), sc::Event::UNKNOWN);
+}
+
+int main()
+{
+ test_canvas_event_types();
+ return 0;
}
diff --git a/simgear/canvas/layout/CMakeLists.txt b/simgear/canvas/layout/CMakeLists.txt
index e9f29424..fdaede68 100644
--- a/simgear/canvas/layout/CMakeLists.txt
+++ b/simgear/canvas/layout/CMakeLists.txt
@@ -25,7 +25,4 @@ if (TARGET SimGearScene)
install(FILES ${HEADERS} DESTINATION include/simgear/canvas/layout)
endif()
-add_boost_test(canvas_layout
- SOURCES canvas_layout_test.cxx
- LIBRARIES SimGearScene
-)
+add_simgear_scene_autotest(canvas_layout canvas_layout_test.cxx)
diff --git a/simgear/canvas/layout/canvas_layout_test.cxx b/simgear/canvas/layout/canvas_layout_test.cxx
index 5e64bd31..e1420f0a 100644
--- a/simgear/canvas/layout/canvas_layout_test.cxx
+++ b/simgear/canvas/layout/canvas_layout_test.cxx
@@ -6,28 +6,16 @@
* @brief Testing canvas layout system
*/
-#define BOOST_TEST_MODULE canvas_layout
-#include <BoostTestTargetConfig.h>
-
#include "BoxLayout.hxx"
#include "GridLayout.hxx"
#include "NasalWidget.hxx"
#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/test_macros.hxx>
#include <simgear/nasal/cppbind/NasalContext.hxx>
#include <cstdlib>
-//------------------------------------------------------------------------------
-struct SetLogLevelFixture
-{
- SetLogLevelFixture()
- {
- // sglog().set_log_priority(SG_DEBUG);
- }
-};
-BOOST_GLOBAL_FIXTURE(SetLogLevelFixture);
-
//------------------------------------------------------------------------------
namespace sc = simgear::canvas;
@@ -105,28 +93,28 @@ class TestWidgetHFW:
typedef SGSharedPtr<TestWidget> TestWidgetRef;
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( horizontal_layout )
+void test_horizontal_layout()
{
sc::BoxLayoutRef box_layout(new sc::BoxLayout(sc::BoxLayout::BottomToTop));
box_layout->setSpacing(5);
- BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::BottomToTop);
- BOOST_CHECK_EQUAL(box_layout->spacing(), 5);
+ SG_CHECK_EQUAL_NOSTREAM(box_layout->direction(), sc::BoxLayout::BottomToTop);
+ SG_CHECK_EQUAL(box_layout->spacing(), 5);
box_layout->setDirection(sc::BoxLayout::LeftToRight);
box_layout->setSpacing(9);
- BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::LeftToRight);
- BOOST_CHECK_EQUAL(box_layout->spacing(), 9);
+ SG_CHECK_EQUAL_NOSTREAM(box_layout->direction(), sc::BoxLayout::LeftToRight);
+ SG_CHECK_EQUAL(box_layout->spacing(), 9);
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
SGVec2i(16, 16),
SGVec2i(16, 16) ) );
box_layout->addItem(fixed_size_widget);
- BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(16, 16));
- BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(16, 16));
- BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(16, 16));
+ SG_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(16, 16));
+ SG_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(16, 16));
+ SG_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(16, 16));
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32),
@@ -134,22 +122,22 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
box_layout->addItem(limited_resize_widget);
// Combined sizes of both widget plus the padding between them
- BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(41, 16));
- BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(57, 32));
- BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(281, 64));
+ SG_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(41, 16));
+ SG_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(57, 32));
+ SG_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(281, 64));
// Test with different spacing/padding
box_layout->setSpacing(5);
- BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(37, 16));
- BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(53, 32));
- BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(277, 64));
+ SG_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(37, 16));
+ SG_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(53, 32));
+ SG_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(277, 64));
box_layout->setGeometry(SGRecti(0, 0, 128, 32));
// Fixed size for first widget and remaining space goes to second widget
- BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
- BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(21, 0, 107, 32));
+ SG_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
+ SG_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(21, 0, 107, 32));
TestWidgetRef stretch_widget( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32),
@@ -157,15 +145,15 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
box_layout->addItem(stretch_widget, 1);
box_layout->update();
- BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(58, 16));
- BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(90, 32));
- BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(410, 64));
+ SG_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(58, 16));
+ SG_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(90, 32));
+ SG_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(410, 64));
// Due to the stretch factor only the last widget gets additional space. All
// other widgets get the preferred size.
- BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
- BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(21, 0, 32, 32));
- BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(58, 0, 70, 32));
+ SG_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
+ SG_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(21, 0, 32, 32));
+ SG_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(58, 0, 70, 32));
// Test stretch factor
TestWidgetRef fast_stretch( new TestWidget(*stretch_widget) );
@@ -178,19 +166,19 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
box_layout_stretch->setGeometry(SGRecti(0,0,128,32));
- BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 41, 32));
- BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(46, 0, 82, 32));
+ SG_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 41, 32));
+ SG_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(46, 0, 82, 32));
box_layout_stretch->setGeometry(SGRecti(0,0,256,32));
- BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 123, 32));
- BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
+ SG_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 123, 32));
+ SG_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
// Test superfluous space to padding
box_layout_stretch->setGeometry(SGRecti(0,0,512,32));
- BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(83, 0, 128, 32));
- BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
+ SG_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(83, 0, 128, 32));
+ SG_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
// ...and now with alignment
//
@@ -203,33 +191,33 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
// Right widget: maximum size and positioned on the right
stretch_widget->setAlignment(sc::AlignLeft);
box_layout_stretch->update();
- BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
- BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
+ SG_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
+ SG_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
// Left widget: align right
stretch_widget->setAlignment(sc::AlignRight);
box_layout_stretch->update();
- BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(347, 0, 32, 32));
- BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
+ SG_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(347, 0, 32, 32));
+ SG_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
// Left widget: size hint and positioned on the right
// Right widget: size hint and positioned on the left of the right half
fast_stretch->setAlignment(sc::AlignLeft);
box_layout_stretch->update();
- BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(221, 0, 32, 32));
- BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 0, 32, 32));
+ SG_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(221, 0, 32, 32));
+ SG_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 0, 32, 32));
// Also check vertical alignment
stretch_widget->setAlignment(sc::AlignLeft | sc::AlignTop);
fast_stretch->setAlignment(sc::AlignLeft | sc::AlignBottom);
box_layout_stretch->setGeometry(SGRecti(0,0,512,64));
- BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
- BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 32, 32, 32));
+ SG_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
+ SG_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 32, 32, 32));
}
//------------------------------------------------------------------------------
// Test more space then preferred, but less than maximum
-BOOST_AUTO_TEST_CASE( hbox_pref_to_max )
+void test_hbox_pref_to_max()
{
sc::BoxLayoutRef hbox(new sc::HBoxLayout());
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
@@ -242,32 +230,32 @@ BOOST_AUTO_TEST_CASE( hbox_pref_to_max )
hbox->setGeometry( SGRecti(0, 0, 256, 32) );
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
hbox->setStretch(0, 1);
hbox->setStretch(1, 1);
- BOOST_CHECK_EQUAL(hbox->stretch(0), 1);
- BOOST_CHECK_EQUAL(hbox->stretch(1), 1);
+ SG_CHECK_EQUAL(hbox->stretch(0), 1);
+ SG_CHECK_EQUAL(hbox->stretch(1), 1);
hbox->update();
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
- BOOST_REQUIRE( hbox->setStretchFactor(w1, 2) );
- BOOST_REQUIRE( hbox->setStretchFactor(w2, 3) );
- BOOST_CHECK_EQUAL(hbox->stretch(0), 2);
- BOOST_CHECK_EQUAL(hbox->stretch(1), 3);
+ SG_VERIFY(hbox->setStretchFactor(w1, 2));
+ SG_VERIFY(hbox->setStretchFactor(w2, 3));
+ SG_CHECK_EQUAL(hbox->stretch(0), 2);
+ SG_CHECK_EQUAL(hbox->stretch(1), 3);
hbox->removeItem(w1);
- BOOST_CHECK( !hbox->setStretchFactor(w1, 0) );
+ SG_VERIFY(!hbox->setStretchFactor(w1, 0));
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( spacer_layouting )
+void test_spacer_layouting()
{
sc::HBoxLayout hbox;
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
@@ -279,31 +267,31 @@ BOOST_AUTO_TEST_CASE( spacer_layouting )
hbox.addItem(w2);
hbox.addStretch(1);
- BOOST_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(37, 16));
- BOOST_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(69, 32));
- BOOST_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
+ SG_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(37, 16));
+ SG_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(69, 32));
+ SG_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
hbox.setGeometry(SGRecti(0, 0, 256, 40));
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 32, 40));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(37, 0, 32, 40));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 32, 40));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(37, 0, 32, 40));
// now center with increased spacing between both widgets
hbox.insertStretch(0, 1);
hbox.insertSpacing(2, 10);
- BOOST_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(47, 16));
- BOOST_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(79, 32));
- BOOST_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
+ SG_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(47, 16));
+ SG_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(79, 32));
+ SG_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
hbox.update();
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(88, 0, 32, 40));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(135, 0, 32, 40));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(88, 0, 32, 40));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(135, 0, 32, 40));
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( vertical_layout)
+void test_vertical_layout()
{
sc::BoxLayout vbox(sc::BoxLayout::TopToBottom);
vbox.setSpacing(7);
@@ -318,26 +306,26 @@ BOOST_AUTO_TEST_CASE( vertical_layout)
vbox.addItem(fixed_size_widget);
vbox.addItem(limited_resize_widget);
- BOOST_CHECK_EQUAL(vbox.minimumSize(), SGVec2i(16, 39));
- BOOST_CHECK_EQUAL(vbox.sizeHint(), SGVec2i(32, 55));
- BOOST_CHECK_EQUAL(vbox.maximumSize(), SGVec2i(256, 87));
+ SG_CHECK_EQUAL(vbox.minimumSize(), SGVec2i(16, 39));
+ SG_CHECK_EQUAL(vbox.sizeHint(), SGVec2i(32, 55));
+ SG_CHECK_EQUAL(vbox.maximumSize(), SGVec2i(256, 87));
vbox.setGeometry(SGRecti(10, 20, 16, 55));
- BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(10, 20, 16, 16));
- BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(10, 43, 16, 32));
+ SG_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(10, 20, 16, 16));
+ SG_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(10, 43, 16, 32));
vbox.setDirection(sc::BoxLayout::BottomToTop);
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( boxlayout_insert_remove )
+void test_boxlayout_insert_remove()
{
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
- BOOST_CHECK_EQUAL(hbox->count(), 0);
- BOOST_CHECK(!hbox->itemAt(0));
- BOOST_CHECK(!hbox->takeAt(0));
+ SG_CHECK_EQUAL(hbox->count(), 0);
+ SG_VERIFY(!hbox->itemAt(0));
+ SG_VERIFY(!hbox->takeAt(0));
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32),
@@ -345,33 +333,33 @@ BOOST_AUTO_TEST_CASE( boxlayout_insert_remove )
w2( new TestWidget(*w1) );
hbox->addItem(w1);
- BOOST_CHECK_EQUAL(hbox->count(), 1);
- BOOST_CHECK_EQUAL(hbox->itemAt(0), w1);
- BOOST_CHECK_EQUAL(w1->getParent(), hbox);
+ SG_CHECK_EQUAL(hbox->count(), 1);
+ SG_CHECK_EQUAL_NOSTREAM(hbox->itemAt(0), w1);
+ SG_CHECK_EQUAL_NOSTREAM(w1->getParent(), hbox);
hbox->insertItem(0, w2);
- BOOST_CHECK_EQUAL(hbox->count(), 2);
- BOOST_CHECK_EQUAL(hbox->itemAt(0), w2);
- BOOST_CHECK_EQUAL(hbox->itemAt(1), w1);
- BOOST_CHECK_EQUAL(w2->getParent(), hbox);
+ SG_CHECK_EQUAL(hbox->count(), 2);
+ SG_CHECK_EQUAL_NOSTREAM(hbox->itemAt(0), w2);
+ SG_CHECK_EQUAL_NOSTREAM(hbox->itemAt(1), w1);
+ SG_CHECK_EQUAL_NOSTREAM(w2->getParent(), hbox);
hbox->removeItem(w2);
- BOOST_CHECK_EQUAL(hbox->count(), 1);
- BOOST_CHECK_EQUAL(hbox->itemAt(0), w1);
- BOOST_CHECK( !w2->getParent() );
+ SG_CHECK_EQUAL(hbox->count(), 1);
+ SG_CHECK_EQUAL_NOSTREAM(hbox->itemAt(0), w1);
+ SG_VERIFY(!w2->getParent());
hbox->addItem(w2);
- BOOST_CHECK_EQUAL(hbox->count(), 2);
- BOOST_CHECK_EQUAL(w2->getParent(), hbox);
+ SG_CHECK_EQUAL(hbox->count(), 2);
+ SG_CHECK_EQUAL_NOSTREAM(w2->getParent(), hbox);
hbox->clear();
- BOOST_CHECK_EQUAL(hbox->count(), 0);
- BOOST_CHECK( !w1->getParent() );
- BOOST_CHECK( !w2->getParent() );
+ SG_CHECK_EQUAL(hbox->count(), 0);
+ SG_VERIFY(!w1->getParent());
+ SG_VERIFY(!w2->getParent());
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( boxlayout_visibility )
+void test_boxlayout_visibility()
{
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
@@ -383,67 +371,67 @@ BOOST_AUTO_TEST_CASE( boxlayout_visibility )
hbox->addItem(w2);
hbox->addItem(w3);
- BOOST_REQUIRE_EQUAL(hbox->sizeHint().x(), 3 * 32 + 2 * hbox->spacing());
+ SG_CHECK_EQUAL(hbox->sizeHint().x(), 3 * 32 + 2 * hbox->spacing());
hbox->setGeometry(SGRecti(0, 0, 69, 32));
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 20, 32));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
- BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 20, 32));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
+ SG_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
w2->setVisible(false);
- BOOST_REQUIRE(hbox->isVisible());
- BOOST_REQUIRE(w1->isVisible());
- BOOST_REQUIRE(!w2->isVisible());
- BOOST_REQUIRE(w2->isExplicitlyHidden());
- BOOST_REQUIRE(w3->isVisible());
+ SG_VERIFY(hbox->isVisible());
+ SG_VERIFY(w1->isVisible());
+ SG_VERIFY(!w2->isVisible());
+ SG_VERIFY(w2->isExplicitlyHidden());
+ SG_VERIFY(w3->isVisible());
- BOOST_CHECK_EQUAL(hbox->sizeHint().x(), 2 * 32 + 1 * hbox->spacing());
+ SG_CHECK_EQUAL(hbox->sizeHint().x(), 2 * 32 + 1 * hbox->spacing());
hbox->update();
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 32, 32));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
- BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(37, 0, 32, 32));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 32, 32));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
+ SG_CHECK_EQUAL(w3->geometry(), SGRecti(37, 0, 32, 32));
hbox->setVisible(false);
- BOOST_REQUIRE(!hbox->isVisible());
- BOOST_REQUIRE(hbox->isExplicitlyHidden());
- BOOST_REQUIRE(!w1->isVisible());
- BOOST_REQUIRE(!w1->isExplicitlyHidden());
- BOOST_REQUIRE(!w2->isVisible());
- BOOST_REQUIRE(w2->isExplicitlyHidden());
- BOOST_REQUIRE(!w3->isVisible());
- BOOST_REQUIRE(!w3->isExplicitlyHidden());
+ SG_VERIFY(!hbox->isVisible());
+ SG_VERIFY(hbox->isExplicitlyHidden());
+ SG_VERIFY(!w1->isVisible());
+ SG_VERIFY(!w1->isExplicitlyHidden());
+ SG_VERIFY(!w2->isVisible());
+ SG_VERIFY(w2->isExplicitlyHidden());
+ SG_VERIFY(!w3->isVisible());
+ SG_VERIFY(!w3->isExplicitlyHidden());
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 0, 0));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
- BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(0, 0, 0, 0));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 0, 0));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
+ SG_CHECK_EQUAL(w3->geometry(), SGRecti(0, 0, 0, 0));
w2->setVisible(true);
- BOOST_REQUIRE(!w2->isVisible());
- BOOST_REQUIRE(!w2->isExplicitlyHidden());
+ SG_VERIFY(!w2->isVisible());
+ SG_VERIFY(!w2->isExplicitlyHidden());
hbox->setVisible(true);
- BOOST_REQUIRE(hbox->isVisible());
- BOOST_REQUIRE(w1->isVisible());
- BOOST_REQUIRE(w2->isVisible());
- BOOST_REQUIRE(w3->isVisible());
+ SG_VERIFY(hbox->isVisible());
+ SG_VERIFY(w1->isVisible());
+ SG_VERIFY(w2->isVisible());
+ SG_VERIFY(w3->isVisible());
hbox->update();
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 20, 32));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
- BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 20, 32));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
+ SG_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE(boxlayout_equal)
+void test_boxlayout_equal()
{
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
TestWidgetRef w1(new TestWidget(SGVec2i(16, 16),
@@ -464,70 +452,70 @@ BOOST_AUTO_TEST_CASE(boxlayout_equal)
hbox->setEqualsItem(w2);
hbox->setStretchFactor(w3, 1);
- BOOST_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(106, 16));
- BOOST_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(162, 40));
+ SG_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(106, 16));
+ SG_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(162, 40));
hbox->setGeometry(SGRecti(0, 0, 256, 40));
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 60, 40));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(65, 0, 60, 40));
- BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(130, 0, 126, 40));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 60, 40));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(65, 0, 60, 40));
+ SG_CHECK_EQUAL(w3->geometry(), SGRecti(130, 0, 126, 40));
- // visibility
+ // visibility
w2->setVisible(false);
- BOOST_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(37, 16));
- BOOST_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(69, 32));
+ SG_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(37, 16));
+ SG_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(69, 32));
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( boxlayout_contents_margins )
+void test_boxlayout_contents_margins()
{
sc::Margins m;
- BOOST_REQUIRE(m.isNull());
+ SG_VERIFY(m.isNull());
m = sc::Margins(5);
- BOOST_REQUIRE_EQUAL(m.l, 5);
- BOOST_REQUIRE_EQUAL(m.t, 5);
- BOOST_REQUIRE_EQUAL(m.r, 5);
- BOOST_REQUIRE_EQUAL(m.b, 5);
+ SG_CHECK_EQUAL(m.l, 5);
+ SG_CHECK_EQUAL(m.t, 5);
+ SG_CHECK_EQUAL(m.r, 5);
+ SG_CHECK_EQUAL(m.b, 5);
m = sc::Margins(6, 7);
- BOOST_REQUIRE_EQUAL(m.l, 6);
- BOOST_REQUIRE_EQUAL(m.t, 7);
- BOOST_REQUIRE_EQUAL(m.r, 6);
- BOOST_REQUIRE_EQUAL(m.b, 7);
+ SG_CHECK_EQUAL(m.l, 6);
+ SG_CHECK_EQUAL(m.t, 7);
+ SG_CHECK_EQUAL(m.r, 6);
+ SG_CHECK_EQUAL(m.b, 7);
- BOOST_REQUIRE_EQUAL(m.horiz(), 12);
- BOOST_REQUIRE_EQUAL(m.vert(), 14);
- BOOST_REQUIRE(!m.isNull());
+ SG_CHECK_EQUAL(m.horiz(), 12);
+ SG_CHECK_EQUAL(m.vert(), 14);
+ SG_VERIFY(!m.isNull());
m = sc::Margins(1, 2, 3, 4);
- BOOST_REQUIRE_EQUAL(m.l, 1);
- BOOST_REQUIRE_EQUAL(m.t, 2);
- BOOST_REQUIRE_EQUAL(m.r, 3);
- BOOST_REQUIRE_EQUAL(m.b, 4);
+ SG_CHECK_EQUAL(m.l, 1);
+ SG_CHECK_EQUAL(m.t, 2);
+ SG_CHECK_EQUAL(m.r, 3);
+ SG_CHECK_EQUAL(m.b, 4);
- BOOST_REQUIRE_EQUAL(m.horiz(), 4);
- BOOST_REQUIRE_EQUAL(m.vert(), 6);
- BOOST_REQUIRE_EQUAL(m.size(), SGVec2i(4, 6));
+ SG_CHECK_EQUAL(m.horiz(), 4);
+ SG_CHECK_EQUAL(m.vert(), 6);
+ SG_CHECK_EQUAL(m.size(), SGVec2i(4, 6));
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
hbox->setContentsMargins(5, 10, 15, 20);
- BOOST_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(20, 30));
- BOOST_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(20, 30));
- BOOST_CHECK_EQUAL(hbox->maximumSize(), SGVec2i(20, 30));
+ SG_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(20, 30));
+ SG_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(20, 30));
+ SG_CHECK_EQUAL(hbox->maximumSize(), SGVec2i(20, 30));
hbox->setGeometry(SGRecti(0, 0, 30, 40));
- BOOST_CHECK_EQUAL(hbox->geometry(), SGRecti(0, 0, 30, 40));
- BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 10, 10));
+ SG_CHECK_EQUAL(hbox->geometry(), SGRecti(0, 0, 30, 40));
+ SG_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 10, 10));
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32) ) ),
@@ -538,57 +526,57 @@ BOOST_AUTO_TEST_CASE( boxlayout_contents_margins )
w2->setContentsMargin(6);
w3->setContentsMargin(7);
- BOOST_CHECK_EQUAL(w1->minimumSize(), SGVec2i(26, 26));
- BOOST_CHECK_EQUAL(w1->sizeHint(), SGVec2i(42, 42));
- BOOST_CHECK_EQUAL(w1->maximumSize(), sc::LayoutItem::MAX_SIZE);
+ SG_CHECK_EQUAL(w1->minimumSize(), SGVec2i(26, 26));
+ SG_CHECK_EQUAL(w1->sizeHint(), SGVec2i(42, 42));
+ SG_CHECK_EQUAL(w1->maximumSize(), sc::LayoutItem::MAX_SIZE);
- BOOST_CHECK_EQUAL(w2->minimumSize(), SGVec2i(28, 28));
- BOOST_CHECK_EQUAL(w2->sizeHint(), SGVec2i(44, 44));
- BOOST_CHECK_EQUAL(w2->maximumSize(), sc::LayoutItem::MAX_SIZE);
+ SG_CHECK_EQUAL(w2->minimumSize(), SGVec2i(28, 28));
+ SG_CHECK_EQUAL(w2->sizeHint(), SGVec2i(44, 44));
+ SG_CHECK_EQUAL(w2->maximumSize(), sc::LayoutItem::MAX_SIZE);
- BOOST_CHECK_EQUAL(w3->minimumSize(), SGVec2i(30, 30));
- BOOST_CHECK_EQUAL(w3->sizeHint(), SGVec2i(46, 46));
- BOOST_CHECK_EQUAL(w3->maximumSize(), sc::LayoutItem::MAX_SIZE);
+ SG_CHECK_EQUAL(w3->minimumSize(), SGVec2i(30, 30));
+ SG_CHECK_EQUAL(w3->sizeHint(), SGVec2i(46, 46));
+ SG_CHECK_EQUAL(w3->maximumSize(), sc::LayoutItem::MAX_SIZE);
hbox->addItem(w1);
hbox->addItem(w2);
hbox->addItem(w3);
- BOOST_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(114, 60));
- BOOST_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(162, 76));
- BOOST_CHECK_EQUAL(hbox->maximumSize(), sc::LayoutItem::MAX_SIZE);
+ SG_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(114, 60));
+ SG_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(162, 76));
+ SG_CHECK_EQUAL(hbox->maximumSize(), sc::LayoutItem::MAX_SIZE);
hbox->setGeometry(SGRecti(0, 0, hbox->sizeHint().x(), hbox->sizeHint().y()));
- BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 142, 46));
+ SG_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 142, 46));
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(5, 10, 42, 46));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(52, 10, 44, 46));
- BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(101, 10, 46, 46));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(5, 10, 42, 46));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(52, 10, 44, 46));
+ SG_CHECK_EQUAL(w3->geometry(), SGRecti(101, 10, 46, 46));
- BOOST_CHECK_EQUAL(w1->contentsRect(), SGRecti(10, 15, 32, 36));
- BOOST_CHECK_EQUAL(w2->contentsRect(), SGRecti(58, 16, 32, 34));
- BOOST_CHECK_EQUAL(w3->contentsRect(), SGRecti(108, 17, 32, 32));
+ SG_CHECK_EQUAL(w1->contentsRect(), SGRecti(10, 15, 32, 36));
+ SG_CHECK_EQUAL(w2->contentsRect(), SGRecti(58, 16, 32, 34));
+ SG_CHECK_EQUAL(w3->contentsRect(), SGRecti(108, 17, 32, 32));
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( boxlayout_hfw )
+void test_boxlayout_hfw()
{
TestWidgetRef w1( new TestWidgetHFW( SGVec2i(16, 16),
SGVec2i(32, 32) ) ),
w2( new TestWidgetHFW( SGVec2i(24, 24),
SGVec2i(48, 48) ) );
- BOOST_CHECK_EQUAL(w1->heightForWidth(16), 64);
- BOOST_CHECK_EQUAL(w1->minimumHeightForWidth(16), 16);
- BOOST_CHECK_EQUAL(w2->heightForWidth(24), 96);
- BOOST_CHECK_EQUAL(w2->minimumHeightForWidth(24), 24);
+ SG_CHECK_EQUAL(w1->heightForWidth(16), 64);
+ SG_CHECK_EQUAL(w1->minimumHeightForWidth(16), 16);
+ SG_CHECK_EQUAL(w2->heightForWidth(24), 96);
+ SG_CHECK_EQUAL(w2->minimumHeightForWidth(24), 24);
TestWidgetRef w_no_hfw( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32) ) );
- BOOST_CHECK(!w_no_hfw->hasHeightForWidth());
- BOOST_CHECK_EQUAL(w_no_hfw->heightForWidth(16), -1);
- BOOST_CHECK_EQUAL(w_no_hfw->minimumHeightForWidth(16), -1);
+ SG_VERIFY(!w_no_hfw->hasHeightForWidth());
+ SG_CHECK_EQUAL(w_no_hfw->heightForWidth(16), -1);
+ SG_CHECK_EQUAL(w_no_hfw->minimumHeightForWidth(16), -1);
// horizontal
sc::HBoxLayout hbox;
@@ -596,21 +584,21 @@ BOOST_AUTO_TEST_CASE( boxlayout_hfw )
hbox.addItem(w1);
hbox.addItem(w2);
- BOOST_CHECK_EQUAL(hbox.heightForWidth(45), w2->heightForWidth(24));
- BOOST_CHECK_EQUAL(hbox.heightForWidth(85), w2->heightForWidth(48));
+ SG_CHECK_EQUAL(hbox.heightForWidth(45), w2->heightForWidth(24));
+ SG_CHECK_EQUAL(hbox.heightForWidth(85), w2->heightForWidth(48));
hbox.addItem(w_no_hfw);
- BOOST_CHECK_EQUAL(hbox.heightForWidth(66), 96);
- BOOST_CHECK_EQUAL(hbox.heightForWidth(122), 48);
- BOOST_CHECK_EQUAL(hbox.minimumHeightForWidth(66), 24);
- BOOST_CHECK_EQUAL(hbox.minimumHeightForWidth(122), 16);
+ SG_CHECK_EQUAL(hbox.heightForWidth(66), 96);
+ SG_CHECK_EQUAL(hbox.heightForWidth(122), 48);
+ SG_CHECK_EQUAL(hbox.minimumHeightForWidth(66), 24);
+ SG_CHECK_EQUAL(hbox.minimumHeightForWidth(122), 16);
hbox.setGeometry(SGRecti(0, 0, 66, 24));
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 16, 24));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(21, 0, 24, 24));
- BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(50, 0, 16, 24));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 16, 24));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(21, 0, 24, 24));
+ SG_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(50, 0, 16, 24));
// vertical
sc::VBoxLayout vbox;
@@ -618,52 +606,52 @@ BOOST_AUTO_TEST_CASE( boxlayout_hfw )
vbox.addItem(w1);
vbox.addItem(w2);
- BOOST_CHECK_EQUAL(vbox.heightForWidth(24), 143);
- BOOST_CHECK_EQUAL(vbox.heightForWidth(48), 74);
- BOOST_CHECK_EQUAL(vbox.minimumHeightForWidth(24), 39);
- BOOST_CHECK_EQUAL(vbox.minimumHeightForWidth(48), 22);
+ SG_CHECK_EQUAL(vbox.heightForWidth(24), 143);
+ SG_CHECK_EQUAL(vbox.heightForWidth(48), 74);
+ SG_CHECK_EQUAL(vbox.minimumHeightForWidth(24), 39);
+ SG_CHECK_EQUAL(vbox.minimumHeightForWidth(48), 22);
vbox.addItem(w_no_hfw);
- BOOST_CHECK_EQUAL(vbox.heightForWidth(24), 180);
- BOOST_CHECK_EQUAL(vbox.heightForWidth(48), 111);
- BOOST_CHECK_EQUAL(vbox.minimumHeightForWidth(24), 60);
- BOOST_CHECK_EQUAL(vbox.minimumHeightForWidth(48), 43);
+ SG_CHECK_EQUAL(vbox.heightForWidth(24), 180);
+ SG_CHECK_EQUAL(vbox.heightForWidth(48), 111);
+ SG_CHECK_EQUAL(vbox.minimumHeightForWidth(24), 60);
+ SG_CHECK_EQUAL(vbox.minimumHeightForWidth(48), 43);
SGVec2i min_size = vbox.minimumSize(),
size_hint = vbox.sizeHint();
- BOOST_CHECK_EQUAL(min_size, SGVec2i(24, 66));
- BOOST_CHECK_EQUAL(size_hint, SGVec2i(48, 122));
+ SG_CHECK_EQUAL(min_size, SGVec2i(24, 66));
+ SG_CHECK_EQUAL(size_hint, SGVec2i(48, 122));
vbox.setGeometry(SGRecti(0, 0, 24, 122));
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 24, 33));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 38, 24, 47));
- BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 24, 33));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(0, 38, 24, 47));
+ SG_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
// Vertical layout modifies size hints, so check if they are correctly
// restored
- BOOST_CHECK_EQUAL(min_size, vbox.minimumSize());
- BOOST_CHECK_EQUAL(size_hint, vbox.sizeHint());
+ SG_CHECK_EQUAL(min_size, vbox.minimumSize());
+ SG_CHECK_EQUAL(size_hint, vbox.sizeHint());
vbox.setGeometry(SGRecti(0, 0, 50, 122));
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 50, 25));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 30, 50, 51));
- BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 86, 50, 36));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 50, 25));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(0, 30, 50, 51));
+ SG_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 86, 50, 36));
// Same geometry as before -> should get same widget geometry
// (check internal size hint cache updates correctly)
vbox.setGeometry(SGRecti(0, 0, 24, 122));
- BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 24, 33));
- BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 38, 24, 47));
- BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
+ SG_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 24, 33));
+ SG_CHECK_EQUAL(w2->geometry(), SGRecti(0, 38, 24, 47));
+ SG_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( item_alignment_rect )
+void test_item_alignment_rect()
{
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32) ) );
@@ -671,41 +659,41 @@ BOOST_AUTO_TEST_CASE( item_alignment_rect )
const SGRecti r(10, 10, 64, 64);
// Default: AlignFill -> fill up to maximum size
- BOOST_CHECK_EQUAL(w1->alignmentRect(r), r);
+ SG_CHECK_EQUAL(w1->alignmentRect(r), r);
// Horizontal
// AlignLeft -> width from size hint, positioned on the left
w1->setAlignment(sc::AlignLeft);
- BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 32, 64));
+ SG_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 32, 64));
// AlignRight -> width from size hint, positioned on the left
w1->setAlignment(sc::AlignRight);
- BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(42, 10, 32, 64));
+ SG_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(42, 10, 32, 64));
// AlignHCenter -> width from size hint, positioned in the center
w1->setAlignment(sc::AlignHCenter);
- BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 10, 32, 64));
+ SG_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 10, 32, 64));
// Vertical
// AlignTop -> height from size hint, positioned on the top
w1->setAlignment(sc::AlignTop);
- BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 64, 32));
+ SG_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 64, 32));
// AlignBottom -> height from size hint, positioned on the bottom
w1->setAlignment(sc::AlignBottom);
- BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 42, 64, 32));
+ SG_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 42, 64, 32));
// AlignVCenter -> height from size hint, positioned in the center
w1->setAlignment(sc::AlignVCenter);
- BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 26, 64, 32));
+ SG_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 26, 64, 32));
// Vertical + Horizontal
w1->setAlignment(sc::AlignCenter);
- BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 26, 32, 32));
+ SG_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 26, 32, 32));
}
//------------------------------------------------------------------------------
@@ -721,7 +709,7 @@ static naRef f_Widget_visibilityChanged(nasal::CallContext ctx)
}
//------------------------------------------------------------------------------
-BOOST_AUTO_TEST_CASE( nasal_widget )
+void test_nasal_widget...
[truncated message content] |
|
From: <fli...@li...> - 2026-07-22 13:11:51
|
unknown user pushed a commit to branch next
in repository flightgear.
The following commit(s) were added to refs/heads/next by this push:
new 8ef0a0b9d Fix build with asserts enabled
8ef0a0b9d is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/8ef0a0b9d5522d4014adc7090cdf6e589c2d49eb/
Commit: 8ef0a0b9d5522d4014adc7090cdf6e589c2d49eb
Author: James Turner
Committer: James Turner
AuthorDate: Tue Jul 21 09:47:51 2026 +0100
Fix build with asserts enabled
---
src/Environment/fgclouds.cxx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Environment/fgclouds.cxx b/src/Environment/fgclouds.cxx
index c18058902..e7247d40d 100644
--- a/src/Environment/fgclouds.cxx
+++ b/src/Environment/fgclouds.cxx
@@ -533,7 +533,7 @@ bool FGClouds::repositionCloud(int index, float lon, float lat, float alt, float
// the main thread (reads FGLight subsystem state and _cloudPosMatrix).
osg::Vec3f FGClouds::computeSunDirVoxel() const
{
- assert(SGThreads::isMainThread());
+ assert(SGThread::isMainThread());
auto l = globals->get_subsystem<FGLight>();
// sun_vec() points from scene toward sun in world (ECEF) space
@@ -552,7 +552,7 @@ FGClouds::RebuildSnapshot FGClouds::captureSnapshot()
{
RebuildSnapshot snap;
- assert(SGThreads::isMainThread());
+ assert(SGThread::isMainThread());
// Read config (always main-thread safe)
auto cloudsProp = globals->get_props()->getNode("/sim/rendering/hdr/clouds/");
@@ -896,7 +896,7 @@ void FGClouds::commitResult(RebuildResult result)
FGClouds::ShadeSnapshot FGClouds::captureShadeSnapshot()
{
- assert(SGThreads::isMainThread());
+ assert(SGThread::isMainThread());
ShadeSnapshot snap;
snap.width = _detailedVoxelData->s();
|