@@ -1078,42 +1078,53 @@ proc ::tree::mask::safeReadMaskFile {filename} {
10781078
10791079 # Read file contents
10801080 if {[catch {
1081- set fd [open $filename r]
1081+ set fd [:: open $filename r]
10821082 fconfigure $fd -encoding utf-8
10831083 set content [read $fd ]
1084- close $fd
1084+ :: close $fd
10851085 } err]} {
10861086 return 0
10871087 }
10881088
10891089 # Trim whitespace
10901090 set content [string trim $content ]
10911091
1092- # Validate file format: must be exactly "set ::tree::mask::maskSerialized {...} "
1093- # The content inside braces must be a valid Tcl list (key-value pairs)
1094- if {![regexp {^set\s+::tree::mask::maskSerialized\s+( \{ .* \} )\s*$} $content -> listData ]} {
1092+ # Validate file format: must start with "set ::tree::mask::maskSerialized"
1093+ set prefix " set ::tree::mask::maskSerialized "
1094+ if {![string equal -length [ string length $prefix ] $content $prefix ]} {
10951095 return 0
10961096 }
10971097
1098+ # Extract everything after the prefix - this handles multi-line content
1099+ set listData [string range $content [string length $prefix ] end]
1100+ set listData [string trim $listData ]
1101+
10981102 # Validate that the list data is well-formed by attempting to parse it
10991103 # as a Tcl list. This ensures balanced braces and valid list structure.
1104+ # Tcl's llength handles multi-line brace-delimited content correctly.
11001105 if {[catch {llength $listData }]} {
11011106 return 0
11021107 }
11031108
1104- # Additional validation: check that all keys look like valid FEN strings
1105- # and all values are proper lists. We parse the data safely.
1109+ # The save function uses [list [array get ...]] which wraps data in braces,
1110+ # so llength returns 1. We need to extract the inner data for validation.
1111+ if {[catch {set innerData [lindex $listData 0]}]} {
1112+ return 0
1113+ }
1114+
1115+ # Validate the inner data structure
1116+ # Check a sample of entries for performance (first 100 pairs)
11061117 if {[catch {
1107- set parsedList $listData
1108- set len [llength $parsedList ]
1118+ set len [llength $innerData ]
11091119 # Must have even number of elements (key-value pairs)
11101120 if {$len % 2 != 0} {
11111121 error " Invalid mask data structure"
11121122 }
1113- # Validate each key-value pair
1114- for {set i 0} {$i < $len } {incr i 2} {
1115- set key [lindex $parsedList $i ]
1116- set value [lindex $parsedList [expr {$i + 1}]]
1123+ # Validate a sample of key-value pairs (up to 100)
1124+ set maxCheck [expr {min($len , 200)}]
1125+ for {set i 0} {$i < $maxCheck } {incr i 2} {
1126+ set key [lindex $innerData $i ]
1127+ set value [lindex $innerData [expr {$i + 1}]]
11171128 # Key should be a non-empty string (FEN position identifier)
11181129 if {$key eq " " } {
11191130 error " Empty key in mask data"
@@ -1128,6 +1139,7 @@ proc ::tree::mask::safeReadMaskFile {filename} {
11281139 }
11291140
11301141 # All validations passed, set the data
1142+ # Keep the original listData format (with outer braces) for compatibility
11311143 set ::tree::mask::maskSerialized $listData
11321144 return 1
11331145}
0 commit comments