From e9c8f1fd72811883e2895d121f38f8b9c5e5c866 Mon Sep 17 00:00:00 2001 From: Xavier Roche Date: Wed, 23 Sep 2026 12:33:42 +0200 Subject: [PATCH 1/4] The winprofile doc treats Android's live MaxRate=25000 as history httrack-android's OptionsMapper.java carries a fieldsDefaults row seeding MaxRate to 25000, and initializeMap() puts it into every fresh project. Its own golden argv records -A25000 for a run that sets no transfer rate, and WinProfileOmissionTest asserts the value reaches every saved profile. The paragraph called the literal MaxRate=25000 a thing old profiles carry, so it read a live writer as an old file. Two neighbouring claims went with it: the front ends no longer all "pass nothing at all", and "Both cells describe the target rather than WebHTTrack today" named the wrong front end once Android turned out to diverge too. Signed-off-by: Xavier Roche Co-authored-by: Claude Opus 5 (1M context) Signed-off-by: Xavier Roche --- doc/winprofile-ini.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/winprofile-ini.md b/doc/winprofile-ini.md index b0f7fa66b..e12ba7a90 100644 --- a/doc/winprofile-ini.md +++ b/doc/winprofile-ini.md @@ -43,7 +43,7 @@ Android spells three keys that already had WinHTTrack names differently: `ProxyP `Dos` is the one key that is not a number, a checkbox or a list. WinHTTrack packs two independent boxes into it, `m_dos | (m_iso9660 << 1)`, and reads them back with `& 1` and `& 2`, so it alone can write 3. The other two lose it in different places. WebHTTrack has no "both" entry, so it shows 3 as DOS names and drops the ISO bit on re-save; Android decodes only an exact `1`, so 2 and 3 arrive as neither. `Dos=0` is neither box and so means long names, not DOS names, which is why a front end that cannot show 3 must fall back on 1: storing 0 turns the setting into its opposite on the next reopen. Both bits set means DOS names on every side, since that is the precedence WinHTTrack applies when it builds `-L`. -A `default_state` of `none` means do not substitute one. `MaxRate`, `Sockets` and `MaxRetryAfter` carry it: a reader that fills in 100000 for an absent `MaxRate` passes `-A100000` where the front ends pass nothing at all, and the two mirror differently as soon as the engine's own default moves or `bypass_limits` applies. httrack-windows dropped its reader default in #105 for that reason, since a substituted value cannot be told from a chosen one once it reaches a file. The old profiles carrying a literal `MaxRate=25000` nobody chose are the same lesson from the far end. Both cells describe the target rather than WebHTTrack today: `initInt` still seeds `maxrate` and `connexion` (`src/htsserver.c`), so here an absent key still yields `--max-rate=100000` where an empty one yields no flag at all, and the two coincide only once those seeds go. `tests/324_winprofile-table.test` asserts the seeds so the rows are corrected when they do. `MaxRetryAfter` needs no such correction. Nothing seeds it here, so an empty key passes no flag and the engine's own 60 seconds apply. +A `default_state` of `none` means do not substitute one. `MaxRate`, `Sockets` and `MaxRetryAfter` carry it: a reader that fills in 100000 for an absent `MaxRate` passes `-A100000` where a front end holding no value passes nothing at all, and the two mirror differently as soon as the engine's own default moves or `bypass_limits` applies. httrack-windows dropped its reader default in #105 for that reason, since a substituted value cannot be told from a chosen one once it reaches a file. HTTrack for Android still writes it. `fieldsDefaults` seeds `MaxRate` to `25000` (`OptionsMapper.java`), so a project nobody edited carries `-A25000` on its command line and `MaxRate=25000` in its profile. That file's own `NO_DEFAULT[]` table names `MaxRate` all the same, so its two halves disagree. The `MaxRate` and `Sockets` cells describe the target rather than what the front ends do today: `initInt` still seeds `maxrate` and `connexion` (`src/htsserver.c`), so here an absent key still yields `--max-rate=100000` where an empty one yields no flag at all, and the two coincide only once those seeds go. `tests/324_winprofile-table.test` asserts the seeds so the rows are corrected when they do. `MaxRetryAfter` needs no such correction. Nothing seeds it here, so an empty key passes no flag and the engine's own 60 seconds apply. `CurrentPath1` and `CurrentPath2` have no writer at all. WinHTTrack reads them live; its own write sites are commented out and neither other front end produces them. A front end that starts writing either will be consumed there, and the `owners` column cannot say so, since it names writers. From a8ab6f83db868912503c872a5ca7c6c3a0213b82 Mon Sep 17 00:00:00 2001 From: Xavier Roche Date: Wed, 23 Sep 2026 12:39:00 +0200 Subject: [PATCH 2/4] The Android seed also changes what another front end's profile means The httrack-android session corrected the mechanism. ourDefaults() has one call site, inside serialize(), so it is the writer's omission table and never runs on a load. The reader substitution comes from HTTrackActivity.java loading a project with resetMap(), which seeds MaxRate to 25000, and then unserialize(), which overlays only the keys the file states. That makes the effect cross-repository, which is what this document is for: a winprofile.ini written by WinHTTrack or WebHTTrack without a MaxRate line opens there as a 25000 cap rather than as no cap. Android's own profiles are unaffected, because absentMeansSame() gives NO_DEFAULT priority and always writes the key. Verified against httrack-android through the GitHub API, not a checkout. Signed-off-by: Xavier Roche Co-authored-by: Claude Opus 5 (1M context) Signed-off-by: Xavier Roche --- doc/winprofile-ini.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/winprofile-ini.md b/doc/winprofile-ini.md index e12ba7a90..40acd9b97 100644 --- a/doc/winprofile-ini.md +++ b/doc/winprofile-ini.md @@ -43,7 +43,7 @@ Android spells three keys that already had WinHTTrack names differently: `ProxyP `Dos` is the one key that is not a number, a checkbox or a list. WinHTTrack packs two independent boxes into it, `m_dos | (m_iso9660 << 1)`, and reads them back with `& 1` and `& 2`, so it alone can write 3. The other two lose it in different places. WebHTTrack has no "both" entry, so it shows 3 as DOS names and drops the ISO bit on re-save; Android decodes only an exact `1`, so 2 and 3 arrive as neither. `Dos=0` is neither box and so means long names, not DOS names, which is why a front end that cannot show 3 must fall back on 1: storing 0 turns the setting into its opposite on the next reopen. Both bits set means DOS names on every side, since that is the precedence WinHTTrack applies when it builds `-L`. -A `default_state` of `none` means do not substitute one. `MaxRate`, `Sockets` and `MaxRetryAfter` carry it: a reader that fills in 100000 for an absent `MaxRate` passes `-A100000` where a front end holding no value passes nothing at all, and the two mirror differently as soon as the engine's own default moves or `bypass_limits` applies. httrack-windows dropped its reader default in #105 for that reason, since a substituted value cannot be told from a chosen one once it reaches a file. HTTrack for Android still writes it. `fieldsDefaults` seeds `MaxRate` to `25000` (`OptionsMapper.java`), so a project nobody edited carries `-A25000` on its command line and `MaxRate=25000` in its profile. That file's own `NO_DEFAULT[]` table names `MaxRate` all the same, so its two halves disagree. The `MaxRate` and `Sockets` cells describe the target rather than what the front ends do today: `initInt` still seeds `maxrate` and `connexion` (`src/htsserver.c`), so here an absent key still yields `--max-rate=100000` where an empty one yields no flag at all, and the two coincide only once those seeds go. `tests/324_winprofile-table.test` asserts the seeds so the rows are corrected when they do. `MaxRetryAfter` needs no such correction. Nothing seeds it here, so an empty key passes no flag and the engine's own 60 seconds apply. +A `default_state` of `none` means do not substitute one. `MaxRate`, `Sockets` and `MaxRetryAfter` carry it: a reader that fills in 100000 for an absent `MaxRate` passes `-A100000` where a front end holding no value passes nothing at all, and the two mirror differently as soon as the engine's own default moves or `bypass_limits` applies. httrack-windows dropped its reader default in #105 for that reason, since a substituted value cannot be told from a chosen one once it reaches a file. HTTrack for Android still writes it. `fieldsDefaults` seeds `MaxRate` to `25000` (`OptionsMapper.java`), so a project nobody edited carries `-A25000` on its command line and `MaxRate=25000` in its profile. That file's own `NO_DEFAULT[]` table names `MaxRate` all the same, so its two halves disagree. Its own profiles are safe, because `absentMeansSame()` gives `NO_DEFAULT` priority and the key is always written. A profile from WinHTTrack or WebHTTrack that omits `MaxRate` is not. `resetMap()` seeds the map and `unserialize()` then overlays only the keys the file states, so it opens in Android as a 25000 cap. The `MaxRate` and `Sockets` cells describe the target rather than what the front ends do today: `initInt` still seeds `maxrate` and `connexion` (`src/htsserver.c`), so here an absent key still yields `--max-rate=100000` where an empty one yields no flag at all, and the two coincide only once those seeds go. `tests/324_winprofile-table.test` asserts the seeds so the rows are corrected when they do. `MaxRetryAfter` needs no such correction. Nothing seeds it here, so an empty key passes no flag and the engine's own 60 seconds apply. `CurrentPath1` and `CurrentPath2` have no writer at all. WinHTTrack reads them live; its own write sites are commented out and neither other front end produces them. A front end that starts writing either will be consumed there, and the `owners` column cannot say so, since it names writers. From a0985f3a0485f2dce9cdb19b3a64f34ac6560c17 Mon Sep 17 00:00:00 2001 From: Xavier Roche Date: Wed, 23 Sep 2026 12:41:19 +0200 Subject: [PATCH 3/4] Android does not always write MaxRate, so "always" was an overclaim absentMeansSame() returns value.length() == 0 for a NO_DEFAULT key, so the key is written only while its baseline is non-empty. resetMap() runs initializeMap() and then loadDefaultPreferences(), and OptionsActivity's save-default menu item writes every field's current value into those preferences, so the baseline is not pinned at the 25000 seed. The httrack-android session caught it. The cross-front-end effect stands either way, because a file that omits the key never overwrites whatever baseline is in force. Signed-off-by: Xavier Roche Co-authored-by: Claude Opus 5 (1M context) Signed-off-by: Xavier Roche --- doc/winprofile-ini.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/winprofile-ini.md b/doc/winprofile-ini.md index 40acd9b97..449433e38 100644 --- a/doc/winprofile-ini.md +++ b/doc/winprofile-ini.md @@ -43,7 +43,7 @@ Android spells three keys that already had WinHTTrack names differently: `ProxyP `Dos` is the one key that is not a number, a checkbox or a list. WinHTTrack packs two independent boxes into it, `m_dos | (m_iso9660 << 1)`, and reads them back with `& 1` and `& 2`, so it alone can write 3. The other two lose it in different places. WebHTTrack has no "both" entry, so it shows 3 as DOS names and drops the ISO bit on re-save; Android decodes only an exact `1`, so 2 and 3 arrive as neither. `Dos=0` is neither box and so means long names, not DOS names, which is why a front end that cannot show 3 must fall back on 1: storing 0 turns the setting into its opposite on the next reopen. Both bits set means DOS names on every side, since that is the precedence WinHTTrack applies when it builds `-L`. -A `default_state` of `none` means do not substitute one. `MaxRate`, `Sockets` and `MaxRetryAfter` carry it: a reader that fills in 100000 for an absent `MaxRate` passes `-A100000` where a front end holding no value passes nothing at all, and the two mirror differently as soon as the engine's own default moves or `bypass_limits` applies. httrack-windows dropped its reader default in #105 for that reason, since a substituted value cannot be told from a chosen one once it reaches a file. HTTrack for Android still writes it. `fieldsDefaults` seeds `MaxRate` to `25000` (`OptionsMapper.java`), so a project nobody edited carries `-A25000` on its command line and `MaxRate=25000` in its profile. That file's own `NO_DEFAULT[]` table names `MaxRate` all the same, so its two halves disagree. Its own profiles are safe, because `absentMeansSame()` gives `NO_DEFAULT` priority and the key is always written. A profile from WinHTTrack or WebHTTrack that omits `MaxRate` is not. `resetMap()` seeds the map and `unserialize()` then overlays only the keys the file states, so it opens in Android as a 25000 cap. The `MaxRate` and `Sockets` cells describe the target rather than what the front ends do today: `initInt` still seeds `maxrate` and `connexion` (`src/htsserver.c`), so here an absent key still yields `--max-rate=100000` where an empty one yields no flag at all, and the two coincide only once those seeds go. `tests/324_winprofile-table.test` asserts the seeds so the rows are corrected when they do. `MaxRetryAfter` needs no such correction. Nothing seeds it here, so an empty key passes no flag and the engine's own 60 seconds apply. +A `default_state` of `none` means do not substitute one. `MaxRate`, `Sockets` and `MaxRetryAfter` carry it: a reader that fills in 100000 for an absent `MaxRate` passes `-A100000` where a front end holding no value passes nothing at all, and the two mirror differently as soon as the engine's own default moves or `bypass_limits` applies. httrack-windows dropped its reader default in #105 for that reason, since a substituted value cannot be told from a chosen one once it reaches a file. HTTrack for Android still writes it. `fieldsDefaults` seeds `MaxRate` to `25000` (`OptionsMapper.java`), so a project nobody edited carries `-A25000` on its command line and `MaxRate=25000` in its profile. That file's own `NO_DEFAULT[]` table names `MaxRate` all the same, so its two halves disagree. Its own profiles are safe by default, because `absentMeansSame()` writes a `NO_DEFAULT` key while its baseline is not empty. The baseline can move, since `resetMap()` loads the user's saved defaults over the seed, and an empty one drops the key instead. A profile from another front end that omits `MaxRate` is not safe either way. `unserialize()` overlays only the keys the file states, so the seed stands and the profile opens in Android as a 25000 cap. The `MaxRate` and `Sockets` cells describe the target rather than what the front ends do today: `initInt` still seeds `maxrate` and `connexion` (`src/htsserver.c`), so here an absent key still yields `--max-rate=100000` where an empty one yields no flag at all, and the two coincide only once those seeds go. `tests/324_winprofile-table.test` asserts the seeds so the rows are corrected when they do. `MaxRetryAfter` needs no such correction. Nothing seeds it here, so an empty key passes no flag and the engine's own 60 seconds apply. `CurrentPath1` and `CurrentPath2` have no writer at all. WinHTTrack reads them live; its own write sites are commented out and neither other front end produces them. A front end that starts writing either will be consumed there, and the `owners` column cannot say so, since it names writers. From 73b27d3b2da0295c3dc36a52a6e4d60f7809f7dc Mon Sep 17 00:00:00 2001 From: Xavier Roche Date: Wed, 23 Sep 2026 12:42:16 +0200 Subject: [PATCH 4/4] "Either way" contradicted the sentence before it The empty baseline that drops MaxRate on a save also fixes the read. resetMap() overlays the user's saved "" over the seed, unserialize() leaves it alone for a file that omits the key, and SimpleOption emits nothing for a non-numeric value, so the profile opens with no cap. The 25000 follows from the seeded baseline being in force, which is the default state rather than every state. Caught by the httrack-android session, which had just supplied the corner the claim contradicted. Signed-off-by: Xavier Roche Co-authored-by: Claude Opus 5 (1M context) Signed-off-by: Xavier Roche --- doc/winprofile-ini.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/winprofile-ini.md b/doc/winprofile-ini.md index 449433e38..b5d0525e8 100644 --- a/doc/winprofile-ini.md +++ b/doc/winprofile-ini.md @@ -43,7 +43,7 @@ Android spells three keys that already had WinHTTrack names differently: `ProxyP `Dos` is the one key that is not a number, a checkbox or a list. WinHTTrack packs two independent boxes into it, `m_dos | (m_iso9660 << 1)`, and reads them back with `& 1` and `& 2`, so it alone can write 3. The other two lose it in different places. WebHTTrack has no "both" entry, so it shows 3 as DOS names and drops the ISO bit on re-save; Android decodes only an exact `1`, so 2 and 3 arrive as neither. `Dos=0` is neither box and so means long names, not DOS names, which is why a front end that cannot show 3 must fall back on 1: storing 0 turns the setting into its opposite on the next reopen. Both bits set means DOS names on every side, since that is the precedence WinHTTrack applies when it builds `-L`. -A `default_state` of `none` means do not substitute one. `MaxRate`, `Sockets` and `MaxRetryAfter` carry it: a reader that fills in 100000 for an absent `MaxRate` passes `-A100000` where a front end holding no value passes nothing at all, and the two mirror differently as soon as the engine's own default moves or `bypass_limits` applies. httrack-windows dropped its reader default in #105 for that reason, since a substituted value cannot be told from a chosen one once it reaches a file. HTTrack for Android still writes it. `fieldsDefaults` seeds `MaxRate` to `25000` (`OptionsMapper.java`), so a project nobody edited carries `-A25000` on its command line and `MaxRate=25000` in its profile. That file's own `NO_DEFAULT[]` table names `MaxRate` all the same, so its two halves disagree. Its own profiles are safe by default, because `absentMeansSame()` writes a `NO_DEFAULT` key while its baseline is not empty. The baseline can move, since `resetMap()` loads the user's saved defaults over the seed, and an empty one drops the key instead. A profile from another front end that omits `MaxRate` is not safe either way. `unserialize()` overlays only the keys the file states, so the seed stands and the profile opens in Android as a 25000 cap. The `MaxRate` and `Sockets` cells describe the target rather than what the front ends do today: `initInt` still seeds `maxrate` and `connexion` (`src/htsserver.c`), so here an absent key still yields `--max-rate=100000` where an empty one yields no flag at all, and the two coincide only once those seeds go. `tests/324_winprofile-table.test` asserts the seeds so the rows are corrected when they do. `MaxRetryAfter` needs no such correction. Nothing seeds it here, so an empty key passes no flag and the engine's own 60 seconds apply. +A `default_state` of `none` means do not substitute one. `MaxRate`, `Sockets` and `MaxRetryAfter` carry it: a reader that fills in 100000 for an absent `MaxRate` passes `-A100000` where a front end holding no value passes nothing at all, and the two mirror differently as soon as the engine's own default moves or `bypass_limits` applies. httrack-windows dropped its reader default in #105 for that reason, since a substituted value cannot be told from a chosen one once it reaches a file. HTTrack for Android still writes it. `fieldsDefaults` seeds `MaxRate` to `25000` (`OptionsMapper.java`), so a project nobody edited carries `-A25000` on its command line and `MaxRate=25000` in its profile. That file's own `NO_DEFAULT[]` table names `MaxRate` all the same, so its two halves disagree. Its own profiles are safe by default, because `absentMeansSame()` writes a `NO_DEFAULT` key while its baseline is not empty. The baseline can move, since `resetMap()` loads the user's saved defaults over the seed, and an empty one drops the key instead. A profile from another front end that omits `MaxRate` is not safe. `unserialize()` overlays only the keys the file states, so the seeded baseline stands and the profile opens in Android as a 25000 cap. The `MaxRate` and `Sockets` cells describe the target rather than what the front ends do today: `initInt` still seeds `maxrate` and `connexion` (`src/htsserver.c`), so here an absent key still yields `--max-rate=100000` where an empty one yields no flag at all, and the two coincide only once those seeds go. `tests/324_winprofile-table.test` asserts the seeds so the rows are corrected when they do. `MaxRetryAfter` needs no such correction. Nothing seeds it here, so an empty key passes no flag and the engine's own 60 seconds apply. `CurrentPath1` and `CurrentPath2` have no writer at all. WinHTTrack reads them live; its own write sites are commented out and neither other front end produces them. A front end that starts writing either will be consumed there, and the `owners` column cannot say so, since it names writers.