[[... atoms ...]] [[... other pages ...]] [Based numbers] with the special case 'base 16' ---- % set hex 3A 3A % scan $hex %x decimal 1 % set decimal 58 ---- '''Decimal to hex:''' format %4.4X $decimalNumber Notice that the ".4" part gives leading zeroes, and does '''not''' have to do with the fractional (right-of-the-point) part of the number. ---- '''Character to hex''': format %4.4X [scan $c %c] Notice that "[[scan $c %c]]" only does what one wants with newer Tcl's, those since version 8.3.0+. ---- [mfi]: Can someone suggest a pure Tcl replacement for xxd UNIX command (creates a hex dump of a given string)? [RS]: Sure enough: proc string2hex {string} { set where 0 set res {} while {$where<[string length $string]} { set str [string range $string $where [expr $where+15]] if {![binary scan $str H* t] || $t==""} break regsub -all (....) $t {\1 } t4 regsub -all (..) $t {\1 } t2 set asc "" foreach i $t2 { scan $i %2x c append asc [expr {$c>=32 && $c<=127? [format %c $c]: "."}] } lappend res [format "%7.7x: %-42s %s" $where $t4 $asc] incr where 16 } join $res \n } See also [Dump a file in hex and ASCII] [LH]: Here's something similar, but speeds things up by using external storage for a character map that is generated one time: proc xxd2 {charMapname convertString} { upvar $charMapname mycharMap #generate a character map for displaying hex equiv of chars [0..127] if { 0 == [string length $mycharMap] } { # init charmap for {set i 0 } { $i < 128 } { incr i } { append mycharMap "[format " \\%03o {%02x }" $i $i ]" } } string map $mycharMap $convertString } #example: set hexcharMap "" ;# global variable xxd2 hexcharMap "abcdz" ;# slow, even if initialized string map $hexcharMap "abcdez" ;# much faster ---- [Bob Rashkin] I know there are plenty of these around but I wanted something to do a hex analysis without all the overhead of editing: proc getFile {} { #this is just a file search before the new tk_getOpenFile global dirlst dirname filelst flnm set dirname [pwd] set filelst [glob -directory $dirname *] lappend filelst "$dirname/.." toplevel .open frame .open.up -borderwidth 4 frame .open.bottom -borderwidth 4 pack .open.up .open.bottom -side top set w .open.up listbox $w.hval -height 8 -font {courier 9} -exportselection 1 \ -yscrollcommand "$w.yscr set" -listvar filelst \ -xscrollcommand "$w.xscr set" -width 55 scrollbar $w.yscr -command "$w.hval yview" scrollbar $w.xscr -command "$w.hval xview" -orient horizontal pack $w.yscr -side right -fill y pack $w.hval $w.xscr -side top -fill x bind .open.up.hval { set filename [lindex $filelst [.open.up.hval curselection]] } bind .open.up.hval { set filename [lindex $filelst [.open.up.hval curselection]] } set u .open.bottom entry $u.filen -textvariable filename -width 50 button $u.opn -text Open -command { if [file isdirectory $filename] { set filelst [glob -directory $filename *] lappend filelst "$filename/.." } else { destroy .open set flnm $filename } } pack $u.filen $u.opn -side left -padx 8 bind .open.bottom.filen { if [file isdirectory $filename] { set filelst [glob -directory $filename *] } else { destroy .open set flnm $filename } } focus .open.bottom.filen } proc closeUp {fid} { close $fid .top.val delete 0.0 end } proc doScan {stadd fsz} { global fid fid2 val hval flnm tag # . configure -cursor watch update # set bold "-background #44aaaa -foreground white" set normal "-background {} -foreground {}" .top.val delete 0.0 end if {$fsz == 0} {set fsz [expr {[file size $flnm] -$stadd}]} #.top.val insert end "Scanning $fsz bytes\n" if {$fsz>5000} { .top.val insert end "scanning more than 5000 bytes at a time\n" c1 .top.val insert end "can result in unpredictable behavior\n" c1 } set nlns [expr {$fsz/16}] if {[expr {fmod($fsz,16)}]>0} {incr nlns} set fid2 [open $flnm r] fconfigure $fid2 -translation binary;#<<<<<<<---this is the key statement! seek $fid2 $stadd start cd [file dirname $flnm] set t 0 set lnadd $stadd for {set ln 1} {$ln <= $nlns} {incr ln} { set val [read $fid2 16] set nbyt [string length $val] set fmnum [expr {2*$nbyt}] binary scan $val H$fmnum hval;#<<<<<<<<<<<<<<<< ".top.val tag configure $tag $bold" .top.val tag bind $tag ".top.val tag configure $tag $normal" .top.val tag bind $tag <1> "scanBin $tag" } # . configure -cursor arrow update -cursor arrow # } proc scanBin {hxline} { global val val1 val2 val3 .middle.left.hval delete 0.0 end .middle.right.hval delete 0.0 end set val [.top.val get $hxline.first $hxline.last] set val2 [binary format "H32" $val] for {set i 0} {$i<=7} {incr i} { set val3 [string range $val2 $i $i] binary scan $val3 B8 hval;#<<< binary scan $val3 H2 val4 binary scan $val3 c dval set dval [expr {( $dval + 0x100 ) % 0x100}] .middle.left.hval insert end $val4\t$hval\t$dval\n } for {set i 8} {$i<=15} {incr i} { set val3 [string range $val2 $i $i] binary scan $val3 B8 hval;#<<< binary scan $val3 H2 val4 binary scan $val3 c dval set dval [expr {( $dval + 0x100 ) % 0x100}] .middle.right.hval insert end $val4\t$hval\t$dval\n } } wm title . Binary_Data_Analyzer wm deiconify . frame .top -borderwidth 4 frame .middle -borderwidth 4 frame .bottom -borderwidth 4 pack .top .middle .bottom -side top set w .top for {set i 0} {$i<65} {incr i} {append lblstr " "} set lblstr [string replace $lblstr 2 5 Addr] set lblstr [string replace $lblstr 15 26 "16 Bytes HEX"] set lblstr [string replace $lblstr 52 56 ASCII] label $w.read2 -text $lblstr -fg blue -font {courier 9} text $w.val -height 12 -width 65 -yscrollcommand "$w.yscr set" -font {courier 9} scrollbar $w.yscr -command "$w.val yview" pack $w.yscr -side right -fill y pack $w.read2 $w.val -side top set w .middle frame .middle.left -borderwidth 4 frame .middle.right -borderwidth 4 pack .middle.left .middle.right -side left set w .middle.left for {set i 1} {$i<=28} {incr i} {append binlbl " "} set binlbl [string replace $binlbl 0 2 Hex] set binlbl [string replace $binlbl 9 14 Binary] set binlbl [string replace $binlbl 21 28 Decimal] label $w.scan -text "BinaryScan 0-7" label $w.tit2 -text $binlbl -font {courier 9} -fg blue text $w.hval -height 8 -width 28 -font {courier 9} pack $w.scan $w.tit2 $w.hval -side top set w .middle.right label $w.scan -text "BinaryScan 8-15" label $w.tit2 -text $binlbl -font {courier 9} -fg blue text $w.hval -height 8 -width 28 -font {courier 9} pack $w.scan $w.tit2 $w.hval -side top if {[winfo depth $w] > 1} { set bold "-background #43ce80 -relief raised -borderwidth 1" set normal "-background {} -relief flat" } else { set bold "-foreground white -background black" set normal "-foreground {} -background {}" } set w .bottom label $w.flbl -text "File name: " entry $w.fent -textvariable flnm -width 42 -font {-size 9 -weight bold} button $w.scan -text Scan -width 42 -activebackground white -command {doScan $stadd $lngt} button $w.getf -text File -command {getFile} frame $w.add -borderwidth 4 pack $w.add -side bottom pack $w.scan -side bottom pack $w.flbl $w.fent $w.getf -side left -padx 6 set stadd 0 set lngt 0 if {$argc>0} {set flnm [lindex $argv 0];set lngt 5000;doScan 0 5000} set w .bottom.add label $w.stlab -text "start address:" entry $w.stent -textvariable stadd -width 8 label $w.lnlab -text Length: entry $w.lnent -textvariable lngt -width 8 label $w.wrng -text "0=to EOF" -justify left pack $w.stlab $w.stent $w.lnlab $w.lnent $w.wrng -side left -padx 6 bind . exit bind . {doScan $stadd $lngt} bind .bottom.add.lnent {set lngt [file size $flnm]} menu .menu -tearoff 0 set m .menu.help menu $m -tearoff 0 .menu add cascade -label "Don't panic" -menu $m -underline 0 $m add cascade -label "System" -menu .menu.help.sys -underline 0 $m add cascade -label "General" -menu .menu.help.gen -underline 0 $m add cascade -label "Quirks" -menu .menu.help.qks -underline 0 set m .menu.help.gen menu $m -tearoff 0 $m add check -label "Scan button reads in file as HEX and ASCII in 16byte chunks" $m add check -label "If start is not 0, reading starts at the address specified (in decimal)" $m add check -label "If Length is 0, the entire file is read (or to EOF)" $m add check -label "Otherwise only (decimal) Length number of bytes is read" $m add separator $m add check -label "If invoked from the command line, will take filename as argument" $m add check -label " and scan from 0 to 5000" $m add separator $m add check -label "Move cursor over any line of HEX," $m add check -label "Left click to analyze each byte of highlit line" $m add separator $m add check -label "The File button opens a listbox to search files" $m add check -label "Click Open to return the file to the main window file entry" $m add check -label " or open the indicated directory" set m .menu.help.sys menu $m -tearoff 0 $m add check -label "Requires Tcl/Tk 8.3 or higher" set m .menu.help.qks menu $m -tearoff 0 $m add check -label "Right click in the Length entry to compute file size" $m add check -label "Very big files can overflow something (tag array?)" $m add check -label ">Not sure what 'very big' is but 5000 bytes or" $m add check -label " fewer at a time certainly works" $m add check -label " (return) anywhere in the main window is the same as Scan" $m add separator $m add check -label " in the File window listbox brings the selection" $m add check -label " to the entry box" $m add check -label " in the file entry in the File window is the same as Open" . configure -menu .menu ---- After that much code, here's a little one: convert a string to hex, so the result can be reparsed as the original string: proc string2hex s { binary scan $s H* hex regsub -all (..) $hex {\\x\1} } ;# RS % string2hex "hello, world!" \x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21 % subst [string2hex "hello, world!"] hello, world! ---- [AM] I needed to inspect the actual value of a number in a binary file. Actually the number was repeated many times, it represented a "missing value". Of course the program that needed to read this file had a different idea about what value constitutes a missing value. So I wanted to know what the actual value was (in human terms). Via a hex viewer, I could see that the bytes were "5c ff 79 c4". In the chatroom, [dkf] came up with the following solution: binary scan [binary format I 0x5cff79c4] f xx set xx -999.989990234 Explanation: * The string "0x5cff79c4" must be converted to a binary string * This can then be read via [[binary scan]] * Some caution is needed: the byte order. If the bytes are given in the same order as the machine expects, then use capital "I" in the [[binary format]]'s format. If the machine uses the opposite byte order, use a lowercase "i" instead. (The binary scan requires the "f" format in any case) ---- [Arts and crafts of Tcl-Tk programming]