Created
July 31, 2012 14:31
-
-
Save juster/3217430 to your computer and use it in GitHub Desktop.
VCE Exam Taker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package require Tk | |
proc initTop {} { | |
menu .topMenu | |
menu .topMenu.fileMenu -tearoff 0 | |
.topMenu.fileMenu add command -label Open... -command selectVCEPath | |
.topMenu add cascade -label File -menu .topMenu.fileMenu | |
. configure -menu .topMenu | |
grid [ttk::frame .top] -row 1 -column 1 -sticky we | |
grid [ttk::frame .mid] -row 2 -column 1 -sticky we | |
## Title | |
set p .top | |
grid [ttk::label $p.titLbl -text Title] -row 1 -column 1 | |
grid [ttk::entry $p.titEnt -state readonly -textvariable vceTitle] \ | |
-row 1 -column 2 -sticky we | |
## Current question count. | |
grid [ttk::label $p.curLbl -text Current] -row 2 -column 1 | |
grid [ttk::entry $p.curEnt -state readonly -textvariable vceCurrent] \ | |
-row 2 -column 2 -sticky we | |
## Next/previous buttons | |
grid [ttk::button $p.nextBtn -text Next -command { gotoNextQ }] \ | |
-row 1 -column 3 | |
grid [ttk::button $p.prevBtn -text Prev -command { gotoPrevQ }] \ | |
-row 2 -column 3 | |
## Question frame | |
set p .mid | |
text $p.qTxt -height 5 -wrap word -state disabled -yscrollcommand "$p.qScrl set" | |
grid $p.qTxt -row 1 -column 1 -sticky ew | |
ttk::scrollbar $p.qScrl -command "$p.qTxt yview" | |
grid $p.qScrl -row 1 -column 2 -sticky nes | |
ttk::button $p.answerBtn -command submitAnswer -text Answer | |
grid $p.answerBtn -row 2 -column 1 -columnspan 2 -sticky w | |
grid columnconfigure . 1 -weight 1 | |
grid columnconfigure .top 2 -weight 1 | |
grid columnconfigure .mid 1 -weight 1 | |
} | |
proc selectVCEPath {} { | |
global vcePath | |
set path [tk_getOpenFile] | |
if { $path eq {} } { return } | |
set vcePath $path | |
openVCE $path | |
} | |
proc openVCE {path} { | |
global vceChan vceVer vceTitle vceCount vceQStart vceIndex | |
set vceChan [open $path {RDONLY BINARY}] | |
binary scan [read $vceChan 4] a2cc magic hiVer loVer | |
if { $magic ne "\x85\xA8" } { | |
tk_messageBox -icon error -message {File does not appear to be in the VCE format.} | |
close $vceChan | |
return | |
} | |
set vceVer "$hiVer.$loVer" | |
skip $vceChan 1 | |
set examCode [readXStr $vceChan] | |
set examTitle [readXStr $vceChan] | |
set vceTitle "$examCode - $examTitle" | |
## Not sure WTF? | |
skip $vceChan [expr {16 * 3 + 5}] | |
## Decodes to all zeros? | |
skipXStr $vceChan | |
## Big JPEG and stuff. Intro message. | |
skipXStr $vceChan | |
skip $vceChan 9 | |
binary scan [read $vceChan 4] i vceCount | |
set vceQStart [tell $vceChan] | |
set vceIndex 1 | |
scanQ $vceChan | |
return | |
} | |
proc skip {ch count} { | |
seek $ch $count current | |
} | |
proc skipXStr {ch} { | |
set count 0 | |
binary scan [read $ch 4] i count | |
if { $count != 0 } { | |
skip $ch $count | |
} | |
} | |
proc readXStr {ch} { | |
binary scan [read $ch 4] i count | |
# & makes unsigned | |
set count [expr {$count & 0xFFFFFFFF}] | |
set msg [read $ch $count] | |
decXOR msg | |
return $msg | |
} | |
proc decXOR {bname} { | |
upvar 1 $bname bytes | |
set i 0 | |
set msg {} | |
binary scan $bytes c* blist | |
foreach b $blist { | |
set x [expr {($b ^ $i) & 0xFF}] | |
append msg [format %c $x] | |
incr i | |
} | |
set bytes $msg | |
} | |
##################################################################################################### | |
proc gotoPrevQ {} { | |
global vceIndex vceChan | |
if { $vceIndex <= 1 } { | |
tk_messageBox -icon error -message "No previous question exists." | |
} else { | |
incr vceIndex -1 | |
gotoQ $vceChan $vceIndex | |
} | |
} | |
proc gotoNextQ {} { | |
global vceIndex vceChan vceCount | |
if { $vceIndex >= $vceCount } { | |
tk_messageBox -icon error -message "No next question exists." | |
} else { | |
incr vceIndex | |
gotoQ $vceChan $vceIndex | |
} | |
} | |
proc gotoQ {ch idx} { | |
global vceCount vceQStart | |
if { $idx < 1 } { | |
error "Question index cannot be less than one." | |
} elseif { $idx > $vceCount } { | |
error "Index is greater than question count." | |
} | |
seek $ch $vceQStart | |
incr idx -1 | |
for { set i 0 } { $i < $idx } { incr i } { | |
skipQ $ch | |
} | |
scanQ $ch | |
} | |
proc skipQ {ch} { | |
scanQStart $ch | |
skip $ch 8 | |
skipXStr $ch | |
skipXStr $ch | |
skip $ch 7 | |
skipXStr $ch | |
} | |
######################################################################################### | |
proc scanQ {ch} { | |
global vceCurrent vceIndex vceCount | |
set offset [tell $ch] | |
set vceCurrent "$vceIndex/$vceCount (0x[format %X $offset])" | |
.top.nextBtn configure -state \ | |
[expr { $vceIndex >= $vceCount ? "disabled" : "enabled" }] | |
.top.prevBtn configure -state \ | |
[expr { $vceIndex <= 1 ? "disabled" : "enabled" }] | |
global vceMulti vceChoiceCount | |
destChoices $vceMulti $vceChoiceCount | |
set vceMulti [scanQStart $ch] | |
skip $ch 8 | |
scanQText $ch $vceMulti | |
global vceAnswer | |
set vceAnswer [readXStr $ch] | |
skip $ch 7 | |
skipXStr $ch | |
} | |
proc scanQStart {ch} { | |
binary scan [read $ch 5] ca4 multi magic | |
if { $magic ne "\xFF\xFF\xFF\xFF" } { | |
error {This does not appear to be a question entry.} | |
} elseif { $multi > 1 } { | |
error "Question entry has an unknown multi flag: $multi" | |
} | |
return [expr {$multi == 1}] | |
} | |
proc scanQText {ch multi} { | |
set in [readXStr $ch] | |
global vceChosen vceChoiceCount | |
set vceChoiceCount 0 | |
set vceChosen "" | |
set qtxt [scanQTextStr in] | |
.mid.qTxt configure -state normal | |
.mid.qTxt delete 0.0 end | |
.mid.qTxt insert 0.0 $qtxt | |
.mid.qTxt configure -state disabled | |
# .mid.answerBtn configure -state disabled | |
set i 0 | |
while { [string length $in] > 0 } { | |
set txt [scanQTextStr in] | |
if { $txt eq {} } { break } | |
addChoice $multi $i $txt | |
incr i | |
} | |
set vceChoiceCount $i | |
} | |
proc scanQTextStr {strname} { | |
upvar 1 $strname str | |
binary scan [string range $str 0 3] i len | |
set txt [string range $str 4 [expr {$len + 4 - 1}]] | |
set str [string range $str [expr {$len + 4}] end] | |
regsub -all "\x0D" $txt {} txt | |
set lines [split $txt "\n"] | |
set txt [join [lrange $lines 2 end] "\n"] | |
regsub -all "\n*$" $txt {} txt | |
return $txt | |
} | |
######################################################################################### | |
proc indexLtr {idx} { | |
scan A %c a | |
return [format %c [expr {$a + $idx}]] | |
} | |
proc addChoice {multi idx txt} { | |
set ltr [indexLtr $idx] | |
set name ".mid.choice$ltr" | |
global vceChosen$ltr | |
if { $multi } { | |
set vceChosen$ltr 0 | |
ttk::checkbutton $name -text "$ltr. $txt" -variable vceChosen$ltr | |
} else { | |
unset vceChosen$ltr | |
ttk::radiobutton $name -text "$ltr. $txt" -value $ltr -variable vceChosen | |
} | |
set row [expr {$idx + 3}] | |
grid $name -row $row -column 1 -sticky w | |
} | |
proc destChoices {multi count} { | |
foreach w [winfo children .mid] { | |
if { [string match .mid.choice* $w] } { destroy $w } | |
} | |
if { $multi } { | |
for { set i 0 } { $i < $count } { incr i } { | |
set ltr [indexLtr $i] | |
global vceChosen$ltr | |
unset vceChosen$ltr | |
} | |
} | |
} | |
proc getChosen {} { | |
set selected {} | |
global vceMulti | |
if { $vceMulti } { | |
global vceChoiceCount | |
for { set i 0 } { $i < $vceChoiceCount } { incr i } { | |
set ltr [indexLtr $i] | |
global vceChosen$ltr | |
if { [subst "\$vceChosen$ltr"] == 1 } { | |
append selected $ltr | |
} | |
} | |
} else { | |
global vceChosen | |
set selected $vceChosen | |
} | |
return $selected | |
} | |
proc submitAnswer {} { | |
global vceAnswer | |
set chosen [getChosen] | |
if { $chosen eq $vceAnswer } { | |
gotoNextQ | |
return | |
} | |
switch $vceAnswer { | |
"" { | |
tk_messageBox -icon error \ | |
-message "Answer is empty, may not be read properly" | |
} | |
default { | |
tk_messageBox -message "Incorrect!" } | |
} | |
} | |
set vceIndex 0 | |
set vceMulti False | |
initTop | |
selectVCEPath |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment