diff --git a/.all-contributorsrc b/.all-contributorsrc
index 3b8675da22..02f07de694 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -73,6 +73,16 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "wyz2368",
+ "name": "wyz2368",
+ "avatar_url": "https://avatars.githubusercontent.com/u/25018133?v=4",
+ "profile": "https://github.com/wyz2368",
+ "contributions": [
+ "code",
+ "research"
+ ]
}
]
}
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 4e01ff6baa..5b88b5f528 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -45,7 +45,7 @@ jobs:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
steps:
- uses: actions/checkout@v7
- - uses: actions/setup-python@v6
+ - uses: actions/setup-python@v7
with:
python-version: "3.14"
- uses: py-actions/flake8@v2
@@ -56,7 +56,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Setup Python
- uses: actions/setup-python@v6
+ uses: actions/setup-python@v7
with:
python-version: "3.14"
- name: Install Python packages
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 76e40c4ea3..9282035009 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v6
+ uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Set up dependencies
@@ -44,7 +44,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v6
+ uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Set up dependencies
@@ -67,7 +67,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v6
+ uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Set up dependencies
@@ -90,7 +90,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v6
+ uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Set up dependencies
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b4d4ef171a..a04ca91f56 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -12,7 +12,7 @@ jobs:
create-release:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@v7
- name: Extract changelog for this version
run: |
diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml
index 96e0ca65f8..fc6e79b78f 100644
--- a/.github/workflows/wheels.yml
+++ b/.github/workflows/wheels.yml
@@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python
- uses: actions/setup-python@v6
+ uses: actions/setup-python@v7
with:
python-version: '3.x'
- name: Set up dependencies
diff --git a/AUTHORS b/AUTHORS
index dd2de970e5..89d0485035 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -57,10 +57,3 @@ wxWidgets, which are Copyright (C) 2004-5 by John Labenski, and distributed
under the wxWidgets license. The version included here is the version
dated 20 July 2005; see http://wxcode.sourceforge.net for details on these
classes.
-
-TinyXML parser:
----------------
-The graphical interface reads and writes files in XML format. The parsing
-is done using the TinyXml package from http://www.grinninglizard.com/tinyxml,
-and is distributed under the zlib license. These are the files named
-tiny* in the sources/gui directory of the distribution.
diff --git a/ChangeLog b/ChangeLog
index bca1fd127a..19e30ae56e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,18 @@
-## [16.7.0] - unreleased
+## [17.0.0] - unreleased
+
+### Changed
+- `lcp_solve` no longer silently absorbs internal exceptions if they occur, but instead these propagate out
+ to match the behaviour of all other Nash equilibrium solvers. (#996)
+- `gnm_solve` executes callback when equilibrium is found rather than emitting all equilibria at the end of
+ the run. (#998)
+- Implemented bespoke XML parser that handles the subset in the de-facto legacy XML workbook .gbt format;
+ removes dependency on tinyxml. (#897)
+
+### Fixed
+- Converting a behavior profile to a strategy profile, and computing pure-strategy payoffs
+ no longer inserts spurious entries into a strategy's internal action map.
+
+## [16.7.0] - 2026-07-11
### Added
- Added `Player.sequences` as the collection of sequences available to a player.
@@ -25,6 +39,9 @@
- Corrected calculation of total number of actions for a player in `pygambit` (#938)
- Corrected a regression in action graph games that left the internal data structure not fully initialised,
leading to segmentation faults.
+- Corrected handling of malformed AGG/BAGG files: files with an invalid or degenerate header
+ (for example a wrong file type, or a header declaring zero players) are now rejected with a
+ `ValueError` instead of causing a segmentation fault while constructing the game.
### Changed
- Added a new welcome/landing window on launching the GUI without a game. This has the effect of
@@ -39,6 +56,9 @@
- In `pygambit`, indexing game object collections by integer position has been removed. (#942)
- Validity of game object labels is enforced (printable ASCII and spaces only, no leading/trailing or
double spaces); invalid labels raise `ValueError` in `pygambit`. (#944)
+- Nonempty labels are now required for all players, outcomes, actions, and strategies.
+ Labels must be unique within the game for players and outcomes, within the player for
+ strategies, and within the information set for actions.
- Refined and clarified the graphical interface's handling (and persisting) of "workspaces", and
improved warning messages on closing windows for games or workspaces with unsaved changes.
- In `pygambit`, the `.outcome`, `.player`, and `.infoset` attributes are now treated as predicates
diff --git a/Makefile.am b/Makefile.am
index fde0f3ca11..f606d7eba3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -223,11 +223,7 @@ core_SOURCES = \
src/core/rational.h \
src/core/matrix.cc \
src/core/function.cc \
- src/core/function.h \
- src/core/tinyxml.cc \
- src/core/tinyxmlerror.cc \
- src/core/tinyxmlparser.cc \
- src/core/tinyxml.h
+ src/core/function.h
agg_SOURCES = \
src/games/gameagg.cc \
@@ -270,6 +266,8 @@ game_SOURCES = \
src/games/stratpure.h \
src/games/stratmixed.h \
src/games/file.cc \
+ src/games/workspace.cc \
+ src/games/workspace.h \
src/games/writer.cc \
src/games/writer.h \
src/games/layout.cc \
@@ -477,8 +475,12 @@ gambit_SOURCES = \
src/gui/analysis.h \
src/gui/app.cc \
src/gui/app.h \
+ src/gui/editlabel.cc \
+ src/gui/editlabel.h \
src/gui/edittext.cc \
src/gui/edittext.h \
+ src/gui/labelcell.cc \
+ src/gui/labelcell.h \
src/gui/dlabout.cc \
src/gui/dlabout.h \
src/gui/dleditmove.cc \
@@ -500,7 +502,7 @@ gambit_SOURCES = \
src/gui/dlnash.cc \
src/gui/dlnash.h \
src/gui/dlnashmon.cc \
- src/gui/dlnashmon.h \
+ src/gui/nashspec.h \
src/gui/dlnewtable.cc \
src/gui/dlnewtable.h \
src/gui/dlnfglogit.cc \
diff --git a/README.md b/README.md
index 69ed98074d..288c524587 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,7 @@ installable via PyPI.
 StephenPasteris 🔬 💻 |
 Daniel Kadnikov 🔬 💻 |
 Andrés Fernández Cervell 💻 |
+  wyz2368 💻 🔬 |
diff --git a/build_support/GAMBIT_VERSION b/build_support/GAMBIT_VERSION
index bd015b9036..2e4239c313 100644
--- a/build_support/GAMBIT_VERSION
+++ b/build_support/GAMBIT_VERSION
@@ -1 +1 @@
-16.6.0
+16.7.0
diff --git a/build_support/catalog/catalog.am b/build_support/catalog/catalog.am
index 58c225f429..5af16f3bcf 100644
--- a/build_support/catalog/catalog.am
+++ b/build_support/catalog/catalog.am
@@ -1,6 +1,24 @@
CATALOG_FILES = \
catalog/books/myerson1991/fig2_1.efg \
catalog/books/myerson1991/fig4_2.efg \
+ catalog/books/shohamleytonbrown2008/fig5_1.efg \
+ catalog/books/shohamleytonbrown2008/fig5_10.efg \
+ catalog/books/shohamleytonbrown2008/fig5_10__original_layout.ef \
+ catalog/books/shohamleytonbrown2008/fig5_11.efg \
+ catalog/books/shohamleytonbrown2008/fig5_11__original_layout.ef \
+ catalog/books/shohamleytonbrown2008/fig5_12.efg \
+ catalog/books/shohamleytonbrown2008/fig5_12__original_layout.ef \
+ catalog/books/shohamleytonbrown2008/fig5_15.efg \
+ catalog/books/shohamleytonbrown2008/fig5_15__original_layout.ef \
+ catalog/books/shohamleytonbrown2008/fig5_1__original_layout.ef \
+ catalog/books/shohamleytonbrown2008/fig5_2.efg \
+ catalog/books/shohamleytonbrown2008/fig5_2__original_layout.ef \
+ catalog/books/shohamleytonbrown2008/fig5_9.efg \
+ catalog/books/shohamleytonbrown2008/fig5_9__original_layout.ef \
+ catalog/books/shohamleytonbrown2008/fig6_2.efg \
+ catalog/books/shohamleytonbrown2008/fig6_2__original_layout.ef \
+ catalog/books/shohamleytonbrown2008/fig6_8.efg \
+ catalog/books/shohamleytonbrown2008/fig6_8__original_layout.ef \
catalog/books/vonstengel2022/fig10.1.efg \
catalog/books/vonstengel2022/fig10.12.efg \
catalog/books/vonstengel2022/fig10.5.efg \
@@ -23,6 +41,7 @@ CATALOG_FILES = \
catalog/journals/ijgt/selten1975/fig2.efg \
catalog/journals/ijgt/selten1975/fig3.efg \
catalog/journals/mor/vonstengelforges2008/fig1.efg \
+ catalog/journals/mor/vonstengelforges2008/fig1__Original_Layout.ef \
catalog/journals/mor/vonstengelforges2008/fig6.efg \
catalog/journals/mor/vonstengelforges2008/fig6__Original_Layout.ef \
catalog/journals/mor/vonstengelforges2008/fig9.efg \
diff --git a/build_support/catalog/catalog_hierarchy.yaml b/build_support/catalog/catalog_hierarchy.yaml
index 9280493a6f..591f21320f 100644
--- a/build_support/catalog/catalog_hierarchy.yaml
+++ b/build_support/catalog/catalog_hierarchy.yaml
@@ -14,6 +14,7 @@ labels:
books/myerson1991: "Myerson (1991) — Game Theory: Analysis of Conflict"
books/vonstengel2022: "von Stengel (2022) — Game Theory Basics"
books/watson2013: "Watson (2013) — Strategy: An Introduction to Game Theory"
+ books/shohamleytonbrown2008: "Shoham and Leyton-Brown (2008) — Multiagent Systems, Algorithmic, Game-Theoretic, and Logical Foundations"
journals/geb/gilboa1997: "Gilboa (1997)"
journals/geb/wichardt2008: "Wichardt (2008)"
journals/ijgt/nau2004: "Nau et al. (2004)"
diff --git a/build_support/catalog/gtdraw_settings.yaml b/build_support/catalog/gtdraw_settings.yaml
index 2bbd9889ca..956b107fa7 100644
--- a/build_support/catalog/gtdraw_settings.yaml
+++ b/build_support/catalog/gtdraw_settings.yaml
@@ -44,3 +44,31 @@ overrides:
2: '#DD79E0'
3: '#1616BC'
4: '#985003'
+
+ books/shohamleytonbrown2008/fig6_8:
+ scale_factor: 1.0
+ level_scaling: 1.0
+ sublevel_scaling: 1.0
+ width_scaling: 1.0
+ horizontal: false
+ mirror: false
+ shared_terminal_depth: false
+ color_scheme: colorblind
+ edge_thickness: 1.0
+ action_label_position: 0.5
+ action_label_position_by: player
+ action_label_dist: 1.0
+ vary_action_label_positions: false
+ vary_action_label_positions_by: all
+ font_family: rmfamily
+ font_bold: false
+ font_italic: false
+ font_size: normalsize
+ node_size: 1.5
+ label_bg: false
+ label_bg_color: white
+ label_bg_opacity: 0.8
+ iset_fill: true
+ iset_fill_opacity: 0.2
+ iset_boundary: none
+ legend_position: top-left
diff --git a/build_support/catalog/test_update.py b/build_support/catalog/test_update.py
index 645dc25f9b..e58c63f554 100644
--- a/build_support/catalog/test_update.py
+++ b/build_support/catalog/test_update.py
@@ -147,6 +147,57 @@ def _make_image_files(catalog_dir, slug, fmt="efg"):
(img_dir / f"{slug}.ef").touch()
+# ---------------------------------------------------------------------------
+# Tests for catalog resource selection
+# ---------------------------------------------------------------------------
+
+
+@pytest.mark.catalog_update
+class TestCatalogResourceSelection:
+ def test_catalog_games_uses_requested_catalog_dir_and_restores_resource(
+ self, tmp_path, monkeypatch
+ ):
+ stale_dir = tmp_path / "installed_catalog_data"
+ checkout_dir = tmp_path / "checkout_catalog"
+ stale_dir.mkdir()
+ checkout_dir.mkdir()
+ calls = []
+
+ def fake_games(**kwargs):
+ calls.append((update.gbt.catalog._CATALOG_RESOURCE, kwargs))
+ return _make_df(_efg_row("checkout/game1"))
+
+ monkeypatch.setattr(update.gbt.catalog, "_CATALOG_RESOURCE", stale_dir)
+ monkeypatch.setattr(update.gbt.catalog, "games", fake_games)
+
+ df = update._catalog_games(checkout_dir)
+
+ assert calls == [(checkout_dir, {"include_descriptions": True})]
+ assert stale_dir == update.gbt.catalog._CATALOG_RESOURCE
+ assert list(df["Game"]) == ["checkout/game1"]
+
+ def test_generate_rst_table_uses_requested_catalog_dir_while_rendering(
+ self, tmp_path, monkeypatch
+ ):
+ stale_dir = tmp_path / "installed_catalog_data"
+ checkout_dir = tmp_path / "checkout_catalog"
+ stale_dir.mkdir()
+ checkout_dir.mkdir()
+ observed = []
+
+ def fake_write_tree_level(*args, **kwargs):
+ observed.append(update.gbt.catalog._CATALOG_RESOURCE)
+
+ monkeypatch.setattr(update.gbt.catalog, "_CATALOG_RESOURCE", stale_dir)
+ monkeypatch.setattr(update, "load_hierarchy_labels", lambda: {})
+ monkeypatch.setattr(update, "_write_tree_level", fake_write_tree_level)
+
+ update.generate_rst_table(_make_df(), tmp_path / "out.rst", catalog_dir=checkout_dir)
+
+ assert observed == [checkout_dir]
+ assert stale_dir == update.gbt.catalog._CATALOG_RESOURCE
+
+
# ---------------------------------------------------------------------------
# Tests for catalog_gtdraw_settings
# ---------------------------------------------------------------------------
diff --git a/build_support/catalog/update.py b/build_support/catalog/update.py
index 0cf51385e9..5cc15443b7 100644
--- a/build_support/catalog/update.py
+++ b/build_support/catalog/update.py
@@ -1,6 +1,7 @@
import argparse
import shutil
import sys
+from contextlib import contextmanager
from pathlib import Path
import pandas as pd
@@ -17,6 +18,24 @@
SUPPORTED_GAME_FORMATS = {"efg", "nfg"}
+@contextmanager
+def _using_catalog_dir(catalog_dir: Path):
+ """Temporarily make pygambit.catalog read data from the checked-out catalog."""
+ old_resource = gbt.catalog._CATALOG_RESOURCE
+ gbt.catalog._CATALOG_RESOURCE = catalog_dir
+ try:
+ yield
+ finally:
+ gbt.catalog._CATALOG_RESOURCE = old_resource
+
+
+def _catalog_games(catalog_dir: Path | None = None) -> pd.DataFrame:
+ """Return catalog games using files from *catalog_dir*, not installed package data."""
+ catalog_dir = catalog_dir or CATALOG_DIR
+ with _using_catalog_dir(catalog_dir):
+ return gbt.catalog.games(include_descriptions=True)
+
+
def catalog_gtdraw_settings(slug: str) -> dict:
"""Return the gtdraw settings for a given catalog slug."""
with open(GTDRAW_SETTINGS_CONFIG, encoding="utf-8") as f:
@@ -325,7 +344,7 @@ def generate_rst_table(
catalog_dir = catalog_dir or CATALOG_DIR
labels = load_hierarchy_labels()
tree = _build_slug_tree(df)
- with open(rst_path, "w", encoding="utf-8") as f:
+ with _using_catalog_dir(catalog_dir), open(rst_path, "w", encoding="utf-8") as f:
_write_tree_level(
f, tree, "", labels, catalog_dir, indent="", regenerate_images=regenerate_images
)
@@ -409,7 +428,7 @@ def update_makefile(
args = parser.parse_args()
# Create RST list-table used by doc/catalog.rst
- df = gbt.catalog.games(include_descriptions=True)
+ df = _catalog_games()
_warn_missing_descriptions(df)
generate_rst_table(df, CATALOG_RST_TABLE, regenerate_images=args.regenerate_images)
print(f"Generated {CATALOG_RST_TABLE} for use in local docs build. DO NOT COMMIT.")
diff --git a/catalog/books/shohamleytonbrown2008/fig5_1.efg b/catalog/books/shohamleytonbrown2008/fig5_1.efg
new file mode 100644
index 0000000000..49f598d289
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_1.efg
@@ -0,0 +1,21 @@
+EFG 2 R "Fig 5.1 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 5.1 from :cite:p:`ShoLeyB08`.
+This is a sharing game. Imagine a brother and sister sharing two indivisible and identical presents
+from their parents. First the brother suggests a split, which can be one of three: he
+keeps both, she keeps both, or they each keep one. Then the sister chooses whether
+to accept or reject the split. If she accepts they each get their allocated present(s),
+and otherwise neither gets any gift.
+"
+
+p "" 1 1 "" { "2-0" "1-1" "0-2" } 0
+p "" 2 2 "" { "no" "yes" } 0
+t "" 1 "" { 0 0 }
+t "" 2 "" { 2 0 }
+p "" 2 3 "" { "no" "yes" } 0
+t "" 3 "" { 0 0 }
+t "" 4 "" { 1 1 }
+p "" 2 4 "" { "no" "yes" } 0
+t "" 5 "" { 0 0 }
+t "" 6 "" { 0 2 }
diff --git a/catalog/books/shohamleytonbrown2008/fig5_10.efg b/catalog/books/shohamleytonbrown2008/fig5_10.efg
new file mode 100644
index 0000000000..94cd759ff3
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_10.efg
@@ -0,0 +1,16 @@
+EFG 2 R "Fig 5.10 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 5.10 from :cite:p:`ShoLeyB08`.
+This is an example of an imperfect-information game.
+"
+
+p "" 1 2 "" { "L" "R" } 0
+p "" 2 3 "" { "A" "B" } 0
+p "" 1 1 "" { "l" "r" } 0
+t "" 1 "" { 0 0 }
+t "" 2 "" { 2 4 }
+p "" 1 1 0
+t "" 3 "" { 4 2 }
+t "" 4 "" { 0 0 }
+t "" 5 "" { 0 0 }
diff --git a/catalog/books/shohamleytonbrown2008/fig5_10__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig5_10__original_layout.ef
new file mode 100644
index 0000000000..55e9832224
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_10__original_layout.ef
@@ -0,0 +1,12 @@
+player 1 name 1
+player 2 name 2
+level 0 node 1 player 1
+level 2 node 1 player 2 xshift -3.58 from 0,1 move L
+level 2 node 2 xshift 3.58 from 0,1 move R payoffs 0 0
+level 4 node 1 xshift -2.86 from 2,1 move A
+level 4 node 2 xshift 2.86 from 2,1 move B
+level 6 node 1 xshift -1.43 from 4,1 move l payoffs 0 0
+level 6 node 2 xshift 1.43 from 4,1 move r payoffs 2 4
+level 6 node 3 xshift -1.43 from 4,2 move l payoffs 4 2
+level 6 node 4 xshift 1.43 from 4,2 move r payoffs 0 0
+iset 4,1 4,2 player 1
diff --git a/catalog/books/shohamleytonbrown2008/fig5_11.efg b/catalog/books/shohamleytonbrown2008/fig5_11.efg
new file mode 100644
index 0000000000..a972fb90be
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_11.efg
@@ -0,0 +1,14 @@
+EFG 2 R "Fig 5.11 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 5.11 from :cite:p:`ShoLeyB08`.
+The Prisoner's Dilemma game in extensive form.
+"
+
+p "" 1 2 "" { "C" "D" } 0
+p "" 2 1 "" { "c" "d" } 0
+t "" 1 "" { -1 -1 }
+t "" 2 "" { -4 0 }
+p "" 2 1 0
+t "" 3 "" { 0 -4 }
+t "" 4 "" { -3 -3 }
diff --git a/catalog/books/shohamleytonbrown2008/fig5_11__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig5_11__original_layout.ef
new file mode 100644
index 0000000000..8aa60582e2
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_11__original_layout.ef
@@ -0,0 +1,10 @@
+player 1 name 1
+player 2 name 2
+level 0 node 1 player 1
+level 2 node 1 xshift -3.58 from 0,1 move C
+level 2 node 2 xshift 3.58 from 0,1 move D
+level 4 node 1 xshift -1.79 from 2,1 move c payoffs -1 -1
+level 4 node 2 xshift 1.79 from 2,1 move d payoffs -4 0
+level 4 node 3 xshift -1.79 from 2,2 move c payoffs 0 -4
+level 4 node 4 xshift 1.79 from 2,2 move d payoffs -3 -3
+iset 2,1 2,2 player 2
diff --git a/catalog/books/shohamleytonbrown2008/fig5_12.efg b/catalog/books/shohamleytonbrown2008/fig5_12.efg
new file mode 100644
index 0000000000..27c70afe2d
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_12.efg
@@ -0,0 +1,15 @@
+EFG 2 R "Fig 5.12 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 5.12 from :cite:p:`ShoLeyB08`.
+A game with imperfect recall, in particular absent-mindedness.
+"
+
+
+p "" 1 1 "" { "L" "R" } 0
+p "" 1 1 0
+t "" 1 "" { 1 0 }
+t "" 2 "" { 100 100 }
+p "" 2 2 "" { "U" "D" } 0
+t "" 3 "" { 5 1 }
+t "" 4 "" { 2 2 }
diff --git a/catalog/books/shohamleytonbrown2008/fig5_12__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig5_12__original_layout.ef
new file mode 100644
index 0000000000..98b720cdc2
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_12__original_layout.ef
@@ -0,0 +1,15 @@
+% Extensive-form game transcribed from the uploaded image
+player 1 name 1
+player 2 name 2
+
+% Player 1's two decision nodes are in the same information set.
+level 0 node 1
+level 2 node 1 xshift -3 from 0,1 move L
+level 2 node 2 xshift 3 from 0,1 move R player 2
+
+level 4 node 1 xshift -1 from 2,1 move L payoffs 1 0
+level 4 node 2 xshift 1 from 2,1 move R payoffs 100 100
+level 4 node 3 xshift -1 from 2,2 move U payoffs 5 1
+level 4 node 4 xshift 1 from 2,2 move D payoffs 2 2
+
+iset 0,1 2,1 player 1
diff --git a/catalog/books/shohamleytonbrown2008/fig5_15.efg b/catalog/books/shohamleytonbrown2008/fig5_15.efg
new file mode 100644
index 0000000000..ceb402d948
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_15.efg
@@ -0,0 +1,17 @@
+EFG 2 R "Fig 5.15 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 5.15 from :cite:p:`ShoLeyB08`.
+A game with imperfect information.
+This example shows how a requirement that a substrategy be a best response in
+all subgames is too simplistic for defining SPE in games with imperfect information.
+"
+
+p "" 1 2 "" { "L" "C" "R" } 0
+t "" 1 "" { 1 1 }
+p "" 2 1 "" { "U" "D" } 0
+t "" 2 "" { 0 1000 }
+t "" 3 "" { 0 0 }
+p "" 2 1 0
+t "" 4 "" { 1 0 }
+t "" 5 "" { 3 1 }
diff --git a/catalog/books/shohamleytonbrown2008/fig5_15__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig5_15__original_layout.ef
new file mode 100644
index 0000000000..50d5d34460
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_15__original_layout.ef
@@ -0,0 +1,11 @@
+player 1 name 1
+player 2 name 2
+level 0 node 1 player 1
+level 2 node 1 xshift -5.01 from 0,1 move L payoffs 1 1
+level 2 node 2 xshift -0.72 from 0,1 move C
+level 2 node 3 xshift 5.01 from 0,1 move R
+level 4 node 1 xshift -1.43 from 2,2 move U payoffs 0 1000
+level 4 node 2 xshift 1.43 from 2,2 move D payoffs 0 0
+level 4 node 3 xshift -1.43 from 2,3 move U payoffs 1 0
+level 4 node 4 xshift 1.43 from 2,3 move D payoffs 3 1
+iset 2,2 2,3 player 2
diff --git a/catalog/books/shohamleytonbrown2008/fig5_1__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig5_1__original_layout.ef
new file mode 100644
index 0000000000..492f047541
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_1__original_layout.ef
@@ -0,0 +1,12 @@
+player 1 name 1
+player 2 name 2
+level 0 node 1 player 1
+level 2 node 1 player 2 xshift -4.77 from 0,1 move 2-0
+level 2 node 2 player 2 xshift 0 from 0,1 move 1-1
+level 4 node 1 xshift -1.19 from 2,1 move no payoffs 0 0
+level 4 node 2 xshift 1.19 from 2,1 move yes payoffs 2 0
+level 2 node 3 player 2 xshift 4.77 from 0,1 move 0-2
+level 4 node 3 xshift -1.19 from 2,2 move no payoffs 0 0
+level 4 node 4 xshift 1.19 from 2,2 move yes payoffs 1 1
+level 4 node 5 xshift -1.19 from 2,3 move no payoffs 0 0
+level 4 node 6 xshift 1.19 from 2,3 move yes payoffs 0 2
diff --git a/catalog/books/shohamleytonbrown2008/fig5_2.efg b/catalog/books/shohamleytonbrown2008/fig5_2.efg
new file mode 100644
index 0000000000..5ed1bd1893
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_2.efg
@@ -0,0 +1,16 @@
+EFG 2 R "Fig 5.2 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 5.2 from :cite:p:`ShoLeyB08`.
+This is an example of a perfect-information game in extensive form.
+"
+
+p "" 1 1 "" { "A" "B" } 0
+p "" 2 2 "" { "C" "D" } 0
+t "" 1 "" { 3 8 }
+t "" 2 "" { 8 3 }
+p "" 2 3 "" { "E" "F" } 0
+t "" 3 "" { 5 5 }
+p "" 1 4 "" { "G" "H" } 0
+t "" 4 "" { 2 10 }
+t "" 5 "" { 1 0 }
diff --git a/catalog/books/shohamleytonbrown2008/fig5_2__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig5_2__original_layout.ef
new file mode 100644
index 0000000000..1d55ae617a
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_2__original_layout.ef
@@ -0,0 +1,11 @@
+player 1 name 1
+player 2 name 2
+level 0 node 1 player 1
+level 2 node 1 player 2 xshift -3.22 from 0,1 move A
+level 2 node 2 player 2 xshift 3.22 from 0,1 move B
+level 4 node 1 xshift -1.43 from 2,1 move C payoffs 3 8
+level 4 node 2 xshift 1.43 from 2,1 move D payoffs 8 3
+level 4 node 3 xshift -2.15 from 2,2 move E payoffs 5 5
+level 4 node 4 player 1 xshift 2.15 from 2,2 move F
+level 6 node 1 xshift -1.43 from 4,4 move G payoffs 2 10
+level 6 node 2 xshift 1.43 from 4,4 move H payoffs 1 0
diff --git a/catalog/books/shohamleytonbrown2008/fig5_9.efg b/catalog/books/shohamleytonbrown2008/fig5_9.efg
new file mode 100644
index 0000000000..861c7c0b70
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_9.efg
@@ -0,0 +1,22 @@
+EFG 2 R "Fig 5.9 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 5.9 from :cite:p:`ShoLeyB08`.
+This is the centipede game. In this game two players alternate in making decisions, at each
+turn choosing between going down and ending the game or going across and
+continuing it.
+This example is used to explain the criticisms of backward induction for finding subgame-perfect equilibrium.
+Note that centipede is also a parametrized game, with the parameter being the number of rounds.
+"
+
+p "" 1 1 "" { "A" "D" } 0
+t "" 1 "" { 1 0 }
+p "" 2 2 "" { "A" "D" } 0
+t "" 2 "" { 0 2 }
+p "" 1 3 "" { "A" "D" } 0
+t "" 3 "" { 3 1 }
+p "" 2 4 "" { "A" "D" } 0
+t "" 4 "" { 2 4 }
+p "" 1 5 "" { "A" "D" } 0
+t "" 5 "" { 4 3 }
+t "" 6 "" { 3 5 }
diff --git a/catalog/books/shohamleytonbrown2008/fig5_9__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig5_9__original_layout.ef
new file mode 100644
index 0000000000..9f477bc52a
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig5_9__original_layout.ef
@@ -0,0 +1,13 @@
+player 1 name 1
+player 2 name 2
+level 0 node 1 player 1
+level 2 node 1 xshift -2.31 from 0,1 move A payoffs 1 0
+level 2 node 2 player 2 xshift 2.31 from 0,1 move D
+level 4 node 1 xshift -2.24 from 2,2 move A payoffs 0 2
+level 4 node 2 player 1 xshift 2.24 from 2,2 move D
+level 6 node 1 xshift -2.09 from 4,2 move A payoffs 3 1
+level 6 node 2 player 2 xshift 2.09 from 4,2 move D
+level 8 node 1 xshift -1.79 from 6,2 move A payoffs 2 4
+level 8 node 2 player 1 xshift 1.79 from 6,2 move D
+level 10 node 1 xshift -1.19 from 8,2 move A payoffs 4 3
+level 10 node 2 xshift 1.19 from 8,2 move D payoffs 3 5
diff --git a/catalog/books/shohamleytonbrown2008/fig6_2.efg b/catalog/books/shohamleytonbrown2008/fig6_2.efg
new file mode 100644
index 0000000000..6a543e3615
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig6_2.efg
@@ -0,0 +1,38 @@
+EFG 2 R "Fig 6.2 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 6.2 from :cite:p:`ShoLeyB08`.
+This is a repeated game, where Prisoner's Dilemma is played twice.
+"
+
+p "" 1 6 "" { "C" "D" } 0
+p "" 2 1 "" { "c" "d" } 0
+p "" 1 7 "" { "C" "D" } 0
+p "" 2 4 "" { "c" "d" } 0
+t "" 1 "" { -2 -2 }
+t "" 2 "" { -5 -1 }
+p "" 2 4 0
+t "" 3 "" { -1 -5 }
+t "" 4 "" { -4 -4 }
+p "" 1 8 "" { "C" "D" } 0
+p "" 2 5 "" { "c" "d" } 0
+t "" 5 "" { -5 -1 }
+t "" 6 "" { -8 0 }
+p "" 2 5 0
+t "" 7 "" { -4 -4 }
+t "" 8 "" { -7 -3 }
+p "" 2 1 0
+p "" 1 9 "" { "C" "D" } 0
+p "" 2 2 "" { "c" "d" } 0
+t "" 9 "" { -1 -5 }
+t "" 10 "" { -4 -4 }
+p "" 2 2 0
+t "" 11 "" { 0 -8 }
+t "" 12 "" { -3 -7 }
+p "" 1 10 "" { "C" "D" } 0
+p "" 2 3 "" { "c" "d" } 0
+t "" 13 "" { -4 -4 }
+t "" 14 "" { -7 -3 }
+p "" 2 3 0
+t "" 15 "" { -3 -7 }
+t "" 16 "" { -6 -6 }
diff --git a/catalog/books/shohamleytonbrown2008/fig6_2__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig6_2__original_layout.ef
new file mode 100644
index 0000000000..563e3b0f07
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig6_2__original_layout.ef
@@ -0,0 +1,38 @@
+player 1 name 1
+player 2 name 2
+level 0 node 1 player 1
+level 2 node 1 xshift -6.37 from 0,1 move C
+level 2 node 2 xshift 6.37 from 0,1 move D
+level 4 node 1 player 1 xshift -3.19 from 2,1 move c
+level 4 node 2 player 1 xshift 3.19 from 2,1 move d
+level 4 node 3 player 1 xshift -3.19 from 2,2 move c
+level 4 node 4 player 1 xshift 3.19 from 2,2 move d
+level 6 node 1 xshift -1.59 from 4,1 move C
+level 6 node 2 xshift 1.59 from 4,1 move D
+level 6 node 3 xshift -1.59 from 4,2 move C
+level 6 node 4 xshift 1.59 from 4,2 move D
+level 6 node 5 xshift -1.59 from 4,3 move C
+level 6 node 6 xshift 1.59 from 4,3 move D
+level 6 node 7 xshift -1.59 from 4,4 move C
+level 6 node 8 xshift 1.59 from 4,4 move D
+level 8 node 1 xshift -0.8 from 6,1 move c payoffs -2 -2
+level 8 node 2 xshift 0.8 from 6,1 move d payoffs -5 -1
+level 8 node 3 xshift -0.8 from 6,2 move c payoffs -1 -5
+level 8 node 4 xshift 0.8 from 6,2 move d payoffs -4 -4
+level 8 node 5 xshift -0.8 from 6,3 move c payoffs -5 -1
+level 8 node 6 xshift 0.8 from 6,3 move d payoffs -8 0
+level 8 node 7 xshift -0.8 from 6,4 move c payoffs -4 -4
+level 8 node 8 xshift 0.8 from 6,4 move d payoffs -7 -3
+level 8 node 9 xshift -0.8 from 6,5 move c payoffs -1 -5
+level 8 node 10 xshift 0.8 from 6,5 move d payoffs -4 -4
+level 8 node 11 xshift -0.8 from 6,6 move c payoffs 0 -8
+level 8 node 12 xshift 0.8 from 6,6 move d payoffs -3 -7
+level 8 node 13 xshift -0.8 from 6,7 move c payoffs -4 -4
+level 8 node 14 xshift 0.8 from 6,7 move d payoffs -7 -3
+level 8 node 15 xshift -0.8 from 6,8 move c payoffs -3 -7
+level 8 node 16 xshift 0.8 from 6,8 move d payoffs -6 -6
+iset 2,1 2,2 player 2
+iset 6,5 6,6 player 2
+iset 6,7 6,8 player 2
+iset 6,1 6,2 player 2
+iset 6,3 6,4 player 2
diff --git a/catalog/books/shohamleytonbrown2008/fig6_8.efg b/catalog/books/shohamleytonbrown2008/fig6_8.efg
new file mode 100644
index 0000000000..08e0e3cbac
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig6_8.efg
@@ -0,0 +1,36 @@
+EFG 2 R "Fig 6.8 from Shoham and Leyton-Brown (2008)" { "1" "2" }
+
+"
+Figure 6.8 from :cite:p:`ShoLeyB08`.
+This is a Bayesian game, represented in EFG with Nature deciding the types.
+"
+
+c "" 5 "" { "MP" 1/4 "PD" 1/4 "Coord" 1/4 "BoS" 1/4 } 0
+p "" 1 1 "" { "U" "D" } 0
+p "" 2 3 "" { "L" "R" } 0
+t "" 1 "" { 2 0 }
+t "" 2 "" { 0 2 }
+p "" 2 3 0
+t "" 3 "" { 0 2 }
+t "" 4 "" { 2 0 }
+p "" 1 1 0
+p "" 2 4 "" { "L" "R" } 0
+t "" 5 "" { 2 2 }
+t "" 6 "" { 0 3 }
+p "" 2 4 0
+t "" 7 "" { 3 0 }
+t "" 8 "" { 1 1 }
+p "" 1 2 "" { "U" "D" } 0
+p "" 2 3 0
+t "" 9 "" { 2 2 }
+t "" 10 "" { 0 0 }
+p "" 2 3 0
+t "" 11 "" { 0 0 }
+t "" 12 "" { 1 1 }
+p "" 1 2 0
+p "" 2 4 0
+t "" 13 "" { 2 1 }
+t "" 14 "" { 0 0 }
+p "" 2 4 0
+t "" 15 "" { 0 0 }
+t "" 16 "" { 1 2 }
diff --git a/catalog/books/shohamleytonbrown2008/fig6_8__original_layout.ef b/catalog/books/shohamleytonbrown2008/fig6_8__original_layout.ef
new file mode 100644
index 0000000000..a01dfbf0fa
--- /dev/null
+++ b/catalog/books/shohamleytonbrown2008/fig6_8__original_layout.ef
@@ -0,0 +1,92 @@
+% Four games with uniform chance and non-overlapping information sets.
+% Nature chooses among MP, PD, Coord, and BoS with probability 1/4 each.
+%
+% The Player 2 information sets are separated vertically:
+% - MP and Coord nodes are at level 5.
+% - PD and BoS nodes are at level 11.
+%
+% The additional spacing prevents the U/D labels and the terminal
+% payoffs of the upper subtrees from overlapping either information set.
+
+player 0 name Nature
+player 1 name 1
+player 2 name 2
+
+% Nature root
+level 0 node 1 player 0
+
+% Nature moves
+% MP and PD belong to Player 1's first information set.
+level 2 node 1 xshift -7.5 from 0,1 move MP~(1/4)
+level 2 node 2 xshift -2.5 from 0,1 move PD~(1/4)
+
+% Coord and BoS belong to Player 1's second information set.
+level 3 node 3 xshift 2.5 from 0,1 move Coord~(1/4)
+level 3 node 4 xshift 7.5 from 0,1 move BoS~(1/4)
+
+% Player 1 moves U/D
+
+% Matching Pennies:
+% These nodes belong to Player 2 information set 1.
+level 5 node 1 xshift -1 from 2,1 move U
+level 5 node 2 xshift 1 from 2,1 move D
+
+% Prisoner's Dilemma:
+% These nodes belong to Player 2 information set 2.
+level 11 node 3 xshift -1 from 2,2 move U
+level 11 node 4 xshift 1 from 2,2 move D
+
+% Coordination:
+% These nodes belong to Player 2 information set 1.
+level 5 node 5 xshift -1 from 3,3 move U
+level 5 node 6 xshift 1 from 3,3 move D
+
+% Battle of the Sexes:
+% These nodes belong to Player 2 information set 2.
+level 11 node 7 xshift -1 from 3,4 move U
+level 11 node 8 xshift 1 from 3,4 move D
+
+% Player 2 moves L/R and terminal payoffs
+
+% Matching Pennies
+% The terminal level is sufficiently above the second information set.
+level 8 node 1 xshift -0.55 from 5,1 move L payoffs 2 0
+level 8 node 2 xshift 0.55 from 5,1 move R payoffs 0 2
+level 8 node 3 xshift -0.55 from 5,2 move L payoffs 0 2
+level 8 node 4 xshift 0.55 from 5,2 move R payoffs 2 0
+
+% Prisoner's Dilemma
+level 14 node 5 xshift -0.55 from 11,3 move L payoffs 2 2
+level 14 node 6 xshift 0.55 from 11,3 move R payoffs 0 3
+level 14 node 7 xshift -0.55 from 11,4 move L payoffs 3 0
+level 14 node 8 xshift 0.55 from 11,4 move R payoffs 1 1
+
+% Coordination
+% These payoffs are placed at level 8, leaving three levels before
+% the lower Player 2 information set at level 11.
+level 8 node 9 xshift -0.55 from 5,5 move L payoffs 2 2
+level 8 node 10 xshift 0.55 from 5,5 move R payoffs 0 0
+level 8 node 11 xshift -0.55 from 5,6 move L payoffs 0 0
+level 8 node 12 xshift 0.55 from 5,6 move R payoffs 1 1
+
+% Battle of the Sexes
+level 14 node 13 xshift -0.55 from 11,7 move L payoffs 2 1
+level 14 node 14 xshift 0.55 from 11,7 move R payoffs 0 0
+level 14 node 15 xshift -0.55 from 11,8 move L payoffs 0 0
+level 14 node 16 xshift 0.55 from 11,8 move R payoffs 1 2
+
+% Player 1 information sets
+
+% Player 1 cannot distinguish MP from PD.
+iset 2,1 2,2 player 1
+
+% Player 1 cannot distinguish Coordination from Battle of the Sexes.
+iset 3,3 3,4 player 1
+
+% Player 2 information sets
+
+% Player 2 cannot distinguish MP from Coordination.
+iset 5,1 5,2 5,5 5,6 player 2
+
+% Player 2 cannot distinguish PD from Battle of the Sexes.
+iset 11,3 11,4 11,7 11,8 player 2
diff --git a/catalog/journals/mor/vonstengelforges2008/fig1__Original_Layout.ef b/catalog/journals/mor/vonstengelforges2008/fig1__Original_Layout.ef
new file mode 100644
index 0000000000..9896620e88
--- /dev/null
+++ b/catalog/journals/mor/vonstengelforges2008/fig1__Original_Layout.ef
@@ -0,0 +1,57 @@
+% Extensive-form game transcribed from the provided figure.
+% DrawTree .ef format.
+% Layout is chosen to preserve the original geometry of the image:
+% chance at the top, two Player 1 singleton information sets,
+% crossed middle branches, and two horizontal Player 2 information sets.
+%
+% Player 0: Chance
+% Player 1: 1
+% Player 2: 2
+%
+% Chance chooses G or B with probability 1/2 each.
+% Player 1 observes the chance outcome and chooses X or Y, with labels
+% indexed by the realized chance outcome: X_G, Y_G, X_B, Y_B.
+% Player 2 observes only whether the signal is X or Y, not the chance outcome.
+
+player 0 name Chance
+player 1 name 1
+player 2 name 2
+
+% Root chance node.
+level 0 node n1 player 0
+
+% Chance branches, arranged as in the figure.
+level 2 node n2 xshift -2.8 from n1 move \frac{1}{2} player 1
+level 2 node n3 xshift 2.8 from n1 move \frac{1}{2} player 1
+
+% Player 1 branches.
+% Left Player 1 node: chance outcome G.
+level 4 node n4 xshift -2.5 yshift -0.9 from n2 move X_G
+level 4 node n5 xshift 3.9 yshift -0.9 from n2 move Y_G
+
+% Right Player 1 node: chance outcome B.
+% The X_B and Y_G branches cross, matching the original layout.
+level 4 node n6 xshift -3.9 yshift -0.9 from n3 move X_B
+level 4 node n7 xshift 2.5 yshift -0.9 from n3 move Y_B
+
+% Player 2 information sets.
+% X-signal information set: histories (G,X_G) and (B,X_B).
+iset n4 n6 player 2
+
+% Y-signal information set: histories (G,Y_G) and (B,Y_B).
+iset n5 n7 player 2
+
+% Player 2 actions and terminal payoffs, listed left-to-right as in the image.
+% At the X-signal information set.
+level 6 node n8 xshift -0.45 from n4 move l_X payoffs 4 10
+level 6 node n9 xshift 0.45 from n4 move r_X payoffs 0 6
+
+level 6 node n10 xshift -0.45 from n6 move l_X payoffs 6 0
+level 6 node n11 xshift 0.45 from n6 move r_X payoffs 0 6
+
+% At the Y-signal information set.
+level 6 node n12 xshift -0.45 from n5 move l_Y payoffs 4 10
+level 6 node n13 xshift 0.45 from n5 move r_Y payoffs 0 6
+
+level 6 node n14 xshift -0.45 from n7 move l_Y payoffs 6 0
+level 6 node n15 xshift 0.45 from n7 move r_Y payoffs 0 6
diff --git a/doc/algorithms.rst b/doc/algorithms.rst
index 0f4b332601..260ea688db 100644
--- a/doc/algorithms.rst
+++ b/doc/algorithms.rst
@@ -15,7 +15,7 @@ Algorithm Description
:ref:`lp` Compute equilibria in a two-player constant-sum game via linear programming :py:func:`pygambit.nash.lp_solve` :ref:`gambit-lp `
:ref:`lcp` Compute equilibria in a two-player game via linear complementarity :py:func:`pygambit.nash.lcp_solve` :ref:`gambit-lcp `
:ref:`liap` Compute equilibria using function minimization :py:func:`pygambit.nash.liap_solve` :ref:`gambit-liap `
-:ref:`logit` Compute quantal response equilibria :py:func:`pygambit.nash.logit_solve` :ref:`gambit-logit `
+:ref:`logit` Trace logit QRE and approximate a Nash equilibrium at high precision :py:func:`pygambit.nash.logit_solve` :ref:`gambit-logit `
:ref:`simpdiv` Compute equilibria via simplicial subdivision :py:func:`pygambit.nash.simpdiv_solve` :ref:`gambit-simpdiv `
:ref:`ipa` Compute equilibria using iterated polymatrix approximation :py:func:`pygambit.nash.ipa_solve` :ref:`gambit-ipa `
:ref:`gnm` Compute equilibria using a global Newton method :py:func:`pygambit.nash.gnm_solve` :ref:`gambit-gnm `
@@ -141,6 +141,10 @@ logit
Computes the
principal branch of the (logit) quantal response correspondence.
+Following this branch toward large values of the precision parameter
+provides an approximation to a Nash equilibrium. The graphical
+interface uses this limiting calculation when it selects ``logit`` as
+the recommended method for computing one Nash equilibrium.
The method is based on the procedure described in Turocy :cite:p:`Tur05` for
strategic games and Turocy :cite:p:`Tur10` for extensive games.
diff --git a/doc/gui.nash.rst b/doc/gui.nash.rst
index 1891dad4ce..b9b9a200f6 100644
--- a/doc/gui.nash.rst
+++ b/doc/gui.nash.rst
@@ -38,22 +38,62 @@ are to be found. Some algorithms for computing equilibria are adapted
to finding a single equilibrium, while others attempt to compute the
whole equilibrium set. The first drop-down in the dialog specifies how
many equilibria to compute. In this drop-down there are options for
-:guilabel:`as many equilibria as possible` and, for two-player games,
-:guilabel:`all equilibria`. For some games, there exist algorithms which will
+:guilabel:`Compute one Nash equilibrium`, :guilabel:`Compute some Nash equilibria`,
+and, for two-player games, :guilabel:`Compute all Nash equilibria`.
+For some games, there exist algorithms which will
compute many equilibria (relatively) efficiently, but are not
guaranteed to find all equilibria.
-To simplify this process of choosing the method to compute equilibria
-in the second drop-down, Gambit provides for any game "recommended"
-methods for computing one, some, and all Nash equilibria,
-respectively. These methods are selected based on experience as to the
-efficiency and reliability of the methods, and should generally work
-well on most games. For more control over the process, the user can
-select from the second drop-down in the dialog one of the appropriate
-methods for computing equilibria. This list only shows the methods
-which are appropriate for the game, given the selection of how many
-equilibria to compute. More details on these methods are contained
-in :ref:`command-line`.
+To simplify this process of choosing the method to compute equilibria,
+the second drop-down offers :guilabel:`Gambit's recommended method`.
+The recommendation is determined by the requested number of equilibria
+and the structure of the game as follows.
+
+======================= ============================================= ==================
+Requested output Game Method
+======================= ============================================= ==================
+One equilibrium Two players and constant sum :ref:`lp`
+One equilibrium Any other supported game :ref:`logit`
+Some equilibria Two players :ref:`lcp`
+Some equilibria Three or more players :ref:`simpdiv`
+All equilibria Two players :ref:`enummixed`
+======================= ============================================= ==================
+
+The :guilabel:`all equilibria` choice is therefore offered only for
+two-player games. The recommendation selects an algorithm; it does not
+infer properties such as uniqueness. In particular, "some" means that
+the selected method searches for multiple equilibria where possible, not
+that a particular number of distinct equilibria is guaranteed.
+
+For more control, the user can select one of the other methods shown in
+the second drop-down. The list is filtered using the requested output
+category and the methods' applicability. Methods which only operate on
+strategic games automatically select and lock the strategic
+representation. Otherwise an extensive game may be solved using either
+its behavior representation or its reduced strategic representation.
+See :ref:`algorithms` for descriptions and limitations of the methods.
+
+The current dialog uses the following solver parameters. They are
+recorded with each computation so that the interface can expose them for
+editing in a future revision.
+
+================ ============================================================================
+Method Parameters used by the graphical interface
+================ ============================================================================
+``enumpure`` Enumerate all pure-strategy equilibria.
+``enummixed`` Enumerate all mixed-strategy extreme equilibria.
+``enumpoly`` Stop after the first equilibrium when "one" is requested; otherwise search all
+ supports; maximum regret ``1e-4``.
+``lp`` No method-specific parameters.
+``lcp`` Search all accessible equilibria; unlimited recursion depth.
+``liap`` 10 random starting points; 1,000 iterations per point; maximum regret ``1e-4``.
+``logit`` Maximum regret ``1e-8``; initial step ``0.03``; maximum acceleration ``1.1``.
+``simpdiv`` One random starting point when "one" is requested, otherwise 20; denominator
+ 100; grid resize factor 2; maximum regret ``1/10000000``.
+``ipa`` One random perturbation.
+``gnm`` One random perturbation; ending lambda ``-10``; 100 steps per support cell;
+ local Newton refinement every 3 steps, with at most 10 iterations.
+================ ============================================================================
.. image:: screens/computing.*
:width: 33%
@@ -61,11 +101,12 @@ in :ref:`command-line`.
:align: right
:target: _images/computing.png
-Finally, for extensive games, there is an option of whether to use the
-extensive or strategic game for computation. In general, computation
+For extensive games, there is an option of whether to use the
+extensive or strategic game for computation when the selected method
+supports both. In general, computation
using the extensive game is preferred, since it is often a
significantly more compact representation of the strategic
-characeteristics of the game than the reduced strategic game is.
+characteristics of the game than the reduced strategic game is.
For even moderate sized games, computation of equilibrium can be a
time-intensive process. Gambit runs all computations in the
diff --git a/doc/references.bib b/doc/references.bib
index 36ae6110e6..728be714ca 100644
--- a/doc/references.bib
+++ b/doc/references.bib
@@ -430,5 +430,6 @@ @book{ShoLeyB08
title={Multiagent systems: Algorithmic, game-theoretic, and logical foundations},
author={Shoham, Yoav and Leyton-Brown, Kevin},
year={2008},
- publisher={Cambridge University Press}
+ publisher={Cambridge University Press},
+ category = {textbooks}
}
diff --git a/doc/tutorials/02_extensive_form.ipynb b/doc/tutorials/02_extensive_form.ipynb
index 1f4f6fd0ee..bba579e9f6 100644
--- a/doc/tutorials/02_extensive_form.ipynb
+++ b/doc/tutorials/02_extensive_form.ipynb
@@ -4,7 +4,30 @@
"cell_type": "markdown",
"id": "96019084",
"metadata": {},
- "source": "# 2) Extensive-form games\n\nIn the first tutorial, we used Gambit to set up the Prisoner's Dilemma, an example of a normal (strategic) form game.\n\nGambit can also be used to set up extensive-form games; the game is represented as a tree, where each node represents a decision point for a player, and the branches represent the possible actions they can take.\n\n**Example: One-shot trust game with binary actions**\n\n[Kreps (1990)](#references) introduced a game commonly referred to as the **trust game**.\nWe will build a one-shot version of this game using Gambit's game transformation operations.\n\nThe game can be defined as follows:\n- There are two players, a **Buyer** and a **Seller**.\n- The Buyer moves first and has two actions, **Trust** or **Not trust**.\n- If the Buyer chooses **Not trust**, then the game ends, and both players receive payoffs of `0`.\n- If the Buyer chooses **Trust**, then the Seller has a choice with two actions, **Honor** or **Abuse**.\n- If the Seller chooses **Honor**, both players receive payoffs of `1`;\n- If the Seller chooses **Abuse**, the Buyer receives a payoff of `-1` and the Seller receives a payoff of `2`.\n\nIn addition to `pygambit`, this tutorial introduces the `gtdraw` package, which can be used to draw extensive form games in Python.\nIf you're running this tutorial on your local machine, you'll need to install the requirements for [gtdraw](https://www.gambit-project.org/gtdraw/), which include LaTeX, in order to run the `gtdraw` cells.\nAnother option for visualising extensive form games is to install the Gambit GUI and use it to load the EFG file generated at the end of this tutorial."
+ "source": [
+ "# 2) Extensive-form games\n",
+ "\n",
+ "In the first tutorial, we used Gambit to set up the Prisoner's Dilemma, an example of a normal (strategic) form game.\n",
+ "\n",
+ "Gambit can also be used to set up extensive-form games; the game is represented as a tree, where each node represents a decision point for a player, and the branches represent the possible actions they can take.\n",
+ "\n",
+ "**Example: One-shot trust game with binary actions**\n",
+ "\n",
+ "[Kreps (1990)](#references) introduced a game commonly referred to as the **trust game**.\n",
+ "We will build a one-shot version of this game using Gambit's game transformation operations.\n",
+ "\n",
+ "The game can be defined as follows:\n",
+ "- There are two players, a **Buyer** and a **Seller**.\n",
+ "- The Buyer moves first and has two actions, **Trust** or **Not trust**.\n",
+ "- If the Buyer chooses **Not trust**, then the game ends, and both players receive payoffs of `0`.\n",
+ "- If the Buyer chooses **Trust**, then the Seller has a choice with two actions, **Honor** or **Abuse**.\n",
+ "- If the Seller chooses **Honor**, both players receive payoffs of `1`;\n",
+ "- If the Seller chooses **Abuse**, the Buyer receives a payoff of `-1` and the Seller receives a payoff of `2`.\n",
+ "\n",
+ "In addition to `pygambit`, this tutorial introduces the `gtdraw` package, which can be used to draw extensive form games in Python.\n",
+ "If you're running this tutorial on your local machine, you'll need to install the requirements for [gtdraw](https://www.gambit-project.org/gtdraw/), which include LaTeX, in order to run the `gtdraw` cells.\n",
+ "Another option for visualising extensive form games is to install the Gambit GUI and use it to load the EFG file generated at the end of this tutorial."
+ ]
},
{
"cell_type": "code",
@@ -12,7 +35,11 @@
"id": "5946289b",
"metadata": {},
"outputs": [],
- "source": "from gtdraw import draw\n\nimport pygambit as gbt"
+ "source": [
+ "from gtdraw import draw\n",
+ "\n",
+ "import pygambit as gbt"
+ ]
},
{
"cell_type": "markdown",
@@ -49,7 +76,9 @@
"id": "3cd94917",
"metadata": {},
"outputs": [],
- "source": "draw(g)"
+ "source": [
+ "draw(g)"
+ ]
},
{
"cell_type": "markdown",
@@ -81,7 +110,9 @@
"id": "45638fda-7e25-4c8e-b709-24b05780581b",
"metadata": {},
"outputs": [],
- "source": "draw(g)"
+ "source": [
+ "draw(g)"
+ ]
},
{
"cell_type": "markdown",
@@ -111,7 +142,9 @@
"id": "ce41e9fe-cca4-46fb-8e9d-b2c27342e5ef",
"metadata": {},
"outputs": [],
- "source": "draw(g)"
+ "source": [
+ "draw(g)"
+ ]
},
{
"cell_type": "markdown",
@@ -134,10 +167,7 @@
"source": [
"g.set_outcome(\n",
" g.root.children[\"Trust\"].children[\"Honor\"],\n",
- " outcome=g.add_outcome(\n",
- " payoffs=[1, 1],\n",
- " label=\"Trustworthy\"\n",
- " )\n",
+ " outcome=g.add_outcome(\"Trustworthy\", [1, 1])\n",
")"
]
},
@@ -147,7 +177,9 @@
"id": "b3408c55-714e-4a6f-b598-e338839442e4",
"metadata": {},
"outputs": [],
- "source": "draw(g)"
+ "source": [
+ "draw(g)"
+ ]
},
{
"cell_type": "markdown",
@@ -166,10 +198,7 @@
"source": [
"g.set_outcome(\n",
" g.root.children[\"Trust\"].children[\"Abuse\"],\n",
- " outcome=g.add_outcome(\n",
- " payoffs=[-1, 2],\n",
- " label=\"Untrustworthy\"\n",
- " )\n",
+ " outcome=g.add_outcome(\"Untrustworthy\", [-1, 2])\n",
")"
]
},
@@ -179,7 +208,9 @@
"id": "09bedb3a-aac7-46e6-ae93-c47932c746d4",
"metadata": {},
"outputs": [],
- "source": "draw(g)"
+ "source": [
+ "draw(g)"
+ ]
},
{
"cell_type": "markdown",
@@ -198,10 +229,7 @@
"source": [
"g.set_outcome(\n",
" g.root.children[\"Not trust\"],\n",
- " g.add_outcome(\n",
- " payoffs=[0, 0],\n",
- " label=\"Opt-out\"\n",
- " )\n",
+ " g.add_outcome(\"Opt-out\", [0, 0])\n",
")"
]
},
@@ -211,7 +239,9 @@
"id": "cba0e562-2989-4dae-a0f0-b121635ba032",
"metadata": {},
"outputs": [],
- "source": "draw(g)"
+ "source": [
+ "draw(g)"
+ ]
},
{
"cell_type": "markdown",
@@ -258,7 +288,10 @@
"id": "56899a29-cc53-48db-9eb4-ed2295517400",
"metadata": {},
"outputs": [],
- "source": "g = gbt.catalog.load(\"journals/ijgt/selten1975/fig2\")\ndraw(g)"
+ "source": [
+ "g = gbt.catalog.load(\"journals/ijgt/selten1975/fig2\")\n",
+ "draw(g)"
+ ]
},
{
"cell_type": "markdown",
diff --git a/doc/tutorials/03_stripped_down_poker.ipynb b/doc/tutorials/03_stripped_down_poker.ipynb
index 5dc52da3d7..7f47f183f4 100644
--- a/doc/tutorials/03_stripped_down_poker.ipynb
+++ b/doc/tutorials/03_stripped_down_poker.ipynb
@@ -4,7 +4,38 @@
"cell_type": "markdown",
"id": "98eb65d8",
"metadata": {},
- "source": "# 3) Stripped-down poker\n\nIn this tutorial, we'll create an extensive-form representation of a one-card poker game from [Reiley et al (2008)](#references), a classroom game under the name \"stripped-down poker\".\nThis is perhaps the simplest interesting game with imperfect information.\n\nWe'll use \"stripped-down poker\" to demonstrate and explain the following with Gambit:\n\n1. Setting up an extensive-form game with imperfect information using [information sets](#information-sets)\n2. [Computing and interpreting Nash equilibria](#computing-and-interpreting-nash-equilibria) and understanding mixed behaviour and mixed strategy profiles\n3. [Acceptance criteria for Nash equilibria](#acceptance-criteria-for-nash-equilibria)\n\nIn our version of the game, there are two players, **Alice** and **Bob**, and a deck of cards, with equal numbers of **King** and **Queen** cards.\n\n- The game begins with each player putting \\$1 in the pot.\n - A card is dealt at random to Alice.\n - Alice observes her card.\n - Bob does not observe the card.\n- Alice then chooses either to **Bet** or to **Fold**.\n - If she chooses to Fold, Bob wins the pot and the game ends.\n - If she chooses to Bet, she adds another \\$1 to the pot.\n- Bob then chooses either to **Call** or **Fold**.\n - If he chooses to Fold, Alice wins the pot and the game ends.\n - If he chooses to Call, he adds another $1 to the pot.\n- There is then a showdown, in which Alice reveals her card.\n - If she has a King, then she wins the pot.\n - If she has a Queen, then Bob wins the pot.\n\nIn addition to `pygambit`, this tutorial uses the `gtdraw` package, which can be used to draw extensive form games in Python.\nIf you're running this tutorial on your local machine, you'll need to install the requirements for [gtdraw](https://www.gambit-project.org/gtdraw/), which include LaTeX, in order to run the `gtdraw` cells.\nAnother option for visualising extensive form games is to install the Gambit GUI and use it to load a saved EFG file."
+ "source": [
+ "# 3) Stripped-down poker\n",
+ "\n",
+ "In this tutorial, we'll create an extensive-form representation of a one-card poker game from [Reiley et al (2008)](#references), a classroom game under the name \"stripped-down poker\".\n",
+ "This is perhaps the simplest interesting game with imperfect information.\n",
+ "\n",
+ "We'll use \"stripped-down poker\" to demonstrate and explain the following with Gambit:\n",
+ "\n",
+ "1. Setting up an extensive-form game with imperfect information using [information sets](#information-sets)\n",
+ "2. [Computing and interpreting Nash equilibria](#computing-and-interpreting-nash-equilibria) and understanding mixed behaviour and mixed strategy profiles\n",
+ "3. [Acceptance criteria for Nash equilibria](#acceptance-criteria-for-nash-equilibria)\n",
+ "\n",
+ "In our version of the game, there are two players, **Alice** and **Bob**, and a deck of cards, with equal numbers of **King** and **Queen** cards.\n",
+ "\n",
+ "- The game begins with each player putting \\$1 in the pot.\n",
+ " - A card is dealt at random to Alice.\n",
+ " - Alice observes her card.\n",
+ " - Bob does not observe the card.\n",
+ "- Alice then chooses either to **Bet** or to **Fold**.\n",
+ " - If she chooses to Fold, Bob wins the pot and the game ends.\n",
+ " - If she chooses to Bet, she adds another \\$1 to the pot.\n",
+ "- Bob then chooses either to **Call** or **Fold**.\n",
+ " - If he chooses to Fold, Alice wins the pot and the game ends.\n",
+ " - If he chooses to Call, he adds another $1 to the pot.\n",
+ "- There is then a showdown, in which Alice reveals her card.\n",
+ " - If she has a King, then she wins the pot.\n",
+ " - If she has a Queen, then Bob wins the pot.\n",
+ "\n",
+ "In addition to `pygambit`, this tutorial uses the `gtdraw` package, which can be used to draw extensive form games in Python.\n",
+ "If you're running this tutorial on your local machine, you'll need to install the requirements for [gtdraw](https://www.gambit-project.org/gtdraw/), which include LaTeX, in order to run the `gtdraw` cells.\n",
+ "Another option for visualising extensive form games is to install the Gambit GUI and use it to load a saved EFG file."
+ ]
},
{
"cell_type": "code",
@@ -12,7 +43,11 @@
"id": "69cbfe81",
"metadata": {},
"outputs": [],
- "source": "from gtdraw import draw\n\nimport pygambit as gbt"
+ "source": [
+ "from gtdraw import draw\n",
+ "\n",
+ "import pygambit as gbt"
+ ]
},
{
"cell_type": "markdown",
@@ -89,7 +124,9 @@
"id": "867cb1d8-7a5d-45d1-9349-9bbc2a4e2344",
"metadata": {},
"outputs": [],
- "source": "draw(g, color_scheme=\"gambit\")"
+ "source": [
+ "draw(g, color_scheme=\"gambit\")"
+ ]
},
{
"cell_type": "markdown",
@@ -126,7 +163,9 @@
"id": "0c522c2d-992e-48b6-a1f8-0696d33cdbe0",
"metadata": {},
"outputs": [],
- "source": "draw(g, color_scheme=\"gambit\")"
+ "source": [
+ "draw(g, color_scheme=\"gambit\")"
+ ]
},
{
"cell_type": "markdown",
@@ -166,7 +205,9 @@
"id": "e85b3346-2fea-4a73-aa72-9efb436c68c1",
"metadata": {},
"outputs": [],
- "source": "draw(g, color_scheme=\"gambit\")"
+ "source": [
+ "draw(g, color_scheme=\"gambit\")"
+ ]
},
{
"cell_type": "markdown",
@@ -188,10 +229,10 @@
"metadata": {},
"outputs": [],
"source": [
- "win_big = g.add_outcome([2, -2], label=\"Win Big\")\n",
- "win = g.add_outcome([1, -1], label=\"Win\")\n",
- "lose_big = g.add_outcome([-2, 2], label=\"Lose Big\")\n",
- "lose = g.add_outcome([-1, 1], label=\"Lose\")"
+ "win_big = g.add_outcome(\"Win Big\", [2, -2])\n",
+ "win = g.add_outcome(\"Win\", [1, -1])\n",
+ "lose_big = g.add_outcome(\"Lose Big\", [-2, 2])\n",
+ "lose = g.add_outcome(\"Lose\", [-1, 1])"
]
},
{
@@ -230,7 +271,9 @@
"id": "fdee7b53-7820-44df-9d17-d15d0b9667aa",
"metadata": {},
"outputs": [],
- "source": "draw(g, color_scheme=\"gambit\")"
+ "source": [
+ "draw(g, color_scheme=\"gambit\")"
+ ]
},
{
"cell_type": "markdown",
diff --git a/doc/tutorials/interoperability_tutorials/openspiel.ipynb b/doc/tutorials/interoperability_tutorials/openspiel.ipynb
index 21fbf02568..de36447bcc 100644
--- a/doc/tutorials/interoperability_tutorials/openspiel.ipynb
+++ b/doc/tutorials/interoperability_tutorials/openspiel.ipynb
@@ -468,7 +468,17 @@
"id": "b913fc7a",
"metadata": {},
"outputs": [],
- "source": "from gtdraw import draw\n\ndraw(\n gbt_hanabi_game,\n color_scheme=\"gambit\",\n edge_thickness=2,\n action_label_position=0.8,\n shared_terminal_depth=True\n)"
+ "source": [
+ "from gtdraw import draw\n",
+ "\n",
+ "draw(\n",
+ " gbt_hanabi_game,\n",
+ " color_scheme=\"gambit\",\n",
+ " edge_thickness=2,\n",
+ " action_label_position=0.8,\n",
+ " shared_terminal_depth=True\n",
+ ")"
+ ]
},
{
"cell_type": "markdown",
@@ -697,10 +707,10 @@
" actions=[\"Call\", \"Fold\"]\n",
")\n",
"\n",
- "win_big = gbt_one_card_poker.add_outcome([2, -2], label=\"Win Big\")\n",
- "win = gbt_one_card_poker.add_outcome([1, -1], label=\"Win\")\n",
- "lose_big = gbt_one_card_poker.add_outcome([-2, 2], label=\"Lose Big\")\n",
- "lose = gbt_one_card_poker.add_outcome([-1, 1], label=\"Lose\")\n",
+ "win_big = gbt_one_card_poker.add_outcome(\"Win Big\", [2, -2])\n",
+ "win = gbt_one_card_poker.add_outcome(\"Win\", [1, -1])\n",
+ "lose_big = gbt_one_card_poker.add_outcome(\"Lose Big\", [-2, 2])\n",
+ "lose = gbt_one_card_poker.add_outcome(\"Lose\", [-1, 1])\n",
"\n",
"# Alice folds, Bob wins small\n",
"gbt_one_card_poker.set_outcome(\n",
@@ -741,7 +751,9 @@
"id": "ed920d33-b7c6-4cc1-b055-7244a5bf42d8",
"metadata": {},
"outputs": [],
- "source": "draw(gbt_one_card_poker, color_scheme=\"gambit\")"
+ "source": [
+ "draw(gbt_one_card_poker, color_scheme=\"gambit\")"
+ ]
},
{
"cell_type": "markdown",
@@ -833,7 +845,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.13.13"
+ "version": "3.13.5"
}
},
"nbformat": 4,
diff --git a/pyproject.toml b/pyproject.toml
index 1b36d50efa..e2e4e55f26 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -102,6 +102,7 @@ markers = [
"nash_enumpure_strategy: tests of enumpure_solve in pure strategies",
"nash_enumpure_agent: tests of enumpure_solve in pure behaviors",
"nash_enummixed_strategy: tests of enummixed_solve in mixed strategies",
+ "nash_enumpoly_strategy: tests of enumpoly_solve in mixed strategies",
"nash_enumpoly_behavior: tests of enumpoly_solve in mixed behaviors",
"nash_lcp_strategy: tests of lcp_solve in mixed strategies",
"nash_lcp_behavior: tests of lcp_solve in mixed behaviors",
diff --git a/src/core/tinyxml.cc b/src/core/tinyxml.cc
deleted file mode 100644
index 2f4e58d5f1..0000000000
--- a/src/core/tinyxml.cc
+++ /dev/null
@@ -1,1559 +0,0 @@
-/*
-www.sourceforge.net/projects/tinyxml
-Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any
-damages arising from the use of this software.
-
-Permission is granted to anyone to use this software for any
-purpose, including commercial applications, and to alter it and
-redistribute it freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must
-not claim that you wrote the original software. If you use this
-software in a product, an acknowledgment in the product documentation
-would be appreciated but is not required.
-
-2. Altered source versions must be plainly marked as such, and
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-#include "tinyxml.h"
-
-#ifdef TIXML_USE_STL
-#include
-#endif
-
-bool TiXmlBase::condenseWhiteSpace = true;
-
-void TiXmlBase::PutString(const TIXML_STRING &str, TIXML_OSTREAM *stream)
-{
- TIXML_STRING buffer;
- PutString(str, &buffer);
- (*stream) << buffer;
-}
-
-void TiXmlBase::PutString(const TIXML_STRING &str, TIXML_STRING *outString)
-{
- int i = 0;
-
- while (i < (int)str.length()) {
- auto c = (unsigned char)str[i];
-
- if (c == '&' && i < ((int)str.length() - 2) && str[i + 1] == '#' && str[i + 2] == 'x') {
- // Hexadecimal character reference.
- // Pass through unchanged.
- // © -- copyright symbol, for example.
- //
- // The -1 is a bug fix from Rob Laveaux. It keeps
- // an overflow from happening if there is no ';'.
- // There are actually 2 ways to exit this loop -
- // while fails (error case) and break (semicolon found).
- // However, there is no mechanism (currently) for
- // this function to return an error.
- while (i < (int)str.length() - 1) {
- outString->append(str.c_str() + i, 1);
- ++i;
- if (str[i] == ';') {
- break;
- }
- }
- }
- else if (c == '&') {
- outString->append(entity[0].str, entity[0].strLength);
- ++i;
- }
- else if (c == '<') {
- outString->append(entity[1].str, entity[1].strLength);
- ++i;
- }
- else if (c == '>') {
- outString->append(entity[2].str, entity[2].strLength);
- ++i;
- }
- else if (c == '\"') {
- outString->append(entity[3].str, entity[3].strLength);
- ++i;
- }
- else if (c == '\'') {
- outString->append(entity[4].str, entity[4].strLength);
- ++i;
- }
- else if (c < 32) {
- // Easy pass at non-alpha/numeric/symbol
- // Below 32 is symbolic.
- char buf[32];
-
-#if defined(TIXML_SNPRINTF)
- TIXML_SNPRINTF(buf, sizeof(buf), "%02X;", (unsigned)(c & 0xff));
-#else
- sprintf(buf, "%02X;", (unsigned)(c & 0xff));
-#endif
-
- //*ME: warning C4267: convert 'size_t' to 'int'
- //*ME: Int-Cast to make compiler happy ...
- outString->append(buf, (int)strlen(buf));
- ++i;
- }
- else {
- // char realc = (char) c;
- // outString->append( &realc, 1 );
- *outString += (char)c; // somewhat more efficient function call.
- ++i;
- }
- }
-}
-
-// <-- Strange class for a bug fix. Search for STL_STRING_BUG
-TiXmlBase::StringToBuffer::StringToBuffer(const TIXML_STRING &str)
- : buffer(new char[str.length() + 1])
-{
- if (buffer) {
- strcpy(buffer, str.c_str());
- }
-}
-
-TiXmlBase::StringToBuffer::~StringToBuffer() { delete[] buffer; }
-// End strange bug fix. -->
-
-TiXmlNode::~TiXmlNode()
-{
- const TiXmlNode *node = firstChild;
- const TiXmlNode *temp = nullptr;
-
- while (node) {
- temp = node;
- node = node->next;
- delete temp;
- }
-}
-
-void TiXmlNode::CopyTo(TiXmlNode *target) const
-{
- target->SetValue(value.c_str());
- target->userData = userData;
-}
-
-void TiXmlNode::Clear()
-{
- const TiXmlNode *node = firstChild;
- const TiXmlNode *temp = nullptr;
-
- while (node) {
- temp = node;
- node = node->next;
- delete temp;
- }
-
- firstChild = nullptr;
- lastChild = nullptr;
-}
-
-TiXmlNode *TiXmlNode::LinkEndChild(TiXmlNode *node)
-{
- node->parent = this;
-
- node->prev = lastChild;
- node->next = nullptr;
-
- if (lastChild) {
- lastChild->next = node;
- }
- else {
- firstChild = node; // it was an empty list.
- }
-
- lastChild = node;
- return node;
-}
-
-TiXmlNode *TiXmlNode::InsertEndChild(const TiXmlNode &addThis)
-{
- TiXmlNode *node = addThis.Clone();
- if (!node) {
- return nullptr;
- }
-
- return LinkEndChild(node);
-}
-
-TiXmlNode *TiXmlNode::InsertBeforeChild(TiXmlNode *beforeThis, const TiXmlNode &addThis)
-{
- if (!beforeThis || beforeThis->parent != this) {
- return nullptr;
- }
-
- TiXmlNode *node = addThis.Clone();
- if (!node) {
- return nullptr;
- }
- node->parent = this;
-
- node->next = beforeThis;
- node->prev = beforeThis->prev;
- if (beforeThis->prev) {
- beforeThis->prev->next = node;
- }
- else {
- assert(firstChild == beforeThis);
- firstChild = node;
- }
- beforeThis->prev = node;
- return node;
-}
-
-TiXmlNode *TiXmlNode::InsertAfterChild(TiXmlNode *afterThis, const TiXmlNode &addThis)
-{
- if (!afterThis || afterThis->parent != this) {
- return nullptr;
- }
-
- TiXmlNode *node = addThis.Clone();
- if (!node) {
- return nullptr;
- }
- node->parent = this;
-
- node->prev = afterThis;
- node->next = afterThis->next;
- if (afterThis->next) {
- afterThis->next->prev = node;
- }
- else {
- assert(lastChild == afterThis);
- lastChild = node;
- }
- afterThis->next = node;
- return node;
-}
-
-TiXmlNode *TiXmlNode::ReplaceChild(TiXmlNode *replaceThis, const TiXmlNode &withThis)
-{
- if (replaceThis->parent != this) {
- return nullptr;
- }
-
- TiXmlNode *node = withThis.Clone();
- if (!node) {
- return nullptr;
- }
-
- node->next = replaceThis->next;
- node->prev = replaceThis->prev;
-
- if (replaceThis->next) {
- replaceThis->next->prev = node;
- }
- else {
- lastChild = node;
- }
-
- if (replaceThis->prev) {
- replaceThis->prev->next = node;
- }
- else {
- firstChild = node;
- }
-
- delete replaceThis;
- node->parent = this;
- return node;
-}
-
-bool TiXmlNode::RemoveChild(TiXmlNode *removeThis)
-{
- if (removeThis->parent != this) {
- assert(0);
- return false;
- }
-
- if (removeThis->next) {
- removeThis->next->prev = removeThis->prev;
- }
- else {
- lastChild = removeThis->prev;
- }
-
- if (removeThis->prev) {
- removeThis->prev->next = removeThis->next;
- }
- else {
- firstChild = removeThis->next;
- }
-
- delete removeThis;
- return true;
-}
-
-const TiXmlNode *TiXmlNode::FirstChild(const char *_value) const
-{
- const TiXmlNode *node;
- for (node = firstChild; node; node = node->next) {
- if (strcmp(node->Value(), _value) == 0) {
- return node;
- }
- }
- return nullptr;
-}
-
-TiXmlNode *TiXmlNode::FirstChild(const char *_value)
-{
- TiXmlNode *node;
- for (node = firstChild; node; node = node->next) {
- if (strcmp(node->Value(), _value) == 0) {
- return node;
- }
- }
- return nullptr;
-}
-
-const TiXmlNode *TiXmlNode::LastChild(const char *_value) const
-{
- const TiXmlNode *node;
- for (node = lastChild; node; node = node->prev) {
- if (strcmp(node->Value(), _value) == 0) {
- return node;
- }
- }
- return nullptr;
-}
-
-TiXmlNode *TiXmlNode::LastChild(const char *_value)
-{
- TiXmlNode *node;
- for (node = lastChild; node; node = node->prev) {
- if (strcmp(node->Value(), _value) == 0) {
- return node;
- }
- }
- return nullptr;
-}
-
-const TiXmlNode *TiXmlNode::IterateChildren(const TiXmlNode *previous) const
-{
- if (!previous) {
- return FirstChild();
- }
- else {
- assert(previous->parent == this);
- return previous->NextSibling();
- }
-}
-
-TiXmlNode *TiXmlNode::IterateChildren(TiXmlNode *previous)
-{
- if (!previous) {
- return FirstChild();
- }
- else {
- assert(previous->parent == this);
- return previous->NextSibling();
- }
-}
-
-const TiXmlNode *TiXmlNode::IterateChildren(const char *val, const TiXmlNode *previous) const
-{
- if (!previous) {
- return FirstChild(val);
- }
- else {
- assert(previous->parent == this);
- return previous->NextSibling(val);
- }
-}
-
-TiXmlNode *TiXmlNode::IterateChildren(const char *val, TiXmlNode *previous)
-{
- if (!previous) {
- return FirstChild(val);
- }
- else {
- assert(previous->parent == this);
- return previous->NextSibling(val);
- }
-}
-
-const TiXmlNode *TiXmlNode::NextSibling(const char *_value) const
-{
- const TiXmlNode *node;
- for (node = next; node; node = node->next) {
- if (strcmp(node->Value(), _value) == 0) {
- return node;
- }
- }
- return nullptr;
-}
-
-TiXmlNode *TiXmlNode::NextSibling(const char *_value)
-{
- TiXmlNode *node;
- for (node = next; node; node = node->next) {
- if (strcmp(node->Value(), _value) == 0) {
- return node;
- }
- }
- return nullptr;
-}
-
-const TiXmlNode *TiXmlNode::PreviousSibling(const char *_value) const
-{
- const TiXmlNode *node;
- for (node = prev; node; node = node->prev) {
- if (strcmp(node->Value(), _value) == 0) {
- return node;
- }
- }
- return nullptr;
-}
-
-TiXmlNode *TiXmlNode::PreviousSibling(const char *_value)
-{
- TiXmlNode *node;
- for (node = prev; node; node = node->prev) {
- if (strcmp(node->Value(), _value) == 0) {
- return node;
- }
- }
- return nullptr;
-}
-
-void TiXmlElement::RemoveAttribute(const char *name)
-{
- TiXmlAttribute *node = attributeSet.Find(name);
- if (node) {
- attributeSet.Remove(node);
- delete node;
- }
-}
-
-const TiXmlElement *TiXmlNode::FirstChildElement() const
-{
- const TiXmlNode *node;
-
- for (node = FirstChild(); node; node = node->NextSibling()) {
- if (node->ToElement()) {
- return node->ToElement();
- }
- }
- return nullptr;
-}
-
-TiXmlElement *TiXmlNode::FirstChildElement()
-{
- TiXmlNode *node;
-
- for (node = FirstChild(); node; node = node->NextSibling()) {
- if (node->ToElement()) {
- return node->ToElement();
- }
- }
- return nullptr;
-}
-
-const TiXmlElement *TiXmlNode::FirstChildElement(const char *_value) const
-{
- const TiXmlNode *node;
-
- for (node = FirstChild(_value); node; node = node->NextSibling(_value)) {
- if (node->ToElement()) {
- return node->ToElement();
- }
- }
- return nullptr;
-}
-
-TiXmlElement *TiXmlNode::FirstChildElement(const char *_value)
-{
- TiXmlNode *node;
-
- for (node = FirstChild(_value); node; node = node->NextSibling(_value)) {
- if (node->ToElement()) {
- return node->ToElement();
- }
- }
- return nullptr;
-}
-
-const TiXmlElement *TiXmlNode::NextSiblingElement() const
-{
- const TiXmlNode *node;
-
- for (node = NextSibling(); node; node = node->NextSibling()) {
- if (node->ToElement()) {
- return node->ToElement();
- }
- }
- return nullptr;
-}
-
-TiXmlElement *TiXmlNode::NextSiblingElement()
-{
- TiXmlNode *node;
-
- for (node = NextSibling(); node; node = node->NextSibling()) {
- if (node->ToElement()) {
- return node->ToElement();
- }
- }
- return nullptr;
-}
-
-const TiXmlElement *TiXmlNode::NextSiblingElement(const char *_value) const
-{
- const TiXmlNode *node;
-
- for (node = NextSibling(_value); node; node = node->NextSibling(_value)) {
- if (node->ToElement()) {
- return node->ToElement();
- }
- }
- return nullptr;
-}
-
-TiXmlElement *TiXmlNode::NextSiblingElement(const char *_value)
-{
- TiXmlNode *node;
-
- for (node = NextSibling(_value); node; node = node->NextSibling(_value)) {
- if (node->ToElement()) {
- return node->ToElement();
- }
- }
- return nullptr;
-}
-
-const TiXmlDocument *TiXmlNode::GetDocument() const
-{
- const TiXmlNode *node;
-
- for (node = this; node; node = node->parent) {
- if (node->ToDocument()) {
- return node->ToDocument();
- }
- }
- return nullptr;
-}
-
-TiXmlDocument *TiXmlNode::GetDocument()
-{
- TiXmlNode *node;
-
- for (node = this; node; node = node->parent) {
- if (node->ToDocument()) {
- return node->ToDocument();
- }
- }
- return nullptr;
-}
-
-TiXmlElement::TiXmlElement(const char *_value) : TiXmlNode(TiXmlNode::ELEMENT)
-{
- firstChild = lastChild = nullptr;
- value = _value;
-}
-
-#ifdef TIXML_USE_STL
-TiXmlElement::TiXmlElement(const std::string &_value) : TiXmlNode(TiXmlNode::ELEMENT)
-{
- firstChild = lastChild = nullptr;
- value = _value;
-}
-#endif
-
-TiXmlElement::TiXmlElement(const TiXmlElement ©) : TiXmlNode(TiXmlNode::ELEMENT)
-{
- firstChild = lastChild = nullptr;
- copy.CopyTo(this);
-}
-
-void TiXmlElement::operator=(const TiXmlElement &base)
-{
- ClearThis();
- base.CopyTo(this);
-}
-
-TiXmlElement::~TiXmlElement() { ClearThis(); }
-
-void TiXmlElement::ClearThis()
-{
- Clear();
- while (attributeSet.First()) {
- TiXmlAttribute *node = attributeSet.First();
- attributeSet.Remove(node);
- delete node;
- }
-}
-
-const char *TiXmlElement::Attribute(const char *name) const
-{
- const TiXmlAttribute *node = attributeSet.Find(name);
-
- if (node) {
- return node->Value();
- }
-
- return nullptr;
-}
-
-const char *TiXmlElement::Attribute(const char *name, int *i) const
-{
- const char *s = Attribute(name);
- if (i) {
- if (s) {
- *i = atoi(s);
- }
- else {
- *i = 0;
- }
- }
- return s;
-}
-
-const char *TiXmlElement::Attribute(const char *name, double *d) const
-{
- const char *s = Attribute(name);
- if (d) {
- if (s) {
- *d = atof(s);
- }
- else {
- *d = 0;
- }
- }
- return s;
-}
-
-int TiXmlElement::QueryIntAttribute(const char *name, int *ival) const
-{
- const TiXmlAttribute *node = attributeSet.Find(name);
- if (!node) {
- return TIXML_NO_ATTRIBUTE;
- }
-
- return node->QueryIntValue(ival);
-}
-
-int TiXmlElement::QueryDoubleAttribute(const char *name, double *dval) const
-{
- const TiXmlAttribute *node = attributeSet.Find(name);
- if (!node) {
- return TIXML_NO_ATTRIBUTE;
- }
-
- return node->QueryDoubleValue(dval);
-}
-
-void TiXmlElement::SetAttribute(const char *name, int val)
-{
- char buf[64];
-#if defined(TIXML_SNPRINTF)
- TIXML_SNPRINTF(buf, sizeof(buf), "%d", val);
-#else
- sprintf(buf, "%d", val);
-#endif
- SetAttribute(name, buf);
-}
-
-void TiXmlElement::SetDoubleAttribute(const char *name, double val)
-{
- char buf[256];
-#if defined(TIXML_SNPRINTF)
- TIXML_SNPRINTF(buf, sizeof(buf), "%f", val);
-#else
- sprintf(buf, "%f", val);
-#endif
- SetAttribute(name, buf);
-}
-
-void TiXmlElement::SetAttribute(const char *name, const char *_value)
-{
- TiXmlAttribute *node = attributeSet.Find(name);
- if (node) {
- node->SetValue(_value);
- return;
- }
-
- auto *attrib = new TiXmlAttribute(name, _value);
- if (attrib) {
- attributeSet.Add(attrib);
- }
- else {
- TiXmlDocument *document = GetDocument();
- if (document) {
- document->SetError(TIXML_ERROR_OUT_OF_MEMORY, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- }
- }
-}
-
-void TiXmlElement::Print(FILE *cfile, int depth) const
-{
- int i;
- for (i = 0; i < depth; i++) {
- fprintf(cfile, " ");
- }
-
- fprintf(cfile, "<%s", value.c_str());
-
- const TiXmlAttribute *attrib;
- for (attrib = attributeSet.First(); attrib; attrib = attrib->Next()) {
- fprintf(cfile, " ");
- attrib->Print(cfile, depth);
- }
-
- // There are 3 different formatting approaches:
- // 1) An element without children is printed as a node
- // 2) An element with only a text child is printed as text
- // 3) An element with children is printed on multiple lines.
- TiXmlNode *node;
- if (!firstChild) {
- fprintf(cfile, " />");
- }
- else if (firstChild == lastChild && firstChild->ToText()) {
- fprintf(cfile, ">");
- firstChild->Print(cfile, depth + 1);
- fprintf(cfile, "%s>", value.c_str());
- }
- else {
- fprintf(cfile, ">");
-
- for (node = firstChild; node; node = node->NextSibling()) {
- if (!node->ToText()) {
- fprintf(cfile, "\n");
- }
- node->Print(cfile, depth + 1);
- }
- fprintf(cfile, "\n");
- for (i = 0; i < depth; ++i) {
- fprintf(cfile, " ");
- }
- fprintf(cfile, "%s>", value.c_str());
- }
-}
-
-void TiXmlElement::StreamOut(TIXML_OSTREAM *stream) const
-{
- (*stream) << "<" << value;
-
- const TiXmlAttribute *attrib;
- for (attrib = attributeSet.First(); attrib; attrib = attrib->Next()) {
- (*stream) << " ";
- attrib->StreamOut(stream);
- }
-
- // If this node has children, give it a closing tag. Else
- // make it an empty tag.
- TiXmlNode *node;
- if (firstChild) {
- (*stream) << ">";
-
- for (node = firstChild; node; node = node->NextSibling()) {
- node->StreamOut(stream);
- }
- (*stream) << "" << value << ">";
- }
- else {
- (*stream) << " />";
- }
-}
-
-void TiXmlElement::CopyTo(TiXmlElement *target) const
-{
- // superclass:
- TiXmlNode::CopyTo(target);
-
- // Element class:
- // Clone the attributes, then clone the children.
- const TiXmlAttribute *attribute = nullptr;
- for (attribute = attributeSet.First(); attribute; attribute = attribute->Next()) {
- target->SetAttribute(attribute->Name(), attribute->Value());
- }
-
- TiXmlNode *node = nullptr;
- for (node = firstChild; node; node = node->NextSibling()) {
- target->LinkEndChild(node->Clone());
- }
-}
-
-TiXmlNode *TiXmlElement::Clone() const
-{
- auto *clone = new TiXmlElement(Value());
- if (!clone) {
- return nullptr;
- }
-
- CopyTo(clone);
- return clone;
-}
-
-const char *TiXmlElement::GetText() const
-{
- const TiXmlNode *child = this->FirstChild();
- if (child) {
- const TiXmlText *childText = child->ToText();
- if (childText) {
- return childText->Value();
- }
- }
- return nullptr;
-}
-
-TiXmlDocument::TiXmlDocument() : TiXmlNode(TiXmlNode::DOCUMENT) { ClearError(); }
-
-TiXmlDocument::TiXmlDocument(const char *documentName) : TiXmlNode(TiXmlNode::DOCUMENT)
-{
- value = documentName;
- ClearError();
-}
-
-#ifdef TIXML_USE_STL
-TiXmlDocument::TiXmlDocument(const std::string &documentName) : TiXmlNode(TiXmlNode::DOCUMENT)
-{
- value = documentName;
- ClearError();
-}
-#endif
-
-TiXmlDocument::TiXmlDocument(const TiXmlDocument ©) : TiXmlNode(TiXmlNode::DOCUMENT)
-{
- copy.CopyTo(this);
-}
-
-void TiXmlDocument::operator=(const TiXmlDocument ©)
-{
- Clear();
- copy.CopyTo(this);
-}
-
-bool TiXmlDocument::LoadFile(TiXmlEncoding encoding)
-{
- // See STL_STRING_BUG below.
- const StringToBuffer buf(value);
-
- if (buf.buffer && LoadFile(buf.buffer, encoding)) {
- return true;
- }
-
- return false;
-}
-
-bool TiXmlDocument::SaveFile() const
-{
- // See STL_STRING_BUG below.
- const StringToBuffer buf(value);
- return (buf.buffer && SaveFile(buf.buffer));
-}
-
-bool TiXmlDocument::LoadFile(const char *filename, TiXmlEncoding encoding)
-{
- // Delete the existing data:
- Clear();
- location.Clear();
-
- // There was a really terrifying little bug here. The code:
- // value = filename
- // in the STL case, cause the assignment method of the std::string to
- // be called. What is strange, is that the std::string had the same
- // address as it's c_str() method, and so bad things happen. Looks
- // like a bug in the Microsoft STL implementation.
- // See STL_STRING_BUG above.
- // Fixed with the StringToBuffer class.
- value = filename;
-
- // reading in binary mode so that tinyxml can normalize the EOL
- FILE *file = fopen(value.c_str(), "rb");
-
- if (file) {
- // Get the file size, so we can pre-allocate the string. HUGE speed impact.
- long length = 0;
- fseek(file, 0, SEEK_END);
- length = ftell(file);
- fseek(file, 0, SEEK_SET);
-
- // Strange case, but good to handle up front.
- if (length == 0) {
- fclose(file);
- return false;
- }
-
- // If we have a file, assume it is all one big XML file, and read it in.
- // The document parser may decide the document ends sooner than the entire file, however.
- TIXML_STRING data;
- data.reserve(length);
-
- // Subtle bug here. TinyXml did use fgets. But from the XML spec:
- // 2.11 End-of-Line Handling
- //
- //
- // ...the XML processor MUST behave as if it normalized all line breaks in external
- // parsed entities (including the document entity) on input, before parsing, by translating
- // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
- // a single #xA character.
- //
- //
- // It is not clear fgets does that, and certainly isn't clear it works cross platform.
- // Generally, you expect fgets to translate from the convention of the OS to the c/unix
- // convention, and not work generally.
-
- /*
- while( fgets( buf, sizeof(buf), file ) )
- {
- data += buf;
- }
- */
-
- char *buf = new char[length + 1];
- buf[0] = 0;
-
- if (fread(buf, length, 1, file) != 1) {
- // if ( fread( buf, 1, length, file ) != (size_t)length ) {
- SetError(TIXML_ERROR_OPENING_FILE, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- fclose(file);
- return false;
- }
- fclose(file);
-
- const char *lastPos = buf;
- const char *p = buf;
-
- buf[length] = 0;
- while (*p) {
- assert(p < (buf + length));
- if (*p == 0xa) {
- // Newline character. No special rules for this. Append all the characters
- // since the last string, and include the newline.
- data.append(lastPos, p - lastPos + 1); // append, include the newline
- ++p; // move past the newline
- lastPos = p; // and point to the new buffer (may be 0)
- assert(p <= (buf + length));
- }
- else if (*p == 0xd) {
- // Carriage return. Append what we have so far, then
- // handle moving forward in the buffer.
- if ((p - lastPos) > 0) {
- data.append(lastPos, p - lastPos); // do not add the CR
- }
- data += (char)0xa; // a proper newline
-
- if (*(p + 1) == 0xa) {
- // Carriage return - new line sequence
- p += 2;
- lastPos = p;
- assert(p <= (buf + length));
- }
- else {
- // it was followed by something else...that is presumably characters again.
- ++p;
- lastPos = p;
- assert(p <= (buf + length));
- }
- }
- else {
- ++p;
- }
- }
- // Handle any left over characters.
- if (p - lastPos) {
- data.append(lastPos, p - lastPos);
- }
- delete[] buf;
- buf = nullptr;
-
- Parse(data.c_str(), nullptr, encoding);
-
- if (Error()) {
- return false;
- }
- else {
- return true;
- }
- }
- SetError(TIXML_ERROR_OPENING_FILE, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- return false;
-}
-
-bool TiXmlDocument::SaveFile(const char *filename) const
-{
- // The old c stuff lives on...
- FILE *fp = fopen(filename, "w");
- if (fp) {
- if (useMicrosoftBOM) {
- const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
- const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
- const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
-
- fputc(TIXML_UTF_LEAD_0, fp);
- fputc(TIXML_UTF_LEAD_1, fp);
- fputc(TIXML_UTF_LEAD_2, fp);
- }
- Print(fp, 0);
- fclose(fp);
- return true;
- }
- return false;
-}
-
-void TiXmlDocument::CopyTo(TiXmlDocument *target) const
-{
- TiXmlNode::CopyTo(target);
-
- target->error = error;
- target->errorDesc = errorDesc.c_str();
-
- TiXmlNode *node = nullptr;
- for (node = firstChild; node; node = node->NextSibling()) {
- target->LinkEndChild(node->Clone());
- }
-}
-
-TiXmlNode *TiXmlDocument::Clone() const
-{
- auto *clone = new TiXmlDocument();
- if (!clone) {
- return nullptr;
- }
-
- CopyTo(clone);
- return clone;
-}
-
-void TiXmlDocument::Print(FILE *cfile, int depth) const
-{
- const TiXmlNode *node;
- for (node = FirstChild(); node; node = node->NextSibling()) {
- node->Print(cfile, depth);
- fprintf(cfile, "\n");
- }
-}
-
-void TiXmlDocument::StreamOut(TIXML_OSTREAM *out) const
-{
- const TiXmlNode *node;
- for (node = FirstChild(); node; node = node->NextSibling()) {
- node->StreamOut(out);
-
- // Special rule for streams: stop after the root element.
- // The stream in code will only read one element, so don't
- // write more than one.
- if (node->ToElement()) {
- break;
- }
- }
-}
-
-const TiXmlAttribute *TiXmlAttribute::Next() const
-{
- // We are using knowledge of the sentinel. The sentinel
- // have a value or name.
- if (next->value.empty() && next->name.empty()) {
- return nullptr;
- }
- return next;
-}
-
-TiXmlAttribute *TiXmlAttribute::Next()
-{
- // We are using knowledge of the sentinel. The sentinel
- // have a value or name.
- if (next->value.empty() && next->name.empty()) {
- return nullptr;
- }
- return next;
-}
-
-const TiXmlAttribute *TiXmlAttribute::Previous() const
-{
- // We are using knowledge of the sentinel. The sentinel
- // have a value or name.
- if (prev->value.empty() && prev->name.empty()) {
- return nullptr;
- }
- return prev;
-}
-
-TiXmlAttribute *TiXmlAttribute::Previous()
-{
- // We are using knowledge of the sentinel. The sentinel
- // have a value or name.
- if (prev->value.empty() && prev->name.empty()) {
- return nullptr;
- }
- return prev;
-}
-
-void TiXmlAttribute::Print(FILE *cfile, int /*depth*/) const
-{
- TIXML_STRING n, v;
-
- PutString(name, &n);
- PutString(value, &v);
-
- if (value.find('\"') == TIXML_STRING::npos) {
- fprintf(cfile, "%s=\"%s\"", n.c_str(), v.c_str());
- }
- else {
- fprintf(cfile, "%s='%s'", n.c_str(), v.c_str());
- }
-}
-
-void TiXmlAttribute::StreamOut(TIXML_OSTREAM *stream) const
-{
- if (value.find('\"') != TIXML_STRING::npos) {
- PutString(name, stream);
- (*stream) << "="
- << "'";
- PutString(value, stream);
- (*stream) << "'";
- }
- else {
- PutString(name, stream);
- (*stream) << "="
- << "\"";
- PutString(value, stream);
- (*stream) << "\"";
- }
-}
-
-int TiXmlAttribute::QueryIntValue(int *ival) const
-{
- if (sscanf(value.c_str(), "%d", ival) == 1) {
- return TIXML_SUCCESS;
- }
- return TIXML_WRONG_TYPE;
-}
-
-int TiXmlAttribute::QueryDoubleValue(double *dval) const
-{
- if (sscanf(value.c_str(), "%lf", dval) == 1) {
- return TIXML_SUCCESS;
- }
- return TIXML_WRONG_TYPE;
-}
-
-void TiXmlAttribute::SetIntValue(int _value)
-{
- char buf[64];
-#if defined(TIXML_SNPRINTF)
- TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
-#else
- sprintf(buf, "%d", _value);
-#endif
- SetValue(buf);
-}
-
-void TiXmlAttribute::SetDoubleValue(double _value)
-{
- char buf[256];
-#if defined(TIXML_SNPRINTF)
- TIXML_SNPRINTF(buf, sizeof(buf), "%lf", _value);
-#else
- sprintf(buf, "%lf", _value);
-#endif
- SetValue(buf);
-}
-
-int TiXmlAttribute::IntValue() const { return atoi(value.c_str()); }
-
-double TiXmlAttribute::DoubleValue() const { return atof(value.c_str()); }
-
-TiXmlComment::TiXmlComment(const TiXmlComment ©) : TiXmlNode(TiXmlNode::COMMENT)
-{
- copy.CopyTo(this);
-}
-
-void TiXmlComment::operator=(const TiXmlComment &base)
-{
- Clear();
- base.CopyTo(this);
-}
-
-void TiXmlComment::Print(FILE *cfile, int depth) const
-{
- for (int i = 0; i < depth; i++) {
- fputs(" ", cfile);
- }
- fprintf(cfile, "", value.c_str());
-}
-
-void TiXmlComment::StreamOut(TIXML_OSTREAM *stream) const
-{
- (*stream) << "";
-}
-
-void TiXmlComment::CopyTo(TiXmlComment *target) const { TiXmlNode::CopyTo(target); }
-
-TiXmlNode *TiXmlComment::Clone() const
-{
- auto *clone = new TiXmlComment();
-
- if (!clone) {
- return nullptr;
- }
-
- CopyTo(clone);
- return clone;
-}
-
-void TiXmlText::Print(FILE *cfile, int depth) const
-{
- if (cdata) {
- int i;
- fprintf(cfile, "\n");
- for (i = 0; i < depth; i++) {
- fprintf(cfile, " ");
- }
- fprintf(cfile, "\n");
- }
- else {
- TIXML_STRING buffer;
- PutString(value, &buffer);
- fprintf(cfile, "%s", buffer.c_str());
- }
-}
-
-void TiXmlText::StreamOut(TIXML_OSTREAM *stream) const
-{
- if (cdata) {
- (*stream) << "";
- }
- else {
- PutString(value, stream);
- }
-}
-
-void TiXmlText::CopyTo(TiXmlText *target) const
-{
- TiXmlNode::CopyTo(target);
- target->cdata = cdata;
-}
-
-TiXmlNode *TiXmlText::Clone() const
-{
- TiXmlText *clone = nullptr;
- clone = new TiXmlText("");
-
- if (!clone) {
- return nullptr;
- }
-
- CopyTo(clone);
- return clone;
-}
-
-TiXmlDeclaration::TiXmlDeclaration(const char *_version, const char *_encoding,
- const char *_standalone)
- : TiXmlNode(TiXmlNode::DECLARATION), version(_version), encoding(_encoding),
- standalone(_standalone)
-{
-}
-
-#ifdef TIXML_USE_STL
-TiXmlDeclaration::TiXmlDeclaration(const std::string &_version, const std::string &_encoding,
- const std::string &_standalone)
- : TiXmlNode(TiXmlNode::DECLARATION), version(_version), encoding(_encoding),
- standalone(_standalone)
-{
-}
-#endif
-
-TiXmlDeclaration::TiXmlDeclaration(const TiXmlDeclaration ©)
- : TiXmlNode(TiXmlNode::DECLARATION)
-{
- copy.CopyTo(this);
-}
-
-void TiXmlDeclaration::operator=(const TiXmlDeclaration ©)
-{
- Clear();
- copy.CopyTo(this);
-}
-
-void TiXmlDeclaration::Print(FILE *cfile, int /*depth*/) const
-{
- fprintf(cfile, "");
-}
-
-void TiXmlDeclaration::StreamOut(TIXML_OSTREAM *stream) const
-{
- (*stream) << "";
-}
-
-void TiXmlDeclaration::CopyTo(TiXmlDeclaration *target) const
-{
- TiXmlNode::CopyTo(target);
-
- target->version = version;
- target->encoding = encoding;
- target->standalone = standalone;
-}
-
-TiXmlNode *TiXmlDeclaration::Clone() const
-{
- auto *clone = new TiXmlDeclaration();
-
- if (!clone) {
- return nullptr;
- }
-
- CopyTo(clone);
- return clone;
-}
-
-void TiXmlUnknown::Print(FILE *cfile, int depth) const
-{
- for (int i = 0; i < depth; i++) {
- fprintf(cfile, " ");
- }
- fprintf(cfile, "<%s>", value.c_str());
-}
-
-void TiXmlUnknown::StreamOut(TIXML_OSTREAM *stream) const
-{
- (*stream) << "<" << value << ">"; // Don't use entities here! It is unknown.
-}
-
-void TiXmlUnknown::CopyTo(TiXmlUnknown *target) const { TiXmlNode::CopyTo(target); }
-
-TiXmlNode *TiXmlUnknown::Clone() const
-{
- auto *clone = new TiXmlUnknown();
-
- if (!clone) {
- return nullptr;
- }
-
- CopyTo(clone);
- return clone;
-}
-
-TiXmlAttributeSet::TiXmlAttributeSet()
-{
- sentinel.next = &sentinel;
- sentinel.prev = &sentinel;
-}
-
-TiXmlAttributeSet::~TiXmlAttributeSet()
-{
- assert(sentinel.next == &sentinel);
- assert(sentinel.prev == &sentinel);
-}
-
-void TiXmlAttributeSet::Add(TiXmlAttribute *addMe)
-{
- assert(!Find(addMe->Name())); // Shouldn't be multiply adding to the set.
-
- addMe->next = &sentinel;
- addMe->prev = sentinel.prev;
-
- sentinel.prev->next = addMe;
- sentinel.prev = addMe;
-}
-
-void TiXmlAttributeSet::Remove(TiXmlAttribute *removeMe)
-{
- TiXmlAttribute *node;
-
- for (node = sentinel.next; node != &sentinel; node = node->next) {
- if (node == removeMe) {
- node->prev->next = node->next;
- node->next->prev = node->prev;
- node->next = nullptr;
- node->prev = nullptr;
- return;
- }
- }
- assert(0); // we tried to remove a non-linked attribute.
-}
-
-const TiXmlAttribute *TiXmlAttributeSet::Find(const char *name) const
-{
- const TiXmlAttribute *node;
-
- for (node = sentinel.next; node != &sentinel; node = node->next) {
- if (node->name == name) {
- return node;
- }
- }
- return nullptr;
-}
-
-TiXmlAttribute *TiXmlAttributeSet::Find(const char *name)
-{
- TiXmlAttribute *node;
-
- for (node = sentinel.next; node != &sentinel; node = node->next) {
- if (node->name == name) {
- return node;
- }
- }
- return nullptr;
-}
-
-#ifdef TIXML_USE_STL
-TIXML_ISTREAM &operator>>(TIXML_ISTREAM &in, TiXmlNode &base)
-{
- TIXML_STRING tag;
- tag.reserve(8 * 1000);
- base.StreamIn(&in, &tag);
-
- base.Parse(tag.c_str(), nullptr, TIXML_DEFAULT_ENCODING);
- return in;
-}
-#endif
-
-TIXML_OSTREAM &operator<<(TIXML_OSTREAM &out, const TiXmlNode &base)
-{
- base.StreamOut(&out);
- return out;
-}
-
-#ifdef TIXML_USE_STL
-std::string &operator<<(std::string &out, const TiXmlNode &base)
-{
- std::ostringstream os_stream(std::ostringstream::out);
- base.StreamOut(&os_stream);
-
- out.append(os_stream.str());
- return out;
-}
-#endif
-
-TiXmlHandle TiXmlHandle::FirstChild() const
-{
- if (node) {
- TiXmlNode *child = node->FirstChild();
- if (child) {
- return {child};
- }
- }
- return {nullptr};
-}
-
-TiXmlHandle TiXmlHandle::FirstChild(const char *value) const
-{
- if (node) {
- TiXmlNode *child = node->FirstChild(value);
- if (child) {
- return {child};
- }
- }
- return {nullptr};
-}
-
-TiXmlHandle TiXmlHandle::FirstChildElement() const
-{
- if (node) {
- TiXmlElement *child = node->FirstChildElement();
- if (child) {
- return {child};
- }
- }
- return {nullptr};
-}
-
-TiXmlHandle TiXmlHandle::FirstChildElement(const char *value) const
-{
- if (node) {
- TiXmlElement *child = node->FirstChildElement(value);
- if (child) {
- return {child};
- }
- }
- return {nullptr};
-}
-
-TiXmlHandle TiXmlHandle::Child(int count) const
-{
- if (node) {
- int i;
- TiXmlNode *child = node->FirstChild();
- for (i = 0; child && i < count; child = child->NextSibling(), ++i) {
- // nothing
- }
- if (child) {
- return {child};
- }
- }
- return {nullptr};
-}
-
-TiXmlHandle TiXmlHandle::Child(const char *value, int count) const
-{
- if (node) {
- int i;
- TiXmlNode *child = node->FirstChild(value);
- for (i = 0; child && i < count; child = child->NextSibling(value), ++i) {
- // nothing
- }
- if (child) {
- return {child};
- }
- }
- return {nullptr};
-}
-
-TiXmlHandle TiXmlHandle::ChildElement(int count) const
-{
- if (node) {
- int i;
- TiXmlElement *child = node->FirstChildElement();
- for (i = 0; child && i < count; child = child->NextSiblingElement(), ++i) {
- // nothing
- }
- if (child) {
- return {child};
- }
- }
- return {nullptr};
-}
-
-TiXmlHandle TiXmlHandle::ChildElement(const char *value, int count) const
-{
- if (node) {
- int i;
- TiXmlElement *child = node->FirstChildElement(value);
- for (i = 0; child && i < count; child = child->NextSiblingElement(value), ++i) {
- // nothing
- }
- if (child) {
- return {child};
- }
- }
- return {nullptr};
-}
diff --git a/src/core/tinyxml.h b/src/core/tinyxml.h
deleted file mode 100644
index 209cf7c63b..0000000000
--- a/src/core/tinyxml.h
+++ /dev/null
@@ -1,1602 +0,0 @@
-/*
-www.sourceforge.net/projects/tinyxml
-Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any
-damages arising from the use of this software.
-
-Permission is granted to anyone to use this software for any
-purpose, including commercial applications, and to alter it and
-redistribute it freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must
-not claim that you wrote the original software. If you use this
-software in a product, an acknowledgment in the product documentation
-would be appreciated but is not required.
-
-2. Altered source versions must be plainly marked as such, and
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-#ifndef TINYXML_INCLUDED
-#define TINYXML_INCLUDED
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4530)
-#pragma warning(disable : 4786)
-#endif
-
-#include
-#include
-#include
-#include
-#include
-
-// Help out windows:
-#if defined(_DEBUG) && !defined(DEBUG)
-#define DEBUG
-#endif
-
-#if defined(DEBUG) && defined(_MSC_VER)
-#include
-#define TIXML_LOG OutputDebugString
-#else
-#define TIXML_LOG printf
-#endif
-
-// Gambit change: we use STL, so we define this here.
-#define TIXML_USE_STL 1
-
-#ifdef TIXML_USE_STL
-#include
-#include
-#define TIXML_STRING std::string
-#define TIXML_ISTREAM std::istream
-#define TIXML_OSTREAM std::ostream
-#else
-#include "tinystr.h"
-#define TIXML_STRING TiXmlString
-#define TIXML_OSTREAM TiXmlOutStream
-#endif
-
-// Deprecated library function hell. Compilers want to use the
-// new safe versions. This probably doesn't fully address the problem,
-// but it gets closer. There are too many compilers for me to fully
-// test. If you get compilation troubles, undefine TIXML_SAFE
-
-#define TIXML_SAFE // TinyXml isn't fully buffer overrun protected, safe code. This is work in
- // progress.
-#ifdef TIXML_SAFE
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-// Microsoft visual studio, version 6 and higher.
-// #pragma message( "Using _sn* functions." )
-#define TIXML_SNPRINTF _snprintf
-#define TIXML_SNSCANF _snscanf
-#elif defined(__GNUC__) && (__GNUC__ >= 3)
-// GCC version 3 and higher.s
-// #warning( "Using sn* functions." )
-#define TIXML_SNPRINTF snprintf
-#define TIXML_SNSCANF snscanf
-#endif
-#endif
-
-class TiXmlDocument;
-class TiXmlElement;
-class TiXmlComment;
-class TiXmlUnknown;
-class TiXmlAttribute;
-class TiXmlText;
-class TiXmlDeclaration;
-class TiXmlParsingData;
-
-const int TIXML_MAJOR_VERSION = 2;
-const int TIXML_MINOR_VERSION = 4;
-const int TIXML_PATCH_VERSION = 2;
-
-/* Internal structure for tracking location of items
- in the XML file.
-*/
-struct TiXmlCursor {
- TiXmlCursor() = default;
- void Clear() { row = col = -1; }
-
- int row{-1}; // 0 based.
- int col{-1}; // 0 based.
-};
-
-// Only used by Attribute::Query functions
-enum { TIXML_SUCCESS, TIXML_NO_ATTRIBUTE, TIXML_WRONG_TYPE };
-
-// Used by the parsing routines.
-enum TiXmlEncoding { TIXML_ENCODING_UNKNOWN, TIXML_ENCODING_UTF8, TIXML_ENCODING_LEGACY };
-
-const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
-
-/** TiXmlBase is a base class for every class in TinyXml.
- It does little except to establish that TinyXml classes
- can be printed and provide some utility functions.
-
- In XML, the document and elements can contain
- other elements and other types of nodes.
-
- @verbatim
- A Document can contain: Element (container or leaf)
- Comment (leaf)
- Unknown (leaf)
- Declaration( leaf )
-
- An Element can contain: Element (container or leaf)
- Text (leaf)
- Attributes (not on tree)
- Comment (leaf)
- Unknown (leaf)
-
- A Decleration contains: Attributes (not on tree)
- @endverbatim
-*/
-class TiXmlBase {
- friend class TiXmlNode;
- friend class TiXmlElement;
- friend class TiXmlDocument;
-
-public:
- TiXmlBase() = default;
- virtual ~TiXmlBase() = default;
-
- /** All TinyXml classes can print themselves to a filestream.
- This is a formatted print, and will insert tabs and newlines.
-
- (For an unformatted stream, use the << operator.)
- */
- virtual void Print(FILE *cfile, int depth) const = 0;
-
- /** The world does not agree on whether white space should be kept or
- not. In order to make everyone happy, these global, static functions
- are provided to set whether or not TinyXml will condense all white space
- into a single space or not. The default is to condense. Note changing this
- values is not thread safe.
- */
- static void SetCondenseWhiteSpace(bool condense) { condenseWhiteSpace = condense; }
-
- /// Return the current white space setting.
- static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; }
-
- /** Return the position, in the original source file, of this node or attribute.
- The row and column are 1-based. (That is the first row and first column is
- 1,1). If the returns values are 0 or less, then the parser does not have
- a row and column value.
-
- Generally, the row and column value will be set when the TiXmlDocument::Load(),
- TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set
- when the DOM was created from operator>>.
-
- The values reflect the initial load. Once the DOM is modified programmatically
- (by adding or changing nodes and attributes) the new values will NOT update to
- reflect changes in the document.
-
- There is a minor performance cost to computing the row and column. Computation
- can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.
-
- @sa TiXmlDocument::SetTabSize()
- */
- int Row() const { return location.row + 1; }
- int Column() const { return location.col + 1; } ///< See Row()
-
- void SetUserData(void *user) { userData = user; }
- void *GetUserData() { return userData; }
-
- // Table that returs, for a given lead byte, the total number of bytes
- // in the UTF-8 sequence.
- static const int utf8ByteTable[256];
-
- virtual const char *Parse(const char *p, TiXmlParsingData *data,
- TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */) = 0;
-
- enum {
- TIXML_NO_ERROR = 0,
- TIXML_ERROR,
- TIXML_ERROR_OPENING_FILE,
- TIXML_ERROR_OUT_OF_MEMORY,
- TIXML_ERROR_PARSING_ELEMENT,
- TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
- TIXML_ERROR_READING_ELEMENT_VALUE,
- TIXML_ERROR_READING_ATTRIBUTES,
- TIXML_ERROR_PARSING_EMPTY,
- TIXML_ERROR_READING_END_TAG,
- TIXML_ERROR_PARSING_UNKNOWN,
- TIXML_ERROR_PARSING_COMMENT,
- TIXML_ERROR_PARSING_DECLARATION,
- TIXML_ERROR_DOCUMENT_EMPTY,
- TIXML_ERROR_EMBEDDED_NULL,
- TIXML_ERROR_PARSING_CDATA,
-
- TIXML_ERROR_STRING_COUNT
- };
-
-protected:
- // See STL_STRING_BUG
- // Utility class to overcome a bug.
- class StringToBuffer {
- public:
- StringToBuffer(const TIXML_STRING &str);
- ~StringToBuffer();
- char *buffer;
- };
-
- static const char *SkipWhiteSpace(const char *, TiXmlEncoding encoding);
- inline static bool IsWhiteSpace(char c)
- {
- return (isspace((unsigned char)c) || c == '\n' || c == '\r');
- }
-
- virtual void StreamOut(TIXML_OSTREAM *) const = 0;
-
-#ifdef TIXML_USE_STL
- static bool StreamWhiteSpace(TIXML_ISTREAM *in, TIXML_STRING *tag);
- static bool StreamTo(TIXML_ISTREAM *in, int character, TIXML_STRING *tag);
-#endif
-
- /* Reads an XML name into the string provided. Returns
- a pointer just past the last character of the name,
- or 0 if the function has an error.
- */
- static const char *ReadName(const char *p, TIXML_STRING *name, TiXmlEncoding encoding);
-
- /* Reads text. Returns a pointer past the given end tag.
- Wickedly complex options, but it keeps the (sensitive) code in one place.
- */
- static const char *ReadText(const char *in, // where to start
- TIXML_STRING *text, // the string read
- bool ignoreWhiteSpace, // whether to keep the white space
- const char *endTag, // what ends this text
- bool ignoreCase, // whether to ignore case in the end tag
- TiXmlEncoding encoding); // the current encoding
-
- // If an entity has been found, transform it into a character.
- static const char *GetEntity(const char *in, char *value, int *length, TiXmlEncoding encoding);
-
- // Get a character, while interpreting entities.
- // The length can be from 0 to 4 bytes.
- inline static const char *GetChar(const char *p, char *_value, int *length,
- TiXmlEncoding encoding)
- {
- assert(p);
- if (encoding == TIXML_ENCODING_UTF8) {
- *length = utf8ByteTable[*(reinterpret_cast(p))];
- assert(*length >= 0 && *length < 5);
- }
- else {
- *length = 1;
- }
-
- if (*length == 1) {
- if (*p == '&') {
- return GetEntity(p, _value, length, encoding);
- }
- *_value = *p;
- return p + 1;
- }
- else if (*length) {
- // strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe),
- // and the null terminator isn't needed
- for (int i = 0; p[i] && i < *length; ++i) {
- _value[i] = p[i];
- }
- return p + (*length);
- }
- else {
- // Not valid text.
- return nullptr;
- }
- }
-
- // Puts a string to a stream, expanding entities as it goes.
- // Note this should not contian the '<', '>', etc, or they will be transformed into entities!
- static void PutString(const TIXML_STRING &str, TIXML_OSTREAM *out);
-
- static void PutString(const TIXML_STRING &str, TIXML_STRING *out);
-
- // Return true if the next characters in the stream are any of the endTag sequences.
- // Ignore case only works for english, and should only be relied on when comparing
- // to English words: StringEqual( p, "version", true ) is fine.
- static bool StringEqual(const char *p, const char *endTag, bool ignoreCase,
- TiXmlEncoding encoding);
-
- static const char *errorString[TIXML_ERROR_STRING_COUNT];
-
- TiXmlCursor location;
-
- /// Field containing a generic user pointer
- void *userData{nullptr};
-
- // None of these methods are reliable for any language except English.
- // Good for approximation, not great for accuracy.
- static int IsAlpha(unsigned char anyByte, TiXmlEncoding encoding);
- static int IsAlphaNum(unsigned char anyByte, TiXmlEncoding encoding);
- inline static int ToLower(int v, TiXmlEncoding encoding)
- {
- if (encoding == TIXML_ENCODING_UTF8) {
- if (v < 128) {
- return tolower(v);
- }
- return v;
- }
- else {
- return tolower(v);
- }
- }
- static void ConvertUTF32ToUTF8(unsigned long input, char *output, int *length);
-
-private:
- TiXmlBase(const TiXmlBase &); // not implemented.
- void operator=(const TiXmlBase &base); // not allowed.
-
- struct Entity {
- const char *str;
- unsigned int strLength;
- char chr;
- };
- enum {
- NUM_ENTITY = 5,
- MAX_ENTITY_LENGTH = 6
-
- };
- static Entity entity[NUM_ENTITY];
- static bool condenseWhiteSpace;
-};
-
-/** The parent class for everything in the Document Object Model.
- (Except for attributes).
- Nodes have siblings, a parent, and children. A node can be
- in a document, or stand on its own. The type of a TiXmlNode
- can be queried, and it can be cast to its more defined type.
-*/
-class TiXmlNode : public TiXmlBase {
- friend class TiXmlDocument;
- friend class TiXmlElement;
-
-public:
-#ifdef TIXML_USE_STL
-
- /** An input stream operator, for every class. Tolerant of newlines and
- formatting, but doesn't expect them.
- */
- friend std::istream &operator>>(std::istream &in, TiXmlNode &base);
-
- /** An output stream operator, for every class. Note that this outputs
- without any newlines or formatting, as opposed to Print(), which
- includes tabs and new lines.
-
- The operator<< and operator>> are not completely symmetric. Writing
- a node to a stream is very well defined. You'll get a nice stream
- of output, without any extra whitespace or newlines.
-
- But reading is not as well defined. (As it always is.) If you create
- a TiXmlElement (for example) and read that from an input stream,
- the text needs to define an element or junk will result. This is
- true of all input streams, but it's worth keeping in mind.
-
- A TiXmlDocument will read nodes until it reads a root element, and
- all the children of that root element.
- */
- friend std::ostream &operator<<(std::ostream &out, const TiXmlNode &base);
-
- /// Appends the XML node or attribute to a std::string.
- friend std::string &operator<<(std::string &out, const TiXmlNode &base);
-
-#else
- // Used internally, not part of the public API.
- friend TIXML_OSTREAM &operator<<(TIXML_OSTREAM &out, const TiXmlNode &base);
-#endif
-
- /** The types of XML nodes supported by TinyXml. (All the
- unsupported types are picked up by UNKNOWN.)
- */
- enum NodeType { DOCUMENT, ELEMENT, COMMENT, UNKNOWN, TEXT, DECLARATION, TYPECOUNT };
-
- ~TiXmlNode() override;
-
- /** The meaning of 'value' changes for the specific type of
- TiXmlNode.
- @verbatim
- Document: filename of the xml file
- Element: name of the element
- Comment: the comment text
- Unknown: the tag contents
- Text: the text string
- @endverbatim
-
- The subclasses will wrap this function.
- */
- const char *Value() const { return value.c_str(); }
-
-#ifdef TIXML_USE_STL
- /** Return Value() as a std::string. If you only use STL,
- this is more efficient than calling Value().
- Only available in STL mode.
- */
- const std::string &ValueStr() const { return value; }
-#endif
-
- /** Changes the value of the node. Defined as:
- @verbatim
- Document: filename of the xml file
- Element: name of the element
- Comment: the comment text
- Unknown: the tag contents
- Text: the text string
- @endverbatim
- */
- void SetValue(const char *_value) { value = _value; }
-
-#ifdef TIXML_USE_STL
- /// STL std::string form.
- void SetValue(const std::string &_value)
- {
- StringToBuffer const buf(_value);
- SetValue(buf.buffer ? buf.buffer : "");
- }
-#endif
-
- /// Delete all the children of this node. Does not affect 'this'.
- void Clear();
-
- /// One step up the DOM.
- TiXmlNode *Parent() { return parent; }
- const TiXmlNode *Parent() const { return parent; }
-
- const TiXmlNode *FirstChild() const
- {
- return firstChild;
- } ///< The first child of this node. Will be null if there are no children.
- TiXmlNode *FirstChild() { return firstChild; }
- const TiXmlNode *
- FirstChild(const char *value) const; ///< The first child of this node with the matching 'value'.
- ///< Will be null if none found.
- TiXmlNode *FirstChild(const char *value); ///< The first child of this node with the matching
- ///< 'value'. Will be null if none found.
-
- const TiXmlNode *LastChild() const
- {
- return lastChild;
- } /// The last child of this node. Will be null if there are no children.
- TiXmlNode *LastChild() { return lastChild; }
- const TiXmlNode *
- LastChild(const char *value) const; /// The last child of this node matching 'value'. Will be
- /// null if there are no children.
- TiXmlNode *LastChild(const char *value);
-
-#ifdef TIXML_USE_STL
- const TiXmlNode *FirstChild(const std::string &_value) const
- {
- return FirstChild(_value.c_str());
- } ///< STL std::string form.
- TiXmlNode *FirstChild(const std::string &_value)
- {
- return FirstChild(_value.c_str());
- } ///< STL std::string form.
- const TiXmlNode *LastChild(const std::string &_value) const
- {
- return LastChild(_value.c_str());
- } ///< STL std::string form.
- TiXmlNode *LastChild(const std::string &_value)
- {
- return LastChild(_value.c_str());
- } ///< STL std::string form.
-#endif
-
- /** An alternate way to walk the children of a node.
- One way to iterate over nodes is:
- @verbatim
- for( child = parent->FirstChild(); child; child = child->NextSibling() )
- @endverbatim
-
- IterateChildren does the same thing with the syntax:
- @verbatim
- child = 0;
- while( child = parent->IterateChildren( child ) )
- @endverbatim
-
- IterateChildren takes the previous child as input and finds
- the next one. If the previous child is null, it returns the
- first. IterateChildren will return null when done.
- */
- const TiXmlNode *IterateChildren(const TiXmlNode *previous) const;
- TiXmlNode *IterateChildren(TiXmlNode *previous);
-
- /// This flavor of IterateChildren searches for children with a particular 'value'
- const TiXmlNode *IterateChildren(const char *value, const TiXmlNode *previous) const;
- TiXmlNode *IterateChildren(const char *value, TiXmlNode *previous);
-
-#ifdef TIXML_USE_STL
- const TiXmlNode *IterateChildren(const std::string &_value, const TiXmlNode *previous) const
- {
- return IterateChildren(_value.c_str(), previous);
- } ///< STL std::string form.
- TiXmlNode *IterateChildren(const std::string &_value, TiXmlNode *previous)
- {
- return IterateChildren(_value.c_str(), previous);
- } ///< STL std::string form.
-#endif
-
- /** Add a new node related to this. Adds a child past the LastChild.
- Returns a pointer to the new object or NULL if an error occured.
- */
- TiXmlNode *InsertEndChild(const TiXmlNode &addThis);
-
- /** Add a new node related to this. Adds a child past the LastChild.
-
- NOTE: the node to be added is passed by pointer, and will be
- henceforth owned (and deleted) by tinyXml. This method is efficient
- and avoids an extra copy, but should be used with care as it
- uses a different memory model than the other insert functions.
-
- @sa InsertEndChild
- */
- TiXmlNode *LinkEndChild(TiXmlNode *addThis);
-
- /** Add a new node related to this. Adds a child before the specified child.
- Returns a pointer to the new object or NULL if an error occured.
- */
- TiXmlNode *InsertBeforeChild(TiXmlNode *beforeThis, const TiXmlNode &addThis);
-
- /** Add a new node related to this. Adds a child after the specified child.
- Returns a pointer to the new object or NULL if an error occured.
- */
- TiXmlNode *InsertAfterChild(TiXmlNode *afterThis, const TiXmlNode &addThis);
-
- /** Replace a child of this node.
- Returns a pointer to the new object or NULL if an error occured.
- */
- TiXmlNode *ReplaceChild(TiXmlNode *replaceThis, const TiXmlNode &withThis);
-
- /// Delete a child of this node.
- bool RemoveChild(TiXmlNode *removeThis);
-
- /// Navigate to a sibling node.
- const TiXmlNode *PreviousSibling() const { return prev; }
- TiXmlNode *PreviousSibling() { return prev; }
-
- /// Navigate to a sibling node.
- const TiXmlNode *PreviousSibling(const char *) const;
- TiXmlNode *PreviousSibling(const char *);
-
-#ifdef TIXML_USE_STL
- const TiXmlNode *PreviousSibling(const std::string &_value) const
- {
- return PreviousSibling(_value.c_str());
- } ///< STL std::string form.
- TiXmlNode *PreviousSibling(const std::string &_value)
- {
- return PreviousSibling(_value.c_str());
- } ///< STL std::string form.
- const TiXmlNode *NextSibling(const std::string &_value) const
- {
- return NextSibling(_value.c_str());
- } ///< STL std::string form.
- TiXmlNode *NextSibling(const std::string &_value)
- {
- return NextSibling(_value.c_str());
- } ///< STL std::string form.
-#endif
-
- /// Navigate to a sibling node.
- const TiXmlNode *NextSibling() const { return next; }
- TiXmlNode *NextSibling() { return next; }
-
- /// Navigate to a sibling node with the given 'value'.
- const TiXmlNode *NextSibling(const char *) const;
- TiXmlNode *NextSibling(const char *);
-
- /** Convenience function to get through elements.
- Calls NextSibling and ToElement. Will skip all non-Element
- nodes. Returns 0 if there is not another element.
- */
- const TiXmlElement *NextSiblingElement() const;
- TiXmlElement *NextSiblingElement();
-
- /** Convenience function to get through elements.
- Calls NextSibling and ToElement. Will skip all non-Element
- nodes. Returns 0 if there is not another element.
- */
- const TiXmlElement *NextSiblingElement(const char *) const;
- TiXmlElement *NextSiblingElement(const char *);
-
-#ifdef TIXML_USE_STL
- const TiXmlElement *NextSiblingElement(const std::string &_value) const
- {
- return NextSiblingElement(_value.c_str());
- } ///< STL std::string form.
- TiXmlElement *NextSiblingElement(const std::string &_value)
- {
- return NextSiblingElement(_value.c_str());
- } ///< STL std::string form.
-#endif
-
- /// Convenience function to get through elements.
- const TiXmlElement *FirstChildElement() const;
- TiXmlElement *FirstChildElement();
-
- /// Convenience function to get through elements.
- const TiXmlElement *FirstChildElement(const char *value) const;
- TiXmlElement *FirstChildElement(const char *value);
-
-#ifdef TIXML_USE_STL
- const TiXmlElement *FirstChildElement(const std::string &_value) const
- {
- return FirstChildElement(_value.c_str());
- } ///< STL std::string form.
- TiXmlElement *FirstChildElement(const std::string &_value)
- {
- return FirstChildElement(_value.c_str());
- } ///< STL std::string form.
-#endif
-
- /** Query the type (as an enumerated value, above) of this node.
- The possible types are: DOCUMENT, ELEMENT, COMMENT,
- UNKNOWN, TEXT, and DECLARATION.
- */
- int Type() const { return type; }
-
- /** Return a pointer to the Document this node lives in.
- Returns null if not in a document.
- */
- const TiXmlDocument *GetDocument() const;
- TiXmlDocument *GetDocument();
-
- /// Returns true if this node has no children.
- bool NoChildren() const { return !firstChild; }
-
- const TiXmlDocument *ToDocument() const;
- const TiXmlElement *ToElement() const;
- const TiXmlComment *ToComment() const;
- const TiXmlUnknown *ToUnknown() const;
- const TiXmlText *ToText() const;
- const TiXmlDeclaration *ToDeclaration() const;
-
- TiXmlDocument *ToDocument();
- TiXmlElement *ToElement();
- TiXmlComment *ToComment();
- TiXmlUnknown *ToUnknown();
- TiXmlText *ToText();
- TiXmlDeclaration *ToDeclaration();
-
- /** Create an exact duplicate of this node and return it. The memory must be deleted
- by the caller.
- */
- virtual TiXmlNode *Clone() const = 0;
-
-protected:
- TiXmlNode(NodeType _type) : TiXmlBase(), type(_type) {}
-
- // Copy to the allocated object. Shared functionality between Clone, Copy constructor,
- // and the assignment operator.
- void CopyTo(TiXmlNode *target) const;
-
-#ifdef TIXML_USE_STL
- // The real work of the input operator.
- virtual void StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag) = 0;
-#endif
-
- // Figure out what is at *p, and parse it. Returns null if it is not an xml node.
- TiXmlNode *Identify(const char *start, TiXmlEncoding encoding);
-
- TiXmlNode *parent{nullptr};
- NodeType type;
-
- TiXmlNode *firstChild{nullptr};
- TiXmlNode *lastChild{nullptr};
-
- TIXML_STRING value;
-
- TiXmlNode *prev{nullptr};
- TiXmlNode *next{nullptr};
-
-private:
- TiXmlNode(const TiXmlNode &); // not implemented.
- void operator=(const TiXmlNode &base); // not allowed.
-};
-
-/** An attribute is a name-value pair. Elements have an arbitrary
- number of attributes, each with a unique name.
-
- @note The attributes are not TiXmlNodes, since they are not
- part of the tinyXML document object model. There are other
- suggested ways to look at this problem.
-*/
-class TiXmlAttribute : public TiXmlBase {
- friend class TiXmlAttributeSet;
-
-public:
- /// Construct an empty attribute.
- TiXmlAttribute() : TiXmlBase(), document(nullptr) { prev = next = nullptr; }
-
-#ifdef TIXML_USE_STL
- /// std::string constructor.
- TiXmlAttribute(const std::string &_name, const std::string &_value)
- : document(nullptr), name(_name), value(_value)
- {
- prev = next = nullptr;
- }
-#endif
-
- /// Construct an attribute with a name and value.
- TiXmlAttribute(const char *_name, const char *_value)
- : document(nullptr), name(_name), value(_value)
- {
- prev = next = nullptr;
- }
-
- const char *Name() const { return name.c_str(); } ///< Return the name of this attribute.
- const char *Value() const { return value.c_str(); } ///< Return the value of this attribute.
- int IntValue() const; ///< Return the value of this attribute, converted to an integer.
- double DoubleValue() const; ///< Return the value of this attribute, converted to a double.
-
- /** QueryIntValue examines the value string. It is an alternative to the
- IntValue() method with richer error checking.
- If the value is an integer, it is stored in 'value' and
- the call returns TIXML_SUCCESS. If it is not
- an integer, it returns TIXML_WRONG_TYPE.
-
- A specialized but useful call. Note that for success it returns 0,
- which is the opposite of almost all other TinyXml calls.
- */
- int QueryIntValue(int *_value) const;
- /// QueryDoubleValue examines the value string. See QueryIntValue().
- int QueryDoubleValue(double *_value) const;
-
- void SetName(const char *_name) { name = _name; } ///< Set the name of this attribute.
- void SetValue(const char *_value) { value = _value; } ///< Set the value.
-
- void SetIntValue(int _value); ///< Set the value from an integer.
- void SetDoubleValue(double _value); ///< Set the value from a double.
-
-#ifdef TIXML_USE_STL
- /// STL std::string form.
- void SetName(const std::string &_name)
- {
- const StringToBuffer buf(_name);
- SetName(buf.buffer ? buf.buffer : "error");
- }
- /// STL std::string form.
- void SetValue(const std::string &_value)
- {
- const StringToBuffer buf(_value);
- SetValue(buf.buffer ? buf.buffer : "error");
- }
-#endif
-
- /// Get the next sibling attribute in the DOM. Returns null at end.
- const TiXmlAttribute *Next() const;
- TiXmlAttribute *Next();
- /// Get the previous sibling attribute in the DOM. Returns null at beginning.
- const TiXmlAttribute *Previous() const;
- TiXmlAttribute *Previous();
-
- bool operator==(const TiXmlAttribute &rhs) const { return rhs.name == name; }
- bool operator<(const TiXmlAttribute &rhs) const { return name < rhs.name; }
- bool operator>(const TiXmlAttribute &rhs) const { return name > rhs.name; }
-
- /* Attribute parsing starts: first letter of the name
- returns: the next char after the value end quote
- */
- const char *Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding) override;
-
- // Prints this Attribute to a FILE stream.
- void Print(FILE *cfile, int depth) const override;
-
- void StreamOut(TIXML_OSTREAM *out) const override;
- // [internal use]
- // Set the document pointer so the attribute can report errors.
- void SetDocument(TiXmlDocument *doc) { document = doc; }
-
-private:
- TiXmlAttribute(const TiXmlAttribute &); // not implemented.
- void operator=(const TiXmlAttribute &base); // not allowed.
-
- TiXmlDocument *document; // A pointer back to a document, for error reporting.
- TIXML_STRING name;
- TIXML_STRING value;
- TiXmlAttribute *prev;
- TiXmlAttribute *next;
-};
-
-/* A class used to manage a group of attributes.
- It is only used internally, both by the ELEMENT and the DECLARATION.
-
- The set can be changed transparent to the Element and Declaration
- classes that use it, but NOT transparent to the Attribute
- which has to implement a next() and previous() method. Which makes
- it a bit problematic and prevents the use of STL.
-
- This version is implemented with circular lists because:
- - I like circular lists
- - it demonstrates some independence from the (typical) doubly linked list.
-*/
-class TiXmlAttributeSet {
-public:
- TiXmlAttributeSet();
- ~TiXmlAttributeSet();
-
- void Add(TiXmlAttribute *attribute);
- void Remove(TiXmlAttribute *attribute);
-
- const TiXmlAttribute *First() const
- {
- return (sentinel.next == &sentinel) ? nullptr : sentinel.next;
- }
- TiXmlAttribute *First() { return (sentinel.next == &sentinel) ? nullptr : sentinel.next; }
- const TiXmlAttribute *Last() const
- {
- return (sentinel.prev == &sentinel) ? nullptr : sentinel.prev;
- }
- TiXmlAttribute *Last() { return (sentinel.prev == &sentinel) ? nullptr : sentinel.prev; }
-
- const TiXmlAttribute *Find(const char *name) const;
- TiXmlAttribute *Find(const char *name);
-
- TiXmlAttributeSet(const TiXmlAttributeSet &) = delete; // not allowed
- void operator=(const TiXmlAttributeSet &) = delete; // not allowed (as TiXmlAttribute)
-
-private:
- TiXmlAttribute sentinel;
-};
-
-/** The element is a container class. It has a value, the element name,
- and can contain other elements, text, comments, and unknowns.
- Elements also contain an arbitrary number of attributes.
-*/
-class TiXmlElement : public TiXmlNode {
-public:
- /// Construct an element.
- TiXmlElement(const char *in_value);
-
-#ifdef TIXML_USE_STL
- /// std::string constructor.
- TiXmlElement(const std::string &_value);
-#endif
-
- TiXmlElement(const TiXmlElement &);
-
- void operator=(const TiXmlElement &base);
-
- ~TiXmlElement() override;
-
- /** Given an attribute name, Attribute() returns the value
- for the attribute of that name, or null if none exists.
- */
- const char *Attribute(const char *name) const;
-
- /** Given an attribute name, Attribute() returns the value
- for the attribute of that name, or null if none exists.
- If the attribute exists and can be converted to an integer,
- the integer value will be put in the return 'i', if 'i'
- is non-null.
- */
- const char *Attribute(const char *name, int *i) const;
-
- /** Given an attribute name, Attribute() returns the value
- for the attribute of that name, or null if none exists.
- If the attribute exists and can be converted to an double,
- the double value will be put in the return 'd', if 'd'
- is non-null.
- */
- const char *Attribute(const char *name, double *d) const;
-
- /** QueryIntAttribute examines the attribute - it is an alternative to the
- Attribute() method with richer error checking.
- If the attribute is an integer, it is stored in 'value' and
- the call returns TIXML_SUCCESS. If it is not
- an integer, it returns TIXML_WRONG_TYPE. If the attribute
- does not exist, then TIXML_NO_ATTRIBUTE is returned.
- */
- int QueryIntAttribute(const char *name, int *_value) const;
- /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().
- int QueryDoubleAttribute(const char *name, double *_value) const;
- /// QueryFloatAttribute examines the attribute - see QueryIntAttribute().
- int QueryFloatAttribute(const char *name, float *_value) const
- {
- double d;
- const int result = QueryDoubleAttribute(name, &d);
- if (result == TIXML_SUCCESS) {
- *_value = (float)d;
- }
- return result;
- }
-
- /** Sets an attribute of name to a given value. The attribute
- will be created if it does not exist, or changed if it does.
- */
- void SetAttribute(const char *name, const char *_value);
-
-#ifdef TIXML_USE_STL
- const char *Attribute(const std::string &name) const { return Attribute(name.c_str()); }
- const char *Attribute(const std::string &name, int *i) const
- {
- return Attribute(name.c_str(), i);
- }
- const char *Attribute(const std::string &name, double *d) const
- {
- return Attribute(name.c_str(), d);
- }
- int QueryIntAttribute(const std::string &name, int *_value) const
- {
- return QueryIntAttribute(name.c_str(), _value);
- }
- int QueryDoubleAttribute(const std::string &name, double *_value) const
- {
- return QueryDoubleAttribute(name.c_str(), _value);
- }
-
- /// STL std::string form.
- void SetAttribute(const std::string &name, const std::string &_value)
- {
- const StringToBuffer n(name);
- const StringToBuffer v(_value);
- if (n.buffer && v.buffer) {
- SetAttribute(n.buffer, v.buffer);
- }
- }
- ///< STL std::string form.
- void SetAttribute(const std::string &name, int _value)
- {
- const StringToBuffer n(name);
- if (n.buffer) {
- SetAttribute(n.buffer, _value);
- }
- }
-#endif
-
- /** Sets an attribute of name to a given value. The attribute
- will be created if it does not exist, or changed if it does.
- */
- void SetAttribute(const char *name, int value);
-
- /** Sets an attribute of name to a given value. The attribute
- will be created if it does not exist, or changed if it does.
- */
- void SetDoubleAttribute(const char *name, double value);
-
- /** Deletes an attribute with the given name.
- */
- void RemoveAttribute(const char *name);
-#ifdef TIXML_USE_STL
- void RemoveAttribute(const std::string &name)
- {
- RemoveAttribute(name.c_str());
- } ///< STL std::string form.
-#endif
-
- const TiXmlAttribute *FirstAttribute() const
- {
- return attributeSet.First();
- } ///< Access the first attribute in this element.
- TiXmlAttribute *FirstAttribute() { return attributeSet.First(); }
- const TiXmlAttribute *LastAttribute() const
- {
- return attributeSet.Last();
- } ///< Access the last attribute in this element.
- TiXmlAttribute *LastAttribute() { return attributeSet.Last(); }
-
- /** Convenience function for easy access to the text inside an element. Although easy
- and concise, GetText() is limited compared to getting the TiXmlText child
- and accessing it directly.
-
- If the first child of 'this' is a TiXmlText, the GetText()
- returns the character string of the Text node, else null is returned.
-
- This is a convenient method for getting the text of simple contained text:
- @verbatim
- This is text
- const char* str = fooElement->GetText();
- @endverbatim
-
- 'str' will be a pointer to "This is text".
-
- Note that this function can be misleading. If the element foo was created from
- this XML:
- @verbatim
- This is text
- @endverbatim
-
- then the value of str would be null. The first child node isn't a text node, it is
- another element. From this XML:
- @verbatim
- This is text
- @endverbatim
- GetText() will return "This is ".
-
- WARNING: GetText() accesses a child node - don't become confused with the
- similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are
- safe type casts on the referenced node.
- */
- const char *GetText() const;
-
- /// Creates a new Element and returns it - the returned element is a copy.
- TiXmlNode *Clone() const override;
- // Print the Element to a FILE stream.
- void Print(FILE *cfile, int depth) const override;
-
- /* Attribtue parsing starts: next char past '<'
- returns: next char past '>'
- */
- const char *Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding) override;
-
-protected:
- void CopyTo(TiXmlElement *target) const;
- void ClearThis(); // like clear, but initializes 'this' object as well
-
-// Used to be public [internal use]
-#ifdef TIXML_USE_STL
- void StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag) override;
-#endif
- void StreamOut(TIXML_OSTREAM *out) const override;
-
- /* [internal use]
- Reads the "value" of the element -- another element, or text.
- This should terminate with the current end tag.
- */
- const char *ReadValue(const char *in, TiXmlParsingData *prevData, TiXmlEncoding encoding);
-
-private:
- TiXmlAttributeSet attributeSet;
-};
-
-/** An XML comment.
- */
-class TiXmlComment : public TiXmlNode {
-public:
- /// Constructs an empty comment.
- TiXmlComment() : TiXmlNode(TiXmlNode::COMMENT) {}
- TiXmlComment(const TiXmlComment &);
- void operator=(const TiXmlComment &base);
-
- ~TiXmlComment() override = default;
-
- /// Returns a copy of this Comment.
- TiXmlNode *Clone() const override;
- /// Write this Comment to a FILE stream.
- void Print(FILE *cfile, int depth) const override;
-
- /* Attribtue parsing starts: at the ! of the !--
- returns: next char past '>'
- */
- const char *Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding) override;
-
-protected:
- void CopyTo(TiXmlComment *target) const;
-
-// used to be public
-#ifdef TIXML_USE_STL
- void StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag) override;
-#endif
- void StreamOut(TIXML_OSTREAM *out) const override;
-
-private:
-};
-
-/** XML text. A text node can have 2 ways to output the next. "normal" output
- and CDATA. It will default to the mode it was parsed from the XML file and
- you generally want to leave it alone, but you can change the output mode with
- SetCDATA() and query it with CDATA().
-*/
-class TiXmlText : public TiXmlNode {
- friend class TiXmlElement;
-
-public:
- /** Constructor for text element. By default, it is treated as
- normal, encoded text. If you want it be output as a CDATA text
- element, set the parameter _cdata to 'true'
- */
- TiXmlText(const char *initValue) : TiXmlNode(TiXmlNode::TEXT), cdata(false)
- {
- SetValue(initValue);
- }
- ~TiXmlText() override = default;
-
-#ifdef TIXML_USE_STL
- /// Constructor.
- TiXmlText(const std::string &initValue) : TiXmlNode(TiXmlNode::TEXT), cdata(false)
- {
- SetValue(initValue);
- }
-#endif
-
- TiXmlText(const TiXmlText ©) : TiXmlNode(TiXmlNode::TEXT), cdata(copy.cdata)
- {
- copy.CopyTo(this);
- }
- void operator=(const TiXmlText &base) { base.CopyTo(this); }
-
- /// Write this text object to a FILE stream.
- void Print(FILE *cfile, int depth) const override;
-
- /// Queries whether this represents text using a CDATA section.
- bool CDATA() { return cdata; }
- /// Turns on or off a CDATA representation of text.
- void SetCDATA(bool _cdata) { cdata = _cdata; }
-
- const char *Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding) override;
-
-protected:
- /// [internal use] Creates a new Element and returns it.
- TiXmlNode *Clone() const override;
- void CopyTo(TiXmlText *target) const;
-
- void StreamOut(TIXML_OSTREAM *out) const override;
- bool Blank() const; // returns true if all white space and new lines
-// [internal use]
-#ifdef TIXML_USE_STL
- void StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag) override;
-#endif
-
-private:
- bool cdata; // true if this should be input and output as a CDATA style text element
-};
-
-/** In correct XML the declaration is the first entry in the file.
- @verbatim
-
- @endverbatim
-
- TinyXml will happily read or write files without a declaration,
- however. There are 3 possible attributes to the declaration:
- version, encoding, and standalone.
-
- Note: In this version of the code, the attributes are
- handled as special cases, not generic attributes, simply
- because there can only be at most 3 and they are always the same.
-*/
-class TiXmlDeclaration : public TiXmlNode {
-public:
- /// Construct an empty declaration.
- TiXmlDeclaration() : TiXmlNode(TiXmlNode::DECLARATION) {}
-
-#ifdef TIXML_USE_STL
- /// Constructor.
- TiXmlDeclaration(const std::string &_version, const std::string &_encoding,
- const std::string &_standalone);
-#endif
-
- /// Construct.
- TiXmlDeclaration(const char *_version, const char *_encoding, const char *_standalone);
-
- TiXmlDeclaration(const TiXmlDeclaration ©);
- void operator=(const TiXmlDeclaration ©);
-
- ~TiXmlDeclaration() override = default;
-
- /// Version. Will return an empty string if none was found.
- const char *Version() const { return version.c_str(); }
- /// Encoding. Will return an empty string if none was found.
- const char *Encoding() const { return encoding.c_str(); }
- /// Is this a standalone document?
- const char *Standalone() const { return standalone.c_str(); }
-
- /// Creates a copy of this Declaration and returns it.
- TiXmlNode *Clone() const override;
- /// Print this declaration to a FILE stream.
- void Print(FILE *cfile, int depth) const override;
-
- const char *Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding) override;
-
-protected:
- void CopyTo(TiXmlDeclaration *target) const;
-// used to be public
-#ifdef TIXML_USE_STL
- void StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag) override;
-#endif
- void StreamOut(TIXML_OSTREAM *out) const override;
-
-private:
- TIXML_STRING version;
- TIXML_STRING encoding;
- TIXML_STRING standalone;
-};
-
-/** Any tag that tinyXml doesn't recognize is saved as an
- unknown. It is a tag of text, but should not be modified.
- It will be written back to the XML, unchanged, when the file
- is saved.
-
- DTD tags get thrown into TiXmlUnknowns.
-*/
-class TiXmlUnknown : public TiXmlNode {
-public:
- TiXmlUnknown() : TiXmlNode(TiXmlNode::UNKNOWN) {}
- ~TiXmlUnknown() override = default;
-
- TiXmlUnknown(const TiXmlUnknown ©) : TiXmlNode(TiXmlNode::UNKNOWN) { copy.CopyTo(this); }
- void operator=(const TiXmlUnknown ©) { copy.CopyTo(this); }
-
- /// Creates a copy of this Unknown and returns it.
- TiXmlNode *Clone() const override;
- /// Print this Unknown to a FILE stream.
- void Print(FILE *cfile, int depth) const override;
-
- const char *Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding) override;
-
-protected:
- void CopyTo(TiXmlUnknown *target) const;
-
-#ifdef TIXML_USE_STL
- void StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag) override;
-#endif
- void StreamOut(TIXML_OSTREAM *out) const override;
-
-private:
-};
-
-/** Always the top level node. A document binds together all the
- XML pieces. It can be saved, loaded, and printed to the screen.
- The 'value' of a document node is the xml file name.
-*/
-class TiXmlDocument : public TiXmlNode {
-public:
- /// Create an empty document, that has no name.
- TiXmlDocument();
- /// Create a document with a name. The name of the document is also the filename of the xml.
- TiXmlDocument(const char *documentName);
-
-#ifdef TIXML_USE_STL
- /// Constructor.
- TiXmlDocument(const std::string &documentName);
-#endif
-
- TiXmlDocument(const TiXmlDocument ©);
- void operator=(const TiXmlDocument ©);
-
- ~TiXmlDocument() override = default;
-
- /** Load a file using the current document value.
- Returns true if successful. Will delete any existing
- document data before loading.
- */
- bool LoadFile(TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING);
- /// Save a file using the current document value. Returns true if successful.
- bool SaveFile() const;
- /// Load a file using the given filename. Returns true if successful.
- bool LoadFile(const char *filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING);
- /// Save a file using the given filename. Returns true if successful.
- bool SaveFile(const char *filename) const;
-
-#ifdef TIXML_USE_STL
- bool LoadFile(const std::string &filename,
- TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING) ///< STL std::string version.
- {
- const StringToBuffer f(filename);
- return (f.buffer && LoadFile(f.buffer, encoding));
- }
- bool SaveFile(const std::string &filename) const ///< STL std::string version.
- {
- const StringToBuffer f(filename);
- return (f.buffer && SaveFile(f.buffer));
- }
-#endif
-
- /** Parse the given null terminated block of xml data. Passing in an encoding to this
- method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml
- to use that encoding, regardless of what TinyXml might otherwise try to detect.
- */
- const char *Parse(const char *p, TiXmlParsingData *data = nullptr,
- TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING) override;
-
- /** Get the root element -- the only top level element -- of the document.
- In well formed XML, there should only be one. TinyXml is tolerant of
- multiple elements at the document level.
- */
- const TiXmlElement *RootElement() const { return FirstChildElement(); }
- TiXmlElement *RootElement() { return FirstChildElement(); }
-
- /** If an error occurs, Error will be set to true. Also,
- - The ErrorId() will contain the integer identifier of the error (not generally useful)
- - The ErrorDesc() method will return the name of the error. (very useful)
- - The ErrorRow() and ErrorCol() will return the location of the error (if known)
- */
- bool Error() const { return error; }
-
- /// Contains a textual (english) description of the error if one occurs.
- const char *ErrorDesc() const { return errorDesc.c_str(); }
-
- /** Generally, you probably want the error string ( ErrorDesc() ). But if you
- prefer the ErrorId, this function will fetch it.
- */
- int ErrorId() const { return errorId; }
-
- /** Returns the location (if known) of the error. The first column is column 1,
- and the first row is row 1. A value of 0 means the row and column wasn't applicable
- (memory errors, for example, have no row/column) or the parser lost the error. (An
- error in the error reporting, in that case.)
-
- @sa SetTabSize, Row, Column
- */
- int ErrorRow() { return errorLocation.row + 1; }
- int ErrorCol()
- {
- return errorLocation.col + 1;
- } ///< The column where the error occured. See ErrorRow()
-
- /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
- to report the correct values for row and column. It does not change the output
- or input in any way.
-
- By calling this method, with a tab size
- greater than 0, the row and column of each node and attribute is stored
- when the file is loaded. Very useful for tracking the DOM back in to
- the source file.
-
- The tab size is required for calculating the location of nodes. If not
- set, the default of 4 is used. The tabsize is set per document. Setting
- the tabsize to 0 disables row/column tracking.
-
- Note that row and column tracking is not supported when using operator>>.
-
- The tab size needs to be enabled before the parse or load. Correct usage:
- @verbatim
- TiXmlDocument doc;
- doc.SetTabSize( 8 );
- doc.Load( "myfile.xml" );
- @endverbatim
-
- @sa Row, Column
- */
- void SetTabSize(int _tabsize) { tabsize = _tabsize; }
-
- int TabSize() const { return tabsize; }
-
- /** If you have handled the error, it can be reset with this call. The error
- state is automatically cleared if you Parse a new XML block.
- */
- void ClearError()
- {
- error = false;
- errorId = 0;
- errorDesc = "";
- errorLocation.row = errorLocation.col = 0;
- // errorLocation.last = 0;
- }
-
- /** Dump the document to standard out. */
- void Print() const { Print(stdout, 0); }
-
- /// Print this Document to a FILE stream.
- void Print(FILE *cfile, int depth = 0) const override;
- // [internal use]
- void SetError(int err, const char *errorLocation, TiXmlParsingData *prevData,
- TiXmlEncoding encoding);
-
-protected:
- void StreamOut(TIXML_OSTREAM *out) const override;
- // [internal use]
- TiXmlNode *Clone() const override;
-#ifdef TIXML_USE_STL
- void StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag) override;
-#endif
-
-private:
- void CopyTo(TiXmlDocument *target) const;
-
- bool error{false};
- int errorId{0};
- TIXML_STRING errorDesc;
- int tabsize{4};
- TiXmlCursor errorLocation;
- bool useMicrosoftBOM{false}; // the UTF-8 BOM were found when read. Note this, and try to write.
-};
-
-/**
- A TiXmlHandle is a class that wraps a node pointer with null checks; this is
- an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml
- DOM structure. It is a separate utility class.
-
- Take an example:
- @verbatim
-
-
-
-
-
-
- @endverbatim
-
- Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
- easy to write a *lot* of code that looks like:
-
- @verbatim
- TiXmlElement* root = document.FirstChildElement( "Document" );
- if ( root )
- {
- TiXmlElement* element = root->FirstChildElement( "Element" );
- if ( element )
- {
- TiXmlElement* child = element->FirstChildElement( "Child" );
- if ( child )
- {
- TiXmlElement* child2 = child->NextSiblingElement( "Child" );
- if ( child2 )
- {
- // Finally do something useful.
- @endverbatim
-
- And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity
- of such code. A TiXmlHandle checks for null pointers so it is perfectly safe
- and correct to use:
-
- @verbatim
- TiXmlHandle docHandle( &document );
- TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child(
- "Child", 1 ).Element(); if ( child2 )
- {
- // do something useful
- @endverbatim
-
- Which is MUCH more concise and useful.
-
- It is also safe to copy handles - internally they are nothing more than node pointers.
- @verbatim
- TiXmlHandle handleCopy = handle;
- @endverbatim
-
- What they should not be used for is iteration:
-
- @verbatim
- int i=0;
- while ( true )
- {
- TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element"
- ).Child( "Child", i ).Element(); if ( !child ) break;
- // do something
- ++i;
- }
- @endverbatim
-
- It seems reasonable, but it is in fact two embedded while loops. The Child method is
- a linear walk to find the element, so this code would iterate much more than it needs
- to. Instead, prefer:
-
- @verbatim
- TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element"
- ).FirstChild( "Child" ).Element();
-
- for( child; child; child=child->NextSiblingElement() )
- {
- // do something
- }
- @endverbatim
-*/
-class TiXmlHandle {
-public:
- /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
- TiXmlHandle(TiXmlNode *_node) : node(_node) {}
- /// Copy constructor
- TiXmlHandle(const TiXmlHandle &ref) = default;
- TiXmlHandle operator=(const TiXmlHandle &ref)
- {
- this->node = ref.node;
- return *this;
- }
-
- /// Return a handle to the first child node.
- TiXmlHandle FirstChild() const;
- /// Return a handle to the first child node with the given name.
- TiXmlHandle FirstChild(const char *value) const;
- /// Return a handle to the first child element.
- TiXmlHandle FirstChildElement() const;
- /// Return a handle to the first child element with the given name.
- TiXmlHandle FirstChildElement(const char *value) const;
-
- /** Return a handle to the "index" child with the given name.
- The first child is 0, the second 1, etc.
- */
- TiXmlHandle Child(const char *value, int index) const;
- /** Return a handle to the "index" child.
- The first child is 0, the second 1, etc.
- */
- TiXmlHandle Child(int index) const;
- /** Return a handle to the "index" child element with the given name.
- The first child element is 0, the second 1, etc. Note that only TiXmlElements
- are indexed: other types are not counted.
- */
- TiXmlHandle ChildElement(const char *value, int index) const;
- /** Return a handle to the "index" child element.
- The first child element is 0, the second 1, etc. Note that only TiXmlElements
- are indexed: other types are not counted.
- */
- TiXmlHandle ChildElement(int index) const;
-
-#ifdef TIXML_USE_STL
- TiXmlHandle FirstChild(const std::string &_value) const { return FirstChild(_value.c_str()); }
- TiXmlHandle FirstChildElement(const std::string &_value) const
- {
- return FirstChildElement(_value.c_str());
- }
-
- TiXmlHandle Child(const std::string &_value, int index) const
- {
- return Child(_value.c_str(), index);
- }
- TiXmlHandle ChildElement(const std::string &_value, int index) const
- {
- return ChildElement(_value.c_str(), index);
- }
-#endif
-
- /// Return the handle as a TiXmlNode. This may return null.
- TiXmlNode *Node() const { return node; }
- /// Return the handle as a TiXmlElement. This may return null.
- TiXmlElement *Element() const
- {
- return ((node && node->ToElement()) ? node->ToElement() : nullptr);
- }
- /// Return the handle as a TiXmlText. This may return null.
- TiXmlText *Text() const { return ((node && node->ToText()) ? node->ToText() : nullptr); }
- /// Return the handle as a TiXmlUnknown. This may return null;
- TiXmlUnknown *Unknown() const
- {
- return ((node && node->ToUnknown()) ? node->ToUnknown() : nullptr);
- }
-
-private:
- TiXmlNode *node;
-};
-
-inline const TiXmlDocument *TiXmlNode::ToDocument() const
-{
- return (type == DOCUMENT) ? dynamic_cast(this) : nullptr;
-}
-inline const TiXmlElement *TiXmlNode::ToElement() const
-{
- return (type == ELEMENT) ? dynamic_cast(this) : nullptr;
-}
-inline const TiXmlComment *TiXmlNode::ToComment() const
-{
- return (type == COMMENT) ? dynamic_cast(this) : nullptr;
-}
-inline const TiXmlUnknown *TiXmlNode::ToUnknown() const
-{
- return (type == UNKNOWN) ? dynamic_cast(this) : nullptr;
-}
-inline const TiXmlText *TiXmlNode::ToText() const
-{
- return (type == TEXT) ? dynamic_cast(this) : nullptr;
-}
-inline const TiXmlDeclaration *TiXmlNode::ToDeclaration() const
-{
- return (type == DECLARATION) ? dynamic_cast(this) : nullptr;
-}
-
-inline TiXmlDocument *TiXmlNode::ToDocument()
-{
- return (type == DOCUMENT) ? dynamic_cast(this) : nullptr;
-}
-inline TiXmlElement *TiXmlNode::ToElement()
-{
- return (type == ELEMENT) ? dynamic_cast(this) : nullptr;
-}
-inline TiXmlComment *TiXmlNode::ToComment()
-{
- return (type == COMMENT) ? dynamic_cast(this) : nullptr;
-}
-inline TiXmlUnknown *TiXmlNode::ToUnknown()
-{
- return (type == UNKNOWN) ? dynamic_cast(this) : nullptr;
-}
-inline TiXmlText *TiXmlNode::ToText()
-{
- return (type == TEXT) ? dynamic_cast(this) : nullptr;
-}
-inline TiXmlDeclaration *TiXmlNode::ToDeclaration()
-{
- return (type == DECLARATION) ? dynamic_cast(this) : nullptr;
-}
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#endif
diff --git a/src/core/tinyxmlerror.cc b/src/core/tinyxmlerror.cc
deleted file mode 100644
index 1c1466b011..0000000000
--- a/src/core/tinyxmlerror.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-www.sourceforge.net/projects/tinyxml
-Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any
-damages arising from the use of this software.
-
-Permission is granted to anyone to use this software for any
-purpose, including commercial applications, and to alter it and
-redistribute it freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must
-not claim that you wrote the original software. If you use this
-software in a product, an acknowledgment in the product documentation
-would be appreciated but is not required.
-
-2. Altered source versions must be plainly marked as such, and
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-#include "tinyxml.h"
-
-// The goal of the seperate error file is to make the first
-// step towards localization. tinyxml (currently) only supports
-// english error messages, but the could now be translated.
-//
-// It also cleans up the code a bit.
-//
-
-const char *TiXmlBase::errorString[TIXML_ERROR_STRING_COUNT] = {
- "No error",
- "Error",
- "Failed to open file",
- "Memory allocation failed.",
- "Error parsing Element.",
- "Failed to read Element name",
- "Error reading Element value.",
- "Error reading Attributes.",
- "Error: empty tag.",
- "Error reading end tag.",
- "Error parsing Unknown.",
- "Error parsing Comment.",
- "Error parsing Declaration.",
- "Error document empty.",
- "Error null (0) or unexpected EOF found in input stream.",
- "Error parsing CDATA.",
-};
diff --git a/src/core/tinyxmlparser.cc b/src/core/tinyxmlparser.cc
deleted file mode 100644
index 7c0c11e137..0000000000
--- a/src/core/tinyxmlparser.cc
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
-www.sourceforge.net/projects/tinyxml
-Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any
-damages arising from the use of this software.
-
-Permission is granted to anyone to use this software for any
-purpose, including commercial applications, and to alter it and
-redistribute it freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must
-not claim that you wrote the original software. If you use this
-software in a product, an acknowledgment in the product documentation
-would be appreciated but is not required.
-
-2. Altered source versions must be plainly marked as such, and
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-#include
-#include
-
-#include "tinyxml.h"
-
-// #define DEBUG_PARSER
-
-// Note tha "PutString" hardcodes the same list. This
-// is less flexible than it appears. Changing the entries
-// or order will break putstring.
-TiXmlBase::Entity TiXmlBase::entity[NUM_ENTITY] = {{"&", 5, '&'},
- {"<", 4, '<'},
- {">", 4, '>'},
- {""", 6, '\"'},
- {"'", 6, '\''}};
-
-// Bunch of unicode info at:
-// http://www.unicode.org/faq/utf_bom.html
-// Including the basic of this table, which determines the #bytes in the
-// sequence from the lead byte. 1 placed for invalid sequences --
-// although the result will be junk, pass it through as much as possible.
-// Beware of the non-characters in UTF-8:
-// ef bb bf (Microsoft "lead bytes")
-// ef bf be
-// ef bf bf
-
-const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
-const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
-const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
-
-const int TiXmlBase::utf8ByteTable[256] = {
- // 0 1 2 3 4 5 6 7 8 9 a b
- // c d e f
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x20
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x30
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x50
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0x90
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
- 1, 1, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte
- 4, 4, 4, 4, 4, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
-};
-
-void TiXmlBase::ConvertUTF32ToUTF8(unsigned long input, char *output, int *length)
-{
- const unsigned long BYTE_MASK = 0xBF;
- const unsigned long BYTE_MARK = 0x80;
- const unsigned long FIRST_BYTE_MARK[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
-
- if (input < 0x80) {
- *length = 1;
- }
- else if (input < 0x800) {
- *length = 2;
- }
- else if (input < 0x10000) {
- *length = 3;
- }
- else if (input < 0x200000) {
- *length = 4;
- }
- else {
- *length = 0;
- return;
- } // This code won't covert this correctly anyway.
-
- output += *length;
-
- // Scary scary fall throughs.
- switch (*length) {
- case 4:
- --output;
- *output = (char)((input | BYTE_MARK) & BYTE_MASK);
- input >>= 6;
- case 3:
- --output;
- *output = (char)((input | BYTE_MARK) & BYTE_MASK);
- input >>= 6;
- case 2:
- --output;
- *output = (char)((input | BYTE_MARK) & BYTE_MASK);
- input >>= 6;
- case 1:
- --output;
- *output = (char)(input | FIRST_BYTE_MARK[*length]);
- }
-}
-
-/*static*/ int TiXmlBase::IsAlpha(unsigned char anyByte, TiXmlEncoding /*encoding*/)
-{
- // This will only work for low-ascii, everything else is assumed to be a valid
- // letter. I'm not sure this is the best approach, but it is quite tricky trying
- // to figure out alhabetical vs. not across encoding. So take a very
- // conservative approach.
-
- // if ( encoding == TIXML_ENCODING_UTF8 )
- // {
- if (anyByte < 127) {
- return isalpha(anyByte);
- }
- else {
- return 1; // What else to do? The unicode set is huge...get the english ones right.
- }
- // }
- // else
- // {
- // return isalpha( anyByte );
- // }
-}
-
-/*static*/ int TiXmlBase::IsAlphaNum(unsigned char anyByte, TiXmlEncoding /*encoding*/)
-{
- // This will only work for low-ascii, everything else is assumed to be a valid
- // letter. I'm not sure this is the best approach, but it is quite tricky trying
- // to figure out alhabetical vs. not across encoding. So take a very
- // conservative approach.
-
- // if ( encoding == TIXML_ENCODING_UTF8 )
- // {
- if (anyByte < 127) {
- return isalnum(anyByte);
- }
- else {
- return 1; // What else to do? The unicode set is huge...get the english ones right.
- }
- // }
- // else
- // {
- // return isalnum( anyByte );
- // }
-}
-
-class TiXmlParsingData {
- friend class TiXmlDocument;
-
-public:
- void Stamp(const char *now, TiXmlEncoding encoding);
-
- const TiXmlCursor &Cursor() { return cursor; }
-
-private:
- // Only used by the document!
- TiXmlParsingData(const char *start, int _tabsize, int row, int col)
- {
- assert(start);
- stamp = start;
- tabsize = _tabsize;
- cursor.row = row;
- cursor.col = col;
- }
-
- TiXmlCursor cursor;
- const char *stamp;
- int tabsize;
-};
-
-void TiXmlParsingData::Stamp(const char *now, TiXmlEncoding encoding)
-{
- assert(now);
-
- // Do nothing if the tabsize is 0.
- if (tabsize < 1) {
- return;
- }
-
- // Get the current row, column.
- int row = cursor.row;
- int col = cursor.col;
- const char *p = stamp;
- assert(p);
-
- while (p < now) {
- // Treat p as unsigned, so we have a happy compiler.
- const auto *pU = reinterpret_cast(p);
-
- // Code contributed by Fletcher Dunn: (modified by lee)
- switch (*pU) {
- case 0:
- // We *should* never get here, but in case we do, don't
- // advance past the terminating null character, ever
- return;
-
- case '\r':
- // bump down to the next line
- ++row;
- col = 0;
- // Eat the character
- ++p;
-
- // Check for \r\n sequence, and treat this as a single character
- if (*p == '\n') {
- ++p;
- }
- break;
-
- case '\n':
- // bump down to the next line
- ++row;
- col = 0;
-
- // Eat the character
- ++p;
-
- // Check for \n\r sequence, and treat this as a single
- // character. (Yes, this bizarre thing does occur still
- // on some arcane platforms...)
- if (*p == '\r') {
- ++p;
- }
- break;
-
- case '\t':
- // Eat the character
- ++p;
-
- // Skip to next tab stop
- col = (col / tabsize + 1) * tabsize;
- break;
-
- case TIXML_UTF_LEAD_0:
- if (encoding == TIXML_ENCODING_UTF8) {
- if (*(p + 1) && *(p + 2)) {
- // In these cases, don't advance the column. These are
- // 0-width spaces.
- if (*(pU + 1) == TIXML_UTF_LEAD_1 && *(pU + 2) == TIXML_UTF_LEAD_2) {
- p += 3;
- }
- else if (*(pU + 1) == 0xbfU && *(pU + 2) == 0xbeU) {
- p += 3;
- }
- else if (*(pU + 1) == 0xbfU && *(pU + 2) == 0xbfU) {
- p += 3;
- }
- else {
- p += 3;
- ++col;
- } // A normal character.
- }
- }
- else {
- ++p;
- ++col;
- }
- break;
-
- default:
- if (encoding == TIXML_ENCODING_UTF8) {
- // Eat the 1 to 4 byte utf8 character.
- int step = TiXmlBase::utf8ByteTable[*reinterpret_cast(p)];
- if (step == 0) {
- step = 1; // Error case from bad encoding, but handle gracefully.
- }
- p += step;
-
- // Just advance one column, of course.
- ++col;
- }
- else {
- ++p;
- ++col;
- }
- break;
- }
- }
- cursor.row = row;
- cursor.col = col;
- assert(cursor.row >= -1);
- assert(cursor.col >= -1);
- stamp = p;
- assert(stamp);
-}
-
-const char *TiXmlBase::SkipWhiteSpace(const char *p, TiXmlEncoding encoding)
-{
- if (!p || !*p) {
- return nullptr;
- }
- if (encoding == TIXML_ENCODING_UTF8) {
- while (*p) {
- const auto *pU = reinterpret_cast(p);
-
- // Skip the stupid Microsoft UTF-8 Byte order marks
- if (*(pU + 0) == TIXML_UTF_LEAD_0 && *(pU + 1) == TIXML_UTF_LEAD_1 &&
- *(pU + 2) == TIXML_UTF_LEAD_2) {
- p += 3;
- continue;
- }
- else if (*(pU + 0) == TIXML_UTF_LEAD_0 && *(pU + 1) == 0xbfU && *(pU + 2) == 0xbeU) {
- p += 3;
- continue;
- }
- else if (*(pU + 0) == TIXML_UTF_LEAD_0 && *(pU + 1) == 0xbfU && *(pU + 2) == 0xbfU) {
- p += 3;
- continue;
- }
-
- if (IsWhiteSpace(*p) || *p == '\n' || *p == '\r') { // Still using old rules for white space.
- ++p;
- }
- else {
- break;
- }
- }
- }
- else {
- while (*p && (IsWhiteSpace(*p) || *p == '\n' || *p == '\r')) {
- ++p;
- }
- }
-
- return p;
-}
-
-#ifdef TIXML_USE_STL
-/*static*/ bool TiXmlBase::StreamWhiteSpace(TIXML_ISTREAM *in, TIXML_STRING *tag)
-{
- for (;;) {
- if (!in->good()) {
- return false;
- }
-
- const int c = in->peek();
- // At this scope, we can't get to a document. So fail silently.
- if (!IsWhiteSpace(c) || c <= 0) {
- return true;
- }
-
- *tag += (char)in->get();
- }
-}
-
-/*static*/ bool TiXmlBase::StreamTo(TIXML_ISTREAM *in, int character, TIXML_STRING *tag)
-{
- // assert( character > 0 && character < 128 ); // else it won't work in utf-8
- while (in->good()) {
- const int c = in->peek();
- if (c == character) {
- return true;
- }
- if (c <= 0) { // Silent failure: can't get document at this scope
- return false;
- }
-
- in->get();
- *tag += (char)c;
- }
- return false;
-}
-#endif
-
-const char *TiXmlBase::ReadName(const char *p, TIXML_STRING *name, TiXmlEncoding encoding)
-{
- *name = "";
- assert(p);
-
- // Names start with letters or underscores.
- // Of course, in unicode, tinyxml has no idea what a letter *is*. The
- // algorithm is generous.
- //
- // After that, they can be letters, underscores, numbers,
- // hyphens, or colons. (Colons are valid ony for namespaces,
- // but tinyxml can't tell namespaces from names.)
- if (p && *p && (IsAlpha((unsigned char)*p, encoding) || *p == '_')) {
- while (p && *p &&
- (IsAlphaNum((unsigned char)*p, encoding) || *p == '_' || *p == '-' || *p == '.' ||
- *p == ':')) {
- (*name) += *p;
- ++p;
- }
- return p;
- }
- return nullptr;
-}
-
-const char *TiXmlBase::GetEntity(const char *p, char *value, int *length, TiXmlEncoding encoding)
-{
- // Presume an entity, and pull it out.
- const TIXML_STRING ent;
- int i;
- *length = 0;
-
- if (*(p + 1) && *(p + 1) == '#' && *(p + 2)) {
- unsigned long ucs = 0;
- ptrdiff_t delta = 0;
- unsigned mult = 1;
-
- if (*(p + 2) == 'x') {
- // Hexadecimal.
- if (!*(p + 3)) {
- return nullptr;
- }
-
- const char *q = p + 3;
- q = strchr(q, ';');
-
- if (!q || !*q) {
- return nullptr;
- }
-
- delta = q - p;
- --q;
-
- while (*q != 'x') {
- if (*q >= '0' && *q <= '9') {
- ucs += mult * (*q - '0');
- }
- else if (*q >= 'a' && *q <= 'f') {
- ucs += mult * (*q - 'a' + 10);
- }
- else if (*q >= 'A' && *q <= 'F') {
- ucs += mult * (*q - 'A' + 10);
- }
- else {
- return nullptr;
- }
- mult *= 16;
- --q;
- }
- }
- else {
- // Decimal.
- if (!*(p + 2)) {
- return nullptr;
- }
-
- const char *q = p + 2;
- q = strchr(q, ';');
-
- if (!q || !*q) {
- return nullptr;
- }
-
- delta = q - p;
- --q;
-
- while (*q != '#') {
- if (*q >= '0' && *q <= '9') {
- ucs += mult * (*q - '0');
- }
- else {
- return nullptr;
- }
- mult *= 10;
- --q;
- }
- }
- if (encoding == TIXML_ENCODING_UTF8) {
- // convert the UCS to UTF-8
- ConvertUTF32ToUTF8(ucs, value, length);
- }
- else {
- *value = (char)ucs;
- *length = 1;
- }
- return p + delta + 1;
- }
-
- // Now try to match it.
- for (i = 0; i < NUM_ENTITY; ++i) {
- if (strncmp(entity[i].str, p, entity[i].strLength) == 0) {
- assert(strlen(entity[i].str) == entity[i].strLength);
- *value = entity[i].chr;
- *length = 1;
- return (p + entity[i].strLength);
- }
- }
-
- // So it wasn't an entity, its unrecognized, or something like that.
- *value = *p; // Don't put back the last one, since we return it!
- return p + 1;
-}
-
-bool TiXmlBase::StringEqual(const char *p, const char *tag, bool ignoreCase,
- TiXmlEncoding encoding)
-{
- assert(p);
- assert(tag);
- if (!p || !*p) {
- assert(0);
- return false;
- }
-
- const char *q = p;
-
- if (ignoreCase) {
- while (*q && *tag && ToLower(*q, encoding) == ToLower(*tag, encoding)) {
- ++q;
- ++tag;
- }
-
- if (*tag == 0) {
- return true;
- }
- }
- else {
- while (*q && *tag && *q == *tag) {
- ++q;
- ++tag;
- }
-
- if (*tag == 0) { // Have we found the end of the tag, and everything equal?
- return true;
- }
- }
- return false;
-}
-
-const char *TiXmlBase::ReadText(const char *p, TIXML_STRING *text, bool trimWhiteSpace,
- const char *endTag, bool caseInsensitive, TiXmlEncoding encoding)
-{
- *text = "";
- if (!trimWhiteSpace // certain tags always keep whitespace
- || !condenseWhiteSpace) // if true, whitespace is always kept
- {
- // Keep all the white space.
- while (p && *p && !StringEqual(p, endTag, caseInsensitive, encoding)) {
- int len;
- char cArr[4] = {0, 0, 0, 0};
- p = GetChar(p, cArr, &len, encoding);
- text->append(cArr, len);
- }
- }
- else {
- bool whitespace = false;
-
- // Remove leading white space:
- p = SkipWhiteSpace(p, encoding);
- while (p && *p && !StringEqual(p, endTag, caseInsensitive, encoding)) {
- if (*p == '\r' || *p == '\n') {
- whitespace = true;
- ++p;
- }
- else if (IsWhiteSpace(*p)) {
- whitespace = true;
- ++p;
- }
- else {
- // If we've found whitespace, add it before the
- // new character. Any whitespace just becomes a space.
- if (whitespace) {
- (*text) += ' ';
- whitespace = false;
- }
- int len;
- char cArr[4] = {0, 0, 0, 0};
- p = GetChar(p, cArr, &len, encoding);
- if (len == 1) {
- (*text) += cArr[0]; // more efficient
- }
- else {
- text->append(cArr, len);
- }
- }
- }
- }
- return p + strlen(endTag);
-}
-
-#ifdef TIXML_USE_STL
-
-void TiXmlDocument::StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag)
-{
- // The basic issue with a document is that we don't know what we're
- // streaming. Read something presumed to be a tag (and hope), then
- // identify it, and call the appropriate stream method on the tag.
- //
- // This "pre-streaming" will never read the closing ">" so the
- // sub-tag can orient itself.
-
- if (!StreamTo(in, '<', tag)) {
- SetError(TIXML_ERROR_PARSING_EMPTY, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- return;
- }
-
- while (in->good()) {
- const int tagIndex = (int)tag->length();
- while (in->good() && in->peek() != '>') {
- const int c = in->get();
- if (c <= 0) {
- SetError(TIXML_ERROR_EMBEDDED_NULL, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- break;
- }
- (*tag) += (char)c;
- }
-
- if (in->good()) {
- // We now have something we presume to be a node of
- // some sort. Identify it, and call the node to
- // continue streaming.
- TiXmlNode *node = Identify(tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING);
-
- if (node) {
- node->StreamIn(in, tag);
- const bool isElement = node->ToElement() != nullptr;
- delete node;
- node = nullptr;
-
- // If this is the root element, we're done. Parsing will be
- // done by the >> operator.
- if (isElement) {
- return;
- }
- }
- else {
- SetError(TIXML_ERROR, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- return;
- }
- }
- }
- // We should have returned sooner.
- SetError(TIXML_ERROR, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
-}
-
-#endif
-
-const char *TiXmlDocument::Parse(const char *p, TiXmlParsingData *prevData, TiXmlEncoding encoding)
-{
- ClearError();
-
- // Parse away, at the document level. Since a document
- // contains nothing but other tags, most of what happens
- // here is skipping white space.
- if (!p || !*p) {
- SetError(TIXML_ERROR_DOCUMENT_EMPTY, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- return nullptr;
- }
-
- // Note that, for a document, this needs to come
- // before the while space skip, so that parsing
- // starts from the pointer we are given.
- location.Clear();
- if (prevData) {
- location.row = prevData->cursor.row;
- location.col = prevData->cursor.col;
- }
- else {
- location.row = 0;
- location.col = 0;
- }
- TiXmlParsingData data(p, TabSize(), location.row, location.col);
- location = data.Cursor();
-
- if (encoding == TIXML_ENCODING_UNKNOWN) {
- // Check for the Microsoft UTF-8 lead bytes.
- const auto *pU = reinterpret_cast(p);
- if (*(pU + 0) && *(pU + 0) == TIXML_UTF_LEAD_0 && *(pU + 1) && *(pU + 1) == TIXML_UTF_LEAD_1 &&
- *(pU + 2) && *(pU + 2) == TIXML_UTF_LEAD_2) {
- encoding = TIXML_ENCODING_UTF8;
- useMicrosoftBOM = true;
- }
- }
-
- p = SkipWhiteSpace(p, encoding);
- if (!p) {
- SetError(TIXML_ERROR_DOCUMENT_EMPTY, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- return nullptr;
- }
-
- while (p && *p) {
- TiXmlNode *node = Identify(p, encoding);
- if (node) {
- p = node->Parse(p, &data, encoding);
- LinkEndChild(node);
- }
- else {
- break;
- }
-
- // Did we get encoding info?
- if (encoding == TIXML_ENCODING_UNKNOWN && node->ToDeclaration()) {
- const TiXmlDeclaration *dec = node->ToDeclaration();
- const char *enc = dec->Encoding();
- assert(enc);
-
- if (*enc == 0) {
- encoding = TIXML_ENCODING_UTF8;
- }
- else if (StringEqual(enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN)) {
- encoding = TIXML_ENCODING_UTF8;
- }
- else if (StringEqual(enc, "UTF8", true, TIXML_ENCODING_UNKNOWN)) {
- encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice
- }
- else {
- encoding = TIXML_ENCODING_LEGACY;
- }
- }
-
- p = SkipWhiteSpace(p, encoding);
- }
-
- // Was this empty?
- if (!firstChild) {
- SetError(TIXML_ERROR_DOCUMENT_EMPTY, nullptr, nullptr, encoding);
- return nullptr;
- }
-
- // All is well.
- return p;
-}
-
-void TiXmlDocument::SetError(int err, const char *pError, TiXmlParsingData *data,
- TiXmlEncoding encoding)
-{
- // The first error in a chain is more accurate - don't set again!
- if (error) {
- return;
- }
-
- assert(err > 0 && err < TIXML_ERROR_STRING_COUNT);
- error = true;
- errorId = err;
- errorDesc = errorString[errorId];
-
- errorLocation.Clear();
- if (pError && data) {
- data->Stamp(pError, encoding);
- errorLocation = data->Cursor();
- }
-}
-
-TiXmlNode *TiXmlNode::Identify(const char *p, TiXmlEncoding encoding)
-{
- TiXmlNode *returnNode = nullptr;
-
- p = SkipWhiteSpace(p, encoding);
- if (!p || !*p || *p != '<') {
- return nullptr;
- }
-
- TiXmlDocument *doc = GetDocument();
- p = SkipWhiteSpace(p, encoding);
-
- if (!p || !*p) {
- return nullptr;
- }
-
- // What is this thing?
- // - Elements start with a letter or underscore, but xml is reserved.
- // - Comments: ";
-
- if (!StringEqual(p, startTag, false, encoding)) {
- document->SetError(TIXML_ERROR_PARSING_COMMENT, p, data, encoding);
- return nullptr;
- }
- p += strlen(startTag);
- p = ReadText(p, &value, false, endTag, false, encoding);
- return p;
-}
-
-const char *TiXmlAttribute::Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)
-{
- p = SkipWhiteSpace(p, encoding);
- if (!p || !*p) {
- return nullptr;
- }
-
- // int tabsize = 4;
- // if ( document ) {
- // tabsize = document->TabSize();
- // }
-
- if (data) {
- data->Stamp(p, encoding);
- location = data->Cursor();
- }
- // Read the name, the '=' and the value.
- const char *pErr = p;
- p = ReadName(p, &name, encoding);
- if (!p || !*p) {
- if (document) {
- document->SetError(TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding);
- }
- return nullptr;
- }
- p = SkipWhiteSpace(p, encoding);
- if (!p || !*p || *p != '=') {
- if (document) {
- document->SetError(TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding);
- }
- return nullptr;
- }
-
- ++p; // skip '='
- p = SkipWhiteSpace(p, encoding);
- if (!p || !*p) {
- if (document) {
- document->SetError(TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding);
- }
- return nullptr;
- }
-
- const char *end;
-
- if (*p == '\'') {
- ++p;
- end = "\'";
- p = ReadText(p, &value, false, end, false, encoding);
- }
- else if (*p == '"') {
- ++p;
- end = "\"";
- p = ReadText(p, &value, false, end, false, encoding);
- }
- else {
- // All attribute values should be in single or double quotes.
- // But this is such a common error that the parser will try
- // its best, even without them.
- value = "";
- while (p && *p // existence
- && !IsWhiteSpace(*p) && *p != '\n' && *p != '\r' // whitespace
- && *p != '/' && *p != '>') // tag end
- {
- value += *p;
- ++p;
- }
- }
- return p;
-}
-
-#ifdef TIXML_USE_STL
-void TiXmlText::StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag)
-{
- if (cdata) {
- const int c = in->get();
- if (c <= 0) {
- TiXmlDocument *document = GetDocument();
- if (document) {
- document->SetError(TIXML_ERROR_EMBEDDED_NULL, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- }
- return;
- }
-
- (*tag) += (char)c;
-
- if (c == '>' && tag->at(tag->length() - 2) == ']' && tag->at(tag->length() - 3) == ']') {
- // All is well.
- return;
- }
- }
- else {
- while (in->good()) {
- const int c = in->peek();
- if (c == '<') {
- return;
- }
- if (c <= 0) {
- TiXmlDocument *document = GetDocument();
- if (document) {
- document->SetError(TIXML_ERROR_EMBEDDED_NULL, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- }
- return;
- }
-
- (*tag) += (char)c;
- in->get();
- }
- }
-}
-#endif
-
-const char *TiXmlText::Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)
-{
- value = "";
- TiXmlDocument *document = GetDocument();
-
- if (data) {
- data->Stamp(p, encoding);
- location = data->Cursor();
- }
-
- const char *const startTag = "";
-
- if (cdata || StringEqual(p, startTag, false, encoding)) {
- cdata = true;
-
- if (!StringEqual(p, startTag, false, encoding)) {
- document->SetError(TIXML_ERROR_PARSING_CDATA, p, data, encoding);
- return nullptr;
- }
- p += strlen(startTag);
-
- // Keep all the white space, ignore the encoding, etc.
- while (p && *p && !StringEqual(p, endTag, false, encoding)) {
- value += *p;
- ++p;
- }
-
- TIXML_STRING dummy;
- p = ReadText(p, &dummy, false, endTag, false, encoding);
- return p;
- }
- else {
- const bool ignoreWhite = true;
-
- const char *end = "<";
- p = ReadText(p, &value, ignoreWhite, end, false, encoding);
- if (p) {
- return p - 1; // don't truncate the '<'
- }
- return nullptr;
- }
-}
-
-#ifdef TIXML_USE_STL
-void TiXmlDeclaration::StreamIn(TIXML_ISTREAM *in, TIXML_STRING *tag)
-{
- while (in->good()) {
- const int c = in->get();
- if (c <= 0) {
- TiXmlDocument *document = GetDocument();
- if (document) {
- document->SetError(TIXML_ERROR_EMBEDDED_NULL, nullptr, nullptr, TIXML_ENCODING_UNKNOWN);
- }
- return;
- }
- (*tag) += (char)c;
-
- if (c == '>') {
- // All is well.
- return;
- }
- }
-}
-#endif
-
-const char *TiXmlDeclaration::Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding _encoding)
-{
- p = SkipWhiteSpace(p, _encoding);
- // Find the beginning, find the end, and look for
- // the stuff in-between.
- TiXmlDocument *document = GetDocument();
- if (!p || !*p || !StringEqual(p, "SetError(TIXML_ERROR_PARSING_DECLARATION, nullptr, nullptr, _encoding);
- }
- return nullptr;
- }
- if (data) {
- data->Stamp(p, _encoding);
- location = data->Cursor();
- }
- p += 5;
-
- version = "";
- encoding = "";
- standalone = "";
-
- while (p && *p) {
- if (*p == '>') {
- ++p;
- return p;
- }
-
- p = SkipWhiteSpace(p, _encoding);
- if (StringEqual(p, "version", true, _encoding)) {
- TiXmlAttribute attrib;
- p = attrib.Parse(p, data, _encoding);
- version = attrib.Value();
- }
- else if (StringEqual(p, "encoding", true, _encoding)) {
- TiXmlAttribute attrib;
- p = attrib.Parse(p, data, _encoding);
- encoding = attrib.Value();
- }
- else if (StringEqual(p, "standalone", true, _encoding)) {
- TiXmlAttribute attrib;
- p = attrib.Parse(p, data, _encoding);
- standalone = attrib.Value();
- }
- else {
- // Read over whatever it is.
- while (p && *p && *p != '>' && !IsWhiteSpace(*p)) {
- ++p;
- }
- }
- }
- return nullptr;
-}
-
-bool TiXmlText::Blank() const
-{
- for (const char c : value) {
- if (!IsWhiteSpace(c)) {
- return false;
- }
- }
- return true;
-}
diff --git a/src/games/agg/agg.cc b/src/games/agg/agg.cc
index f5f1a2ba85..91e495c88c 100644
--- a/src/games/agg/agg.cc
+++ b/src/games/agg/agg.cc
@@ -152,6 +152,10 @@ std::shared_ptr AGG::makeAGG(istream &in)
if (!in.good()) {
throw std::runtime_error("Error reading the number of function nodes");
}
+ if (n <= 0 || S < 0 || P < 0) {
+ throw std::runtime_error("Error in game file: invalid AGG header (number of players, "
+ "action nodes, or function nodes out of range)");
+ }
stripComment(in);
// enter sizes of action sets:
diff --git a/src/games/agg/bagg.cc b/src/games/agg/bagg.cc
index ab58e63b6d..12d36de06a 100644
--- a/src/games/agg/bagg.cc
+++ b/src/games/agg/bagg.cc
@@ -73,18 +73,22 @@ std::shared_ptr BAGG::makeBAGG(istream &in)
in >> S;
stripComment(in);
in >> P;
+ if (!in || N <= 0 || S < 0 || P < 0) {
+ throw std::runtime_error("Error in game file: expected BAGG header with number of "
+ "players, action nodes, and function nodes");
+ }
stripComment(in);
vector numTypes(N);
// input number of types for each player
for (int i = 0; i < N; ++i) {
- if (in.eof() || in.bad()) {
+ in >> numTypes[i];
+ if (!in) {
throw std::runtime_error(
"Error in game file: integer expected for the number of types for player " +
std::to_string(i));
}
- in >> numTypes[i];
}
// input the type distributions
@@ -93,10 +97,10 @@ std::shared_ptr BAGG::makeBAGG(istream &in)
for (int i = 0; i < N; ++i) {
TDist.emplace_back(numTypes[i]);
for (int j = 0; j < numTypes[i]; ++j) {
- if (in.eof() || in.bad()) {
+ in >> TDist[i][j];
+ if (!in) {
throw std::runtime_error("Error in game file: number expected for type distribution");
}
- in >> TDist[i][j];
}
}
@@ -105,12 +109,12 @@ std::shared_ptr BAGG::makeBAGG(istream &in)
vector>> typeActionSets(N);
for (int i = 0; i < N; ++i) {
for (int j = 0; j < numTypes[i]; ++j) {
- if (in.eof() || in.bad()) {
+ int temp;
+ in >> temp;
+ if (!in || temp < 0) {
throw std::runtime_error(
"Error in game file: integer expected for size of type action set");
}
- int temp;
- in >> temp;
typeActionSets[i].emplace_back(temp);
}
}
@@ -120,10 +124,10 @@ std::shared_ptr BAGG::makeBAGG(istream &in)
for (int i = 0; i < N; ++i) {
for (int j = 0; j < numTypes[i]; ++j) {
for (int &el : typeActionSets[i][j]) {
- if (in.eof() || in.bad()) {
+ in >> el;
+ if (!in) {
throw std::runtime_error("Error in game file: integer expected for type action set");
}
- in >> el;
}
}
}
diff --git a/src/games/file.cc b/src/games/file.cc
index ea033eebf4..db2adc1b5e 100644
--- a/src/games/file.cc
+++ b/src/games/file.cc
@@ -23,6 +23,7 @@
#include
#include
#include