mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-14 07:23:23 -05:00
feat: report pack contents instead of list coverage
This commit is contained in:
1 parent
38d8e78eb3
commit
b586eddb2a
3 files changed
+151
-99
No files matched your search
@@ -32,20 +32,20 @@ The script auto-detects your platform, downloads only missing files, and verifie
|
|||||||
|
|
||||||
Pick your platform, download the ZIP, extract to the BIOS path.
|
Pick your platform, download the ZIP, extract to the BIOS path.
|
||||||
|
|
||||||
| Platform | BIOS files | Extract to | Download |
|
| Platform | Size | Extract to | Download |
|
||||||
|----------|-----------|-----------|----------|
|
|----------|------|-----------|----------|
|
||||||
| Batocera | 353 | `/userdata/bios/` | [Download](../../releases/latest) |
|
| Batocera | 2.7 GB | `/userdata/bios/` | [Download](../../releases/latest) |
|
||||||
| BizHawk | 118 | `Firmware/` | [Download](../../releases/latest) |
|
| BizHawk | 2.4 GB | `Firmware/` | [Download](../../releases/latest) |
|
||||||
| EmuDeck | 161 | `~/Emulation/bios/` | [Download](../../releases/latest) |
|
| EmuDeck | 1.6 GB | `~/Emulation/bios/` | [Download](../../releases/latest) |
|
||||||
| Lakka | 530 | `/storage/system/` | [Download](../../releases/latest) |
|
| Lakka | 3.9 GB | `/storage/system/` | [Download](../../releases/latest) |
|
||||||
| MiSTer FPGA | 65 | `/media/fat/games/` | [Download](../../releases/latest) |
|
| MiSTer FPGA | 23 MB | `/media/fat/games/` | [Download](../../releases/latest) |
|
||||||
| ROCKNIX | 38 | `/storage/roms/bios/` | [Download](../../releases/latest) |
|
| ROCKNIX | 3.8 GB | `/storage/roms/bios/` | [Download](../../releases/latest) |
|
||||||
| Recalbox | 346 | `/recalbox/share/bios/` | [Download](../../releases/latest) |
|
| Recalbox | 2.3 GB | `/recalbox/share/bios/` | [Download](../../releases/latest) |
|
||||||
| RetroArch | 530 | `system/` | [Download](../../releases/latest) |
|
| RetroArch | 3.9 GB | `system/` | [Download](../../releases/latest) |
|
||||||
| RetroBat | 341 | `bios/` | [Download](../../releases/latest) |
|
| RetroBat | 3.1 GB | `bios/` | [Download](../../releases/latest) |
|
||||||
| RetroDECK | 2008 | `~/retrodeck/` | [Download](../../releases/latest) |
|
| RetroDECK | 4.6 GB | `~/retrodeck/` | [Download](../../releases/latest) |
|
||||||
| RetroPie * | 530 | `~/RetroPie/BIOS/` | [Download](../../releases/latest) |
|
| RetroPie * | - | `~/RetroPie/BIOS/` | [Download](../../releases/latest) |
|
||||||
| RomM | 374 | `bios/{platform_slug}/` | [Download](../../releases/latest) |
|
| RomM | 1.4 GB | `bios/{platform_slug}/` | [Download](../../releases/latest) |
|
||||||
|
|
||||||
The RetroDECK pack already contains its own `bios/` folder, so it extracts into `~/retrodeck/` rather than into the BIOS folder.
|
The RetroDECK pack already contains its own `bios/` folder, so it extracts into `~/retrodeck/` rather than into the BIOS folder.
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ BIOS, firmware, and system files for consoles from Atari to PlayStation 3.
|
|||||||
Every file passes its platform's own verification; where an emulator profile exists, the expected hashes and sizes are read from the emulator's source code (the Source-backed column below).
|
Every file passes its platform's own verification; where an emulator profile exists, the expected hashes and sizes are read from the emulator's source code (the Source-backed column below).
|
||||||
|
|
||||||
- **12 platforms** supported with platform-specific verification
|
- **12 platforms** supported with platform-specific verification
|
||||||
- **318 emulators** profiled from source (RetroArch cores + standalone)
|
- **320 emulators** profiled from source (RetroArch cores + standalone)
|
||||||
- **396 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
|
- **396 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
|
||||||
- **7,651 files** indexed with SHA1, MD5, SHA256 and CRC32 checksums: 2,366 system files, 2,746 arcade ROM sets, 2,539 game and engine data files
|
- **7,651 files** indexed with SHA1, MD5, SHA256 and CRC32 checksums: 2,366 system files, 2,746 arcade ROM sets, 2,539 game and engine data files
|
||||||
- **527 files** matched to dump-preservation catalogs (No-Intro, Redump, TOSEC)
|
- **527 files** matched to dump-preservation catalogs (No-Intro, Redump, TOSEC)
|
||||||
@@ -71,24 +71,24 @@ Full list with per-file details: **[https://abdess.github.io/retrobios/](https:/
|
|||||||
|
|
||||||
## Coverage
|
## Coverage
|
||||||
|
|
||||||
| Platform | Coverage | Verified | Untested | Missing | Source-backed |
|
| Platform | Files in pack | Still missing | Verified by |
|
||||||
|----------|----------|----------|----------|---------|---------------|
|
|----------|--------------:|--------------:|-------------|
|
||||||
| Batocera | 353/353 (100.0%) | 353 | 0 | 0 | 96/353 (27%) |
|
| Batocera | 1,601 | 4 | MD5 hash |
|
||||||
| BizHawk | 118/118 (100.0%) | 118 | 0 | 0 | 4/118 (3%) |
|
| BizHawk | 539 | 5 | SHA1 hash |
|
||||||
| EmuDeck | 161/161 (100.0%) | 161 | 0 | 0 | 16/161 (10%) |
|
| EmuDeck | 525 | 0 | MD5 hash |
|
||||||
| Lakka | 530/530 (100.0%) | 530 | 0 | 0 | 124/530 (23%) |
|
| Lakka | 1,631 | 4 | file presence |
|
||||||
| MiSTer FPGA | 65/65 (100.0%) | 65 | 0 | 0 | - |
|
| MiSTer FPGA | 65 | 0 | MD5 hash |
|
||||||
| ROCKNIX | 38/38 (100.0%) | 38 | 0 | 0 | 29/38 (76%) |
|
| ROCKNIX | 1,496 | 5 | MD5 hash |
|
||||||
| Recalbox | 346/346 (100.0%) | 346 | 0 | 0 | 86/346 (25%) |
|
| Recalbox | 1,184 | 6 | MD5 hash |
|
||||||
| RetroArch | 530/530 (100.0%) | 530 | 0 | 0 | 124/530 (23%) |
|
| RetroArch | 1,631 | 4 | file presence |
|
||||||
| RetroBat | 341/341 (100.0%) | 341 | 0 | 0 | 84/341 (25%) |
|
| RetroBat | 1,235 | 4 | MD5 hash |
|
||||||
| RetroDECK | 2008/2008 (100.0%) | 2008 | 0 | 0 | 121/2008 (6%) |
|
| RetroDECK | 3,266 | 4 | MD5 hash |
|
||||||
| RetroPie * | 530/530 (100.0%) | 530 | 0 | 0 | 124/530 (23%) |
|
| RetroPie * | 1,678 | 4 | file presence |
|
||||||
| RomM | 374/374 (100.0%) | 374 | 0 | 0 | 88/374 (24%) |
|
| RomM | 543 | 4 | MD5 hash |
|
||||||
|
|
||||||
Coverage is measured against the file list each platform declares, using that platform's own verification mode.
|
A pack carries what the platform declares plus what its emulators load without the platform listing it, so it holds more files than the platform's own list.
|
||||||
Source-backed counts the files whose content the emulator's own code checks: a size or hash read from its source, reproduced at verification. A dash means no profiled emulator applies to the platform, whose own source is then the only authority.
|
Still missing counts files an emulator needs that are not in the collection yet; verified by is the check the platform itself runs on them.
|
||||||
The [gap analysis](https://abdess.github.io/retrobios/gaps/) page counts separately the files a profile documents without a content check, and tracks where platform lists and emulator source code disagree.
|
The [gap analysis](https://abdess.github.io/retrobios/gaps/) page names those missing files and details how far each platform's files are corroborated against emulator source code.
|
||||||
|
|
||||||
## Build your own pack
|
## Build your own pack
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ The [documentation site](https://abdess.github.io/retrobios/) provides:
|
|||||||
- **Per-emulator profiles** with source code references for every file
|
- **Per-emulator profiles** with source code references for every file
|
||||||
- **Per-system pages** showing which emulators and platforms cover each console
|
- **Per-system pages** showing which emulators and platforms cover each console
|
||||||
- **Gap analysis** identifying missing files and undeclared core requirements
|
- **Gap analysis** identifying missing files and undeclared core requirements
|
||||||
- **Cross-reference** mapping files across 12 platforms and 318 emulators
|
- **Cross-reference** mapping files across 12 platforms and 320 emulators
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
@@ -161,4 +161,4 @@ The scripts and tooling are released under the [MIT License](LICENSE).
|
|||||||
The BIOS and firmware files are not covered by that license: they are third-party system software, preserved and provided for personal backup, archival, and interoperability with emulation software.
|
The BIOS and firmware files are not covered by that license: they are third-party system software, preserved and provided for personal backup, archival, and interoperability with emulation software.
|
||||||
The legal reasoning is laid out in the [FAQ](https://abdess.github.io/retrobios/wiki/faq/#is-this-legal).
|
The legal reasoning is laid out in the [FAQ](https://abdess.github.io/retrobios/wiki/faq/#is-this-legal).
|
||||||
|
|
||||||
*Auto-generated on 2026-08-08T02:07:01Z*
|
*Auto-generated on 2026-08-08T03:39:12Z*
|
||||||
+59
-26
@@ -51,6 +51,9 @@ def compute_coverage(
|
|||||||
total = result["total_files"]
|
total = result["total_files"]
|
||||||
present = ok + untested
|
present = ok + untested
|
||||||
pct = (present / total * 100) if total > 0 else 0
|
pct = (present / total * 100) if total > 0 else 0
|
||||||
|
undeclared = result.get("undeclared_files", [])
|
||||||
|
core_present = sum(1 for u in undeclared if u.get("in_repo"))
|
||||||
|
core_missing = len(undeclared) - core_present
|
||||||
return {
|
return {
|
||||||
"platform": config.get("platform", platform_name),
|
"platform": config.get("platform", platform_name),
|
||||||
"total": total,
|
"total": total,
|
||||||
@@ -59,6 +62,10 @@ def compute_coverage(
|
|||||||
"missing": missing,
|
"missing": missing,
|
||||||
"present": present,
|
"present": present,
|
||||||
"percentage": pct,
|
"percentage": pct,
|
||||||
|
"core_present": core_present,
|
||||||
|
"core_missing": core_missing,
|
||||||
|
"pack_files": present + core_present,
|
||||||
|
"total_missing": missing + core_missing,
|
||||||
"mode": config.get("verification_mode", "existence"),
|
"mode": config.get("verification_mode", "existence"),
|
||||||
"details": result["details"],
|
"details": result["details"],
|
||||||
"config": config,
|
"config": config,
|
||||||
@@ -69,6 +76,33 @@ def compute_coverage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def manifest_totals(
|
||||||
|
platform_name: str, install_dir: str = "install"
|
||||||
|
) -> tuple[int | None, int | None]:
|
||||||
|
"""Files and bytes a platform's pack ships, from its install manifest.
|
||||||
|
|
||||||
|
The manifest is written when packs are built, so it reflects the real
|
||||||
|
pack contents (platform list, core complement and data directories).
|
||||||
|
Returns (None, None) when no manifest exists yet.
|
||||||
|
"""
|
||||||
|
path = os.path.join(install_dir, f"{platform_name}.json")
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return None, None
|
||||||
|
try:
|
||||||
|
with open(path) as f:
|
||||||
|
manifest = json.load(f)
|
||||||
|
except (json.JSONDecodeError, OSError):
|
||||||
|
return None, None
|
||||||
|
return manifest.get("total_files"), manifest.get("total_size")
|
||||||
|
|
||||||
|
|
||||||
|
def format_size(size: int) -> str:
|
||||||
|
"""Human-readable pack size."""
|
||||||
|
if size >= 1024**3:
|
||||||
|
return f"{size / 1024**3:.1f} GB"
|
||||||
|
return f"{size / 1024**2:.0f} MB"
|
||||||
|
|
||||||
|
|
||||||
SITE_URL = "https://abdess.github.io/retrobios/"
|
SITE_URL = "https://abdess.github.io/retrobios/"
|
||||||
RELEASE_URL = "../../releases/latest"
|
RELEASE_URL = "../../releases/latest"
|
||||||
REPO = "Abdess/retrobios"
|
REPO = "Abdess/retrobios"
|
||||||
@@ -195,8 +229,8 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
|
|||||||
"",
|
"",
|
||||||
"Pick your platform, download the ZIP, extract to the BIOS path.",
|
"Pick your platform, download the ZIP, extract to the BIOS path.",
|
||||||
"",
|
"",
|
||||||
"| Platform | BIOS files | Extract to | Download |",
|
"| Platform | Size | Extract to | Download |",
|
||||||
"|----------|-----------|-----------|----------|",
|
"|----------|------|-----------|----------|",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Where the pack itself is extracted, which is not always the BIOS folder:
|
# Where the pack itself is extracted, which is not always the BIOS folder:
|
||||||
@@ -227,8 +261,10 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
|
|||||||
if name in archived:
|
if name in archived:
|
||||||
display = f"{display} *"
|
display = f"{display} *"
|
||||||
path = extract_paths.get(cov["platform"], "")
|
path = extract_paths.get(cov["platform"], "")
|
||||||
|
_, size = manifest_totals(name)
|
||||||
|
size_cell = format_size(size) if size else "-"
|
||||||
lines.append(
|
lines.append(
|
||||||
f"| {display} | {cov['total']} | {path} | [Download]({RELEASE_URL}) |"
|
f"| {display} | {size_cell} | {path} | [Download]({RELEASE_URL}) |"
|
||||||
)
|
)
|
||||||
|
|
||||||
if archived:
|
if archived:
|
||||||
@@ -313,40 +349,37 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
|
|||||||
"",
|
"",
|
||||||
"## Coverage",
|
"## Coverage",
|
||||||
"",
|
"",
|
||||||
"| Platform | Coverage | Verified | Untested | Missing | Source-backed |",
|
"| Platform | Files in pack | Still missing | Verified by |",
|
||||||
"|----------|----------|----------|----------|---------|---------------|",
|
"|----------|--------------:|--------------:|-------------|",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mode_labels = {
|
||||||
|
"md5": "MD5 hash",
|
||||||
|
"sha1": "SHA1 hash",
|
||||||
|
"existence": "file presence",
|
||||||
|
}
|
||||||
|
|
||||||
for name, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]):
|
for name, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]):
|
||||||
pct = f"{cov['percentage']:.1f}%"
|
|
||||||
gt = cov["ground_truth"]
|
|
||||||
if not gt.get("applicable", True):
|
|
||||||
gt_cell = "-"
|
|
||||||
elif gt["total"]:
|
|
||||||
gt_pct = f"{gt['with_validation'] / gt['total'] * 100:.0f}%"
|
|
||||||
gt_cell = f"{gt['with_validation']}/{gt['total']} ({gt_pct})"
|
|
||||||
else:
|
|
||||||
gt_cell = "0/0"
|
|
||||||
display = f"{cov['platform']} *" if name in archived else cov["platform"]
|
display = f"{cov['platform']} *" if name in archived else cov["platform"]
|
||||||
|
files = manifest_totals(name)[0] or cov["pack_files"]
|
||||||
|
checked = mode_labels.get(cov["mode"], cov["mode"])
|
||||||
lines.append(
|
lines.append(
|
||||||
f"| {display} | {cov['present']}/{cov['total']} ({pct}) | "
|
f"| {display} | {files:,} | {cov['total_missing']} | {checked} |"
|
||||||
f"{cov['verified']} | {cov['untested']} | {cov['missing']} | "
|
|
||||||
f"{gt_cell} |"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
lines.extend(
|
lines.extend(
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
"Coverage is measured against the file list each platform declares,"
|
"A pack carries what the platform declares plus what its emulators"
|
||||||
" using that platform's own verification mode.",
|
" load without the platform listing it, so it holds more files than"
|
||||||
"Source-backed counts the files whose content the emulator's own"
|
" the platform's own list.",
|
||||||
" code checks: a size or hash read from its source, reproduced at"
|
"Still missing counts files an emulator needs that are not in the"
|
||||||
" verification. A dash means no profiled emulator applies to the"
|
" collection yet; verified by is the check the platform itself runs"
|
||||||
" platform, whose own source is then the only authority.",
|
" on them.",
|
||||||
f"The [gap analysis]({SITE_URL}gaps/) page counts separately the"
|
f"The [gap analysis]({SITE_URL}gaps/) page names those missing files"
|
||||||
" files a profile documents without a content check, and tracks"
|
" and details how far each platform's files are corroborated against"
|
||||||
" where platform lists and emulator source code disagree.",
|
" emulator source code.",
|
||||||
"",
|
"",
|
||||||
"## Build your own pack",
|
"## Build your own pack",
|
||||||
"",
|
"",
|
||||||
|
|||||||
+58
-39
@@ -32,7 +32,7 @@ from common import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
yaml = require_yaml()
|
yaml = require_yaml()
|
||||||
from generate_readme import compute_coverage
|
from generate_readme import compute_coverage, manifest_totals
|
||||||
from provenance_report import build_report
|
from provenance_report import build_report
|
||||||
|
|
||||||
DOCS_DIR = "docs"
|
DOCS_DIR = "docs"
|
||||||
@@ -1731,58 +1731,77 @@ def generate_gap_analysis(
|
|||||||
# ---- Verification per platform ----
|
# ---- Verification per platform ----
|
||||||
|
|
||||||
lines.extend([
|
lines.extend([
|
||||||
"## Verification by Platform",
|
"## What Each Pack Contains",
|
||||||
"",
|
"",
|
||||||
"| Platform | Files | Verified | Untested | Missing | Mode | Profiled | Source-backed |",
|
"| Platform | Files in pack | Declared by platform | Still missing | Verified by |",
|
||||||
"|----------|------:|---------:|---------:|--------:|------|---------:|--------------:|",
|
"|----------|--------------:|---------------------:|--------------:|-------------|",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
mode_labels = {
|
||||||
|
"md5": "MD5 hash",
|
||||||
|
"sha1": "SHA1 hash",
|
||||||
|
"existence": "file presence",
|
||||||
|
}
|
||||||
|
|
||||||
for pname, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]):
|
for pname, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]):
|
||||||
display = cov["platform"]
|
display = cov["platform"]
|
||||||
m = cov["missing"]
|
gone = cov["total_missing"]
|
||||||
u = cov["untested"]
|
|
||||||
missing_str = (
|
missing_str = (
|
||||||
f'<span class="rb-badge rb-badge-danger">{m}</span>'
|
f'<span class="rb-badge rb-badge-danger">{gone}</span>'
|
||||||
if m > 0
|
if gone > 0
|
||||||
else '<span class="rb-badge rb-badge-success">0</span>'
|
else '<span class="rb-badge rb-badge-success">0</span>'
|
||||||
)
|
)
|
||||||
untested_str = (
|
files = manifest_totals(pname)[0] or cov["pack_files"]
|
||||||
f'<span class="rb-badge rb-badge-warning">{u}</span>'
|
|
||||||
if u > 0
|
|
||||||
else str(u)
|
|
||||||
)
|
|
||||||
gt = cov["ground_truth"]
|
|
||||||
if not gt.get("applicable", True):
|
|
||||||
gt_cell = prof_cell = "-"
|
|
||||||
elif gt["total"]:
|
|
||||||
gt_pct = f"{gt['with_validation'] / gt['total'] * 100:.0f}%"
|
|
||||||
gt_cell = f"{gt['with_validation']}/{gt['total']} ({gt_pct})"
|
|
||||||
prof_pct = f"{gt.get('with_profile', 0) / gt['total'] * 100:.0f}%"
|
|
||||||
prof_cell = f"{gt.get('with_profile', 0)}/{gt['total']} ({prof_pct})"
|
|
||||||
else:
|
|
||||||
gt_cell = prof_cell = "0/0"
|
|
||||||
lines.append(
|
lines.append(
|
||||||
f"| [{display}](platforms/{pname}.md) "
|
f"| [{display}](platforms/{pname}.md) "
|
||||||
f"| {cov['total']} "
|
f"| {files:,} "
|
||||||
f"| {cov['verified']} "
|
f"| {cov['present']:,} "
|
||||||
f"| {untested_str} "
|
|
||||||
f"| {missing_str} "
|
f"| {missing_str} "
|
||||||
f"| {cov['mode']} "
|
f"| {mode_labels.get(cov['mode'], cov['mode'])} |"
|
||||||
f"| {prof_cell} "
|
|
||||||
f"| {gt_cell} |"
|
|
||||||
)
|
)
|
||||||
lines.extend([
|
lines.extend([
|
||||||
"",
|
"",
|
||||||
"Verification follows each platform's own runtime check "
|
"A pack carries the platform's own file list plus every file its "
|
||||||
"([how each mode works](wiki/verification-modes.md)): the counts "
|
"emulators load without that list mentioning them, which is why it "
|
||||||
"measure the repository against the file list each platform declares. "
|
"ships several times what the platform declares. Still missing counts "
|
||||||
"Profiled counts the files documented in an emulator profile (name or "
|
"files an emulator needs that are not in the collection yet, named in "
|
||||||
"alias read from source). Source-backed is stricter: the emulator's "
|
"the sections below. Verified by is the check the platform runs at "
|
||||||
"own code checks the file's content (a size or hash read from its "
|
"runtime, replicated here "
|
||||||
"source, reproduced at verification). A file can be profiled without "
|
"([how each mode works](wiki/verification-modes.md)).",
|
||||||
"being source-backed when the code loads it but never checks it. "
|
"",
|
||||||
"A dash means no profiled emulator applies to the platform, whose "
|
"## Corroboration Against Emulator Source",
|
||||||
"own source is then the only authority.",
|
"",
|
||||||
|
"| Platform | Declared by platform | Profiled | Content checked by emulator code |",
|
||||||
|
"|----------|---------------------:|---------:|---------------------------------:|",
|
||||||
|
])
|
||||||
|
|
||||||
|
for pname, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]):
|
||||||
|
gt = cov["ground_truth"]
|
||||||
|
if not gt.get("applicable", True):
|
||||||
|
prof_cell = gt_cell = "-"
|
||||||
|
elif gt["total"]:
|
||||||
|
prof_pct = f"{gt.get('with_profile', 0) / gt['total'] * 100:.0f}%"
|
||||||
|
prof_cell = f"{gt.get('with_profile', 0)} ({prof_pct})"
|
||||||
|
gt_pct = f"{gt['with_validation'] / gt['total'] * 100:.0f}%"
|
||||||
|
gt_cell = f"{gt['with_validation']} ({gt_pct})"
|
||||||
|
else:
|
||||||
|
prof_cell = gt_cell = "0"
|
||||||
|
lines.append(
|
||||||
|
f"| [{cov['platform']}](platforms/{pname}.md) "
|
||||||
|
f"| {gt['total']:,} | {prof_cell} | {gt_cell} |"
|
||||||
|
)
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
"Both columns count the files a platform declares. Profiled means the "
|
||||||
|
"file is documented in an emulator profile read from source. Content "
|
||||||
|
"checked is stricter: the emulator's code verifies a size or hash for "
|
||||||
|
"it, and this tool reproduces that check. The gap between the two is "
|
||||||
|
"not a defect, it is what the emulator code does: many emulators load "
|
||||||
|
"a file without ever checking its content, and no amount of profiling "
|
||||||
|
"can invent a check the code does not perform. A dash means no "
|
||||||
|
"profiled emulator applies to the platform, whose own source is then "
|
||||||
|
"the only authority.",
|
||||||
"",
|
"",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user