User:Andrew Nikitin/HexView

From J Wiki
Jump to navigation Jump to search

Once in a while some people (including myself) feel a need to modify several bytes in some binary files. Traditionally, piece of software called binary editor is used to complete this task.

In most cases J itself can be used as binary editor. For example,

   D=.1!:1 <'temp\data.bin' NB. read data from file
   a. i. 0 1{ D             NB. inspect data
   D=.'BM' 0 1}D            NB. modify data
   D 1!:2 <'temp\data.bin'  NB. write data back to disk

However, sometimes the file either is too big to comfortably fit in memory or it is desirable to have better view of bytes.

Hexview.png [{{#file: "hexedit.ijs"}} Download script: hexedit.ijs ]

NB. Hex editor for string noun
«history»

require 'jzgrid jmf'

«hexview class»

cocurrent 'base'

«startup cover verbs»

hexview class

The functionality of an editor is implemented in hexview class. It consists of a form with a single grid control in it. Grid control displays contents of a desired noun. [{{#file: "hexview class"}} Download script: hexview class ]

coclass 'hexview'

Formatting verbs are used to format

a) address

b) data

c) top row of offsets

Formatting verbs together with menuitem IDs and captions are stored in VIEWFORMATS noun. VIEWFORMATS is used to build a menu and performa actual string transformations. [{{#file: "hexview class"}} Download script: hexview class ]

hexformat=:'0123456789abcdef' {~ ] #:~ 16 #~ [

VIEWFORMATS=:i.0 0
VIEWFORMATS=:VIEWFORMATS,'hex';'&Hex';(8&hexformat)`(2&hexformat)`(1&hexformat)
VIEWFORMATS=:VIEWFORMATS,'dec';'&Decimal';":`":`":

addr_format=:3 : '(FMT{VIEWFORMATS)@.2 y'
data_format=:3 : '(FMT{VIEWFORMATS)@.3 y'
col_format=: 3 : '(FMT{VIEWFORMATS)@.4 y'

[{{#file: "hexview class"}} Download script: hexview class ]

VIEWCPS=:i.0 0
VIEWCPS=:VIEWCPS, 'ascii';'&ASCII';16 16$'.' ((i.32),127+i.129)}2 u: a.
VIEWCPS=:VIEWCPS, 'iso88591';'&ISO8859-1'; '.' (,0 128+/i.32)} 2 u: a.

Form definition noun is split in two so that View menu can be constructed from VIEWFORMATS and VIEWCPS. [{{#file: "hexview class"}} Download script: hexview class ]

HEXVIEW_MENU=: 0 : 0
pc hexview;
menupop "Data";
menu file "&File" "Ctrl-O" "" "";
menu noun "&Noun" "Ctrl-N" "" "";
menusep;
menu cancel "&Exit" "" "" "";
menupopz;
menupop "Edit";
menu goto "&Go to..." "Ctrl-G" "" "";
menusep;
menu apply "&Apply changes" "" "" "";
menupopz;
menupop "View";
)
HEXVIEW_FORM=: 0 : 0
menupopz;
xywh 5 5 420 120;cc grid isigraph rightmove bottommove;
pas 5 5;pcenter;
rem form end;
)

(The width of grid control was determined by issuing wd 'qchildxywh grid;' after manually resizing form so that grid fits with a little extra room) [{{#file: "hexview class"}} Download script: hexview class ]

create=: 3 : 0
  wd HEXVIEW_MENU
  ([: wd 'menu ', >@(0&{), ' "' , >@(1&{) , '" "" "" "";'"_)"1 VIEWFORMATS
  wd 'menusep;'
  ([: wd 'menu ', >@(0&{), ' "' , >@(1&{) , '" "" "" "";'"_)"1 VIEWCPS
  wd HEXVIEW_FORM
  grid=:conew 'jzgrid'

WIDTH is number of bytes per row of display, Grid control displays 1+WIDTH columns, where last column is text representation of WIDTH bytes shown in this row. [{{#file: "hexview class"}} Download script: hexview class ]

  WIDTH=:16

DATA is character noun holding the bytes to display. This noun can be mapped to a file on disk to view files. [{{#file: "hexview class"}} Download script: hexview class ]

  DATA=:y

Table of views defines how data is displayed. It can be hex or decimal. FMT is index in the table of viewed. Another parameter affecting display is CP -- index in list of codepages to use in text representation of the data. [{{#file: "hexview class"}} Download script: hexview class ]

  FMT=:0
  CP=:0

In case DATA is a mapped to a file, the name of this file is stored in FILE. [{{#file: "hexview class"}} Download script: hexview class ]

  FILE=:''

Grid operates in virtual mode. This enables use of mapped nouns to view large files. [{{#file: "hexview class"}} Download script: hexview class ]

  CELLRANGE__grid=:1 0+<:WIDTH ([ , *@| + <.@%~) # DATA
  HDRTOP__grid=:<'Address'
  HDRCOL__grid=:<@(col_format)"0 i.WIDTH
  HDRCOL__grid=:HDRCOL__grid,<'Text'
  GRIDVIRTUALMODE__grid=:1
  CELLFONT__grid=:1
  CELLCOLORS__grid=:CELLCOLORS__grid,24$192 192 192
  wd 'set ',(>0{FMT{VIEWFORMATS),' 1'
  wd 'set ',(>0{CP{VIEWCPS),' 1'
  show__grid ''
  wd 'pshow;'
)

Destructor

When object is destroyed it first closes the form, unmaps mapped file, if any, and then destroys member grid. [{{#file: "hexview class"}} Download script: hexview class ]

destroy=:3 : 0
  wd 'pclose'
  closefile ''
  destroy__grid''
  codestroy ''
)

Form's close and cancel events simply destroy parent object, which also takes care of GUI. [{{#file: "hexview class"}} Download script: hexview class ]

hexview_close=: 3 : 0
destroy ''
)

[{{#file: "hexview class"}} Download script: hexview class ]

hexview_cancel_button=: destroy

Event processing

[{{#file: "hexview class"}} Download script: hexview class ]

grid_gridhandler=:3 : 0
  select. y
  case. 'get' do.
    NB. smoutput Cls__grid;Rws__grid
    i=.(WIDTH*Rws__grid) +/ }:Cls__grid
    t=.<@(data_format)@(a.&i.)"0 DATA{~(<:#DATA)<.i
    text=.(,>2{CP{VIEWCPS) <@:(7&u:)@:{"1 ~a.i.DATA{~(<:#DATA)<.i
    CELLCOLOR__grid=:(2 1{~i<#DATA),.0
    CELLEDIT__grid=:(i<#DATA),.0
    CELLDATA__grid=:t,.((<"1 i<#DATA) (8 u: #)&.> text)
    HDRROW__grid=:<@(addr_format)"0 Rws__grid*WIDTH
    HDRCOL__grid=:<@(col_format)"0 i.WIDTH
    HDRCOL__grid=:HDRCOL__grid,-.&'&'&.>1{CP{VIEWCPS
  end.
  1
)

Since grid control accepts data in utf8, 8&u: had to be issued before assigning formatted text to CELLDATA.

--- [{{#file: "hexview class"}} Download script: hexview class ]

closefile=:3 : 0
if. -.''-:FILE do.
  n=.'DATA_',(>coname''),'_'
  smoutput 'closing ',FILE,' as ',n
  unmap_jmf_ n
  FILE=:''
  wd 'pn *'
end.
)

hexview_file_button=: 3 : 0
  FILE=:wd 'mbopen "Select file" "" "" "All files (*.*)|*.*" ofn_filemustexist'
  JCHAR map_jmf_ ('DATA_',(>coname''),'_');FILE
  CELLRANGE__grid=:1 0+<:WIDTH ([ , *@| + <.@%~) # DATA
  wd 'pn *',FILE
)

Since items of View menu are generated from nouns, default driver provides processing events from these elements -- change of format or change of displayed codepage. [{{#file: "hexview class"}} Download script: hexview class ]

hexview_default=:3 : 0
 NB. smoutput syschild,' ',sysevent
 if. (<syschild) e. 0{"1 VIEWFORMATS do.
   i=.(<syschild) i.~ 0{"1 VIEWFORMATS
   FMT=:i
   ([: wd 'set ' , ] , ' 0'"_)&> 0{"1 VIEWFORMATS
   wd 'set ',(>0{i{VIEWFORMATS),' 1'
   show__grid''
 elseif. (<syschild) e. 0&{"1 VIEWCPS do.
   i=.(<syschild) i.~ 0&{"1 VIEWCPS
   CP=:i
   ([: wd 'set ' , ] , ' 0'"_)&> 0{"1 VIEWCPS
   wd 'set ',(>0{i{VIEWCPS),' 1'
   show__grid''
 end.
)

Cover verbs

[{{#file: "startup cover verbs"}} Download script: startup cover verbs ]

newhexview=:3 : 0
  a=.a:
  a=.conew 'hexview'
  try.
    create__a y
  catchd.
    smoutput 13!:12 ''
    destroy__a ''
    a=.a:
  end.
  a
)
z=:newhexview a.

History

[{{#file: "history"}} Download script: history ]

NB. 2007-10-10 12:51:11
NB. 2007-11-14 16:48:53

TODO and comments

  • allow updates; store list of addresses and modifications and apply in a

single step (or save delta to a file)

  • (?) noun browser
  • Goto address
  • Search
  • Copy/paste

CategoryLiterate CategoryWorkInProgress