resedit 1.5.1 → 1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c544c164c27a245f45cebe0ede011c1a8ebd19d2
4
- data.tar.gz: a212b23cc05f16ec779469aecc74601b046ae468
3
+ metadata.gz: 5b4e01f23eab7befb55f58374b179252e580ba27
4
+ data.tar.gz: c70bea5859d5fcdb2c62379956034d641336d320
5
5
  SHA512:
6
- metadata.gz: 85deaaad0d6928ceafda0bb8a6642b8af902f061870c1e8a0fc2ba33bf3e3c25c97c83ac38c2858534214f058f713b3e955bba3fa995eacf77abb4b9ea47ea42
7
- data.tar.gz: a8c03dcca383eb79c3215009e4c3563e73cce82e05bd590946926b70ef3a56d57433e57ca51dbb4ea2fbf07596cad6106ccf6fadc66ed6fbd9cd2510db6815de
6
+ metadata.gz: bec413733f867fe85b74bfbb07f99bcb4be3b161f3a3539cf50ed5312e03365accff257b81a107308c1ad205e0c8eb7779f330bb62414e3c508af802ce64edab
7
+ data.tar.gz: f6ef54cd8d085aaf2821f3b7821ccdbaa4c15ac26a4cf38b734091f0095b6626a7333f673a1ccaa72bc49075fbec2d57839dd9588391a46fc25ea7dc2744b9a0
@@ -9,9 +9,13 @@ require 'resedit/text/huffman'
9
9
  require 'resedit/app/font_convert'
10
10
  require 'resedit/app/text_convert'
11
11
  require 'resedit/convert/bitconv'
12
+ require 'resedit/convert/codepatch'
12
13
  require 'resedit/mz/mz'
14
+ require 'resedit/classes/colorizer'
15
+ require 'resedit/classes/hexwriter'
16
+ require 'resedit/classes/changeable'
13
17
 
14
18
 
15
19
  module Resedit
16
- VERSION = "1.5.1"
20
+ VERSION = "1.6"
17
21
  end
@@ -1,6 +1,6 @@
1
1
  require 'resedit/app/std_commands'
2
2
  require 'resedit/app/mz_command'
3
- require 'resedit/app/colorizer'
3
+ require 'resedit/classes/colorizer'
4
4
  require 'logger'
5
5
  require 'readline'
6
6
 
@@ -34,7 +34,7 @@ module Resedit
34
34
  @cmds[n] = c;
35
35
  }
36
36
  }
37
- @col = Colorizer.new(false)
37
+ @col = Colorizer.instance()
38
38
  end
39
39
 
40
40
 
@@ -83,7 +83,6 @@ module Resedit
83
83
  return nil if cmd.length()==0 || cmd[0][0]=='#'
84
84
  c = @cmds[cmd[0]]
85
85
  raise "Unknown command: #{cmd[0]}" if !c
86
- res=[]
87
86
  prms = c.parseParams(cmd[1..-1])
88
87
  return c,prms
89
88
  end
@@ -67,8 +67,8 @@ module Resedit
67
67
  pidx+=1
68
68
  end
69
69
  end
70
- @params.each{|p|
71
- raise "Expected parameter #{p[:name]}" if res[p[:name]]==nil
70
+ @params.each{|pp|
71
+ raise "Expected parameter #{pp[:name]}" if res[pp[:name]]==nil
72
72
  }
73
73
  return res
74
74
  end
@@ -1,4 +1,3 @@
1
- require 'resedit/app/app'
2
1
  require 'resedit/app/app_command'
3
2
  require 'resedit/mz/mz'
4
3
  require 'resedit/mz/mzenv'
@@ -15,14 +14,14 @@ module Resedit
15
14
  addParam('p3', "mz command parameter","")
16
15
  addParam('p4', "mz command parameter","")
17
16
  addParam('p5', "mz command parameter","")
18
- addOption('help', 'h', nil, 'help on mz commands')
17
+ addOption('help', 'h', false, 'help on mz commands')
19
18
  @cmds = {
20
19
  "help"=>[method(:help), "show help on mz commands", {"command" => "command to show help on"}],
21
20
  "use"=>[method(:use), "select mz file", {"file" => "path to mz file"}],
22
21
  "save"=>[method(:save), "save current file",{"filename" => "filename fir saving", "final"=>"don't save changes"}],
23
22
  "close"=>[method(:close), "close file", {"file" => "path or id of file to close"}],
24
23
  "print"=>[method(:info), "print info about mz objects", {"what" => "files/header/reloc/changes", "how" => "original/modified"}],
25
- "append"=>[method(:append), "add bytes to current file", {"value" => "value", "type" => "value type", }],
24
+ "append"=>[method(:append), "add bytes to current file", {"value" => "value", "type" => "value type", "where" => "append offset. default: above ss:sp"}],
26
25
  "replace"=>[method(:replace), "replace added bytes", {"value" => "value", "type"=>"value type"}],
27
26
  "change"=>[method(:change), "change bytes at offset", {"ofs" => "data ofset", "value" => "value", "disp" => "code/file", "type"=>"value type"}],
28
27
  "reloc"=>[method(:reloc), "add relocation", {"value" => "value"}],
@@ -94,7 +93,6 @@ module Resedit
94
93
 
95
94
 
96
95
  def use(params)
97
- App::get().col.on = true
98
96
  mz = getfile(params['file'])
99
97
  if mz==nil
100
98
  mz = MZ.new(params['file'])
@@ -113,7 +111,6 @@ module Resedit
113
111
  mz.close()
114
112
  mz = nil
115
113
  @cur = @files[0] if !@cur && @files.length > 0
116
- App::get().col.on = false if @files.length == 0
117
114
  info()
118
115
  end
119
116
 
@@ -1,5 +1,4 @@
1
1
  require 'resedit/app/app_command'
2
- require 'resedit'
3
2
 
4
3
  module Resedit
5
4
 
@@ -0,0 +1,299 @@
1
+ require 'resedit/classes/colorizer'
2
+ require 'resedit/classes/hexwriter'
3
+ require 'logger'
4
+
5
+ module Resedit
6
+
7
+ class Changeable
8
+ HOW_CHANGED = 0
9
+ HOW_ORIGINAL = 1
10
+ COL_CHANGED = Colorizer::YELLOW
11
+ COL_ORIGINAL = Colorizer::PURPLE
12
+ LOG = Logger.new(STDOUT)
13
+
14
+ class Change
15
+
16
+ attr_accessor :buf, :sz, :n, :obuf, :nbuf
17
+
18
+ def initialize(obuf=nil, nbuf=nil)
19
+ @n = nil
20
+ @mode = HOW_CHANGED
21
+ _updbufs(obuf, nbuf)
22
+ end
23
+
24
+ def _updbufs(obuf=nil, nbuf=nil)
25
+ @obuf = obuf ? obuf : ''
26
+ @nbuf = nbuf
27
+ mode()
28
+ end
29
+
30
+ def mode(mode=nil)
31
+ @mode = mode if mode
32
+ @buf = (@mode == HOW_CHANGED && @nbuf) ? @nbuf : @obuf
33
+ @sz = @buf.length
34
+ @n.mode(mode) if @n && mode
35
+ end
36
+
37
+ def data(ofs, size)
38
+ return @n.data(ofs - @sz, size) if ofs > @sz
39
+ return @buf[ofs .. -1] + @n.data(0, size - @sz + ofs) if @sz < ofs+size
40
+ return @buf[ofs, size]
41
+ end
42
+
43
+ def all; return @buf + (@n ? @n.all() : '') end
44
+ def size; return @sz + (@n ? @n.size() : 0) end
45
+
46
+ def split(ofs, data, nu=false)
47
+ if ofs+(nu ? 0 : data.length) == @sz
48
+ tail = @n
49
+ else
50
+ ntail = @nbuf ? @nbuf[ofs + (nu ? 0 : data.length) .. -1] : nil
51
+ tail = Change.new(@obuf[ofs + (nu ? 0 : data.length) .. -1], ntail)
52
+ tail.n = @n
53
+ end
54
+ if ofs != 0
55
+ body = Change.new(nu ? nil : @obuf[ofs, data.length], data)
56
+ body.n = tail
57
+ _updbufs(@buf[0, ofs], @nbuf ? @nbuf[0, ofs] : nil)
58
+ @n = body
59
+ else
60
+ _updbufs(nu ? nil : @obuf[0, data.length], data)
61
+ @n = tail
62
+ end
63
+ mode(@mode)
64
+ end
65
+
66
+ def insert(ofs, data)
67
+ return @sz + @n.insert(ofs - @sz, data) if ofs > @sz
68
+ LOG.debug("inserting #{data} @#{ofs} of #{@buf} #{@sz}")
69
+ if @nbuf
70
+ @nbuf = @nbuf[0, ofs] + data + @nbuf[ofs..-1]
71
+ mode()
72
+ return ofs
73
+ end
74
+ split(ofs, data, true)
75
+ mode()
76
+ return ofs
77
+ end
78
+
79
+ def change(ofs, data)
80
+ return @sz + @n.change(ofs - @sz, data) if ofs > @sz
81
+ nxt = data.length - @sz + ofs
82
+ size = nxt>0 ? data.length-nxt : data.length
83
+ @n.change(0, data[size..-1]) if nxt > 0
84
+ if @nbuf
85
+ @nbuf = @nbuf[0,ofs] + data[0, size] + @nbuf[ofs+size..-1]
86
+ mode()
87
+ return ofs
88
+ end
89
+ split(ofs, data[0, size])
90
+ mode()
91
+ return ofs
92
+ end
93
+
94
+ def undo(ofs)
95
+ LOG.debug("undo #{ofs} #{@buf}")
96
+ return @n.undo(ofs - @sz) if ofs >= @sz
97
+ raise "Change not found @#{ofs}" if ofs != 0 || !@nbuf
98
+ @nbuf = nil
99
+ mode()
100
+ end
101
+
102
+ def revert
103
+ @nbuf = nil
104
+ mode()
105
+ @n.revert if @n
106
+ end
107
+
108
+ def changed?(ofs, size)
109
+ return @n.changed?(ofs - @sz, size) if ofs >= @sz
110
+ return true if @nbuf
111
+ return @n.changed?(0, size - @sz + ofs) if @sz < ofs+size
112
+ return false
113
+ end
114
+
115
+ def hex(writer, ofs, size, col)
116
+ if ofs > @sz
117
+ return size if !n
118
+ return n.hex(writer, ofs - @sz, size, col)
119
+ end
120
+ sz = @sz < ofs+size ? @sz-ofs : size
121
+ writer.addBytes(@buf[ofs, sz], @nbuf ? col : nil)
122
+ return 0 if sz==size
123
+ return n.hex(writer, 0, size-sz, col) if n
124
+ return size-sz
125
+ end
126
+
127
+ def getChanges(ofs=0)
128
+ ch = {}
129
+ if @nbuf
130
+ ch[ofs] = [@obuf, @nbuf]
131
+ end
132
+ ch = ch.merge(@n.getChanges(ofs+@sz)) if @n
133
+ return ch
134
+ end
135
+
136
+ def normalize()
137
+ while @n && !@nbuf && @obuf.length==0
138
+ @obuf = @n.obuf
139
+ @nbuf = @n.nbuf
140
+ @n = @n.n
141
+ end
142
+ @n=@n.n while @n && !@n.nbuf && @n.obuf.length==0
143
+ while @n &&
144
+ ((@obuf.length>0 && @n.obuf.length>0) || (@obuf.length == 0 && @n.obuf.length==0)) &&
145
+ ((@nbuf && @n.nbuf) || (!@nbuf && !@n.nbuf))
146
+ @obuf += @n.obuf
147
+ @nbuf = @nbuf ? @nbuf+@n.nbuf : nil
148
+ @n=@n.n
149
+ end
150
+ mode()
151
+ @n.normalize() if @n
152
+ end
153
+
154
+ def dump()
155
+ printf("#{@sz}:O(#{@obuf.length})\t\t%s\n", @nbuf ? "N(#{@nbuf.length if @nbuf})" : "")
156
+ @n.dump() if @n
157
+ end
158
+
159
+ def cload(ofs, bytes, len)
160
+ LOG.debug("load #{ofs} #{bytes} #{len}")
161
+ return @n.cload(ofs - @sz, bytes, len) if ofs > @sz
162
+ change(ofs, bytes.length>0 ? bytes : '*'*len)
163
+ nd = ofs==0 ? self : @n
164
+ nd.nbuf = nd.obuf
165
+ nd.obuf = bytes
166
+ end
167
+ end
168
+
169
+ # Changeable
170
+
171
+ def initialize(fileOrBytes, fileSize=nil)
172
+ LOG.level = Logger::INFO
173
+ @col = Colorizer.instance()
174
+ @mode = HOW_CHANGED
175
+ @root = nil
176
+ addData(fileOrBytes, fileSize)
177
+ end
178
+
179
+ def addData(fileOrBytes, size=nil)
180
+ if fileOrBytes.is_a?(IO)
181
+ data = fileOrBytes.read(size)
182
+ else
183
+ data = fileOrBytes
184
+ end
185
+ data = @root.buf + data if @root
186
+ @root = Change.new(data)
187
+ end
188
+
189
+
190
+ def mode(how)
191
+ @root.mode(how)
192
+ @mode = how
193
+ end
194
+
195
+ def insert(offset, data)
196
+ return if !data || !data.length
197
+ @root.insert(offset, data)
198
+ @root.normalize()
199
+ end
200
+
201
+ def undo(offset)
202
+ @root.undo(offset)
203
+ @root.normalize()
204
+ end
205
+
206
+ def change(ofs, bytes)
207
+ @root.change(ofs, bytes)
208
+ @root.normalize()
209
+ return ofs
210
+ end
211
+
212
+ def changed?(ofs, size=1); return @root.changed?(ofs, size) end
213
+
214
+ def debug(); LOG.level = Logger::DEBUG end
215
+
216
+ def dbgdump
217
+ LOG.debug("---#{@root.size()}---\n")
218
+ @root.dump()
219
+ end
220
+
221
+ def getData(ofs, size); return @root.data(ofs, size) end
222
+
223
+ def bytes; return @root.all() end
224
+
225
+ def getChanges; @root.getChanges(); end
226
+
227
+ def revert(what)
228
+ if what=='all'
229
+ @root.revert()
230
+ @root.normalize()
231
+ return true
232
+ end
233
+ undo(what)
234
+ return true
235
+ end
236
+
237
+
238
+ def curcol; @mode == HOW_ORIGINAL ? COL_ORIGINAL : COL_CHANGED end
239
+
240
+ def colVal(ofs, size)
241
+ fmt = "%#{size*2}.#{size*2}X"
242
+ u = size == 2 ? "v" : V
243
+ return colStr( sprintf(fmt, getData(ofs, size).unpack(u)[0]) , changed?(ofs,size))
244
+ end
245
+
246
+ def colStr(str, cond=true)
247
+ str = sprintf("%04X", str) if !str.is_a?(String)
248
+ return str if !cond
249
+ return @col.color(curcol(), str)
250
+ end
251
+
252
+
253
+ def parseHow(how)
254
+ return HOW_CHANGED if !how || how == HOW_CHANGED
255
+ return HOW_ORIGINAL if how == HOW_ORIGINAL
256
+ return HOW_ORIGINAL if how[0] == 'o' || how[0] == 'O'
257
+ return HOW_CHANGED
258
+ end
259
+
260
+
261
+ def hex(writer, ofs, size, how)
262
+ mode(parseHow(how))
263
+ col = curcol()
264
+ return @root.hex(writer, ofs, size, col)
265
+ end
266
+
267
+
268
+ def saveData(file)
269
+ mode(HOW_CHANGED)
270
+ file.write(bytes())
271
+ end
272
+
273
+ def saveChanges(file)
274
+ mode(HOW_CHANGED)
275
+ chs = getChanges()
276
+ file.write([chs.length].pack('V'))
277
+ chs.each{|o,bts|
278
+ flg = bts[0].length==0 ? 0x80000000 : 0
279
+ file.write([o, bts[1].length | flg ].pack('VV'))
280
+ file.write(bts[0]) if flg==0
281
+ }
282
+ end
283
+
284
+ def loadChanges(file)
285
+ mode(HOW_CHANGED)
286
+ @root.revert
287
+ clen = file.read(4).unpack('V')[0]
288
+ for _ in 0..clen-1
289
+ ofs, len = file.read(8).unpack('VV')
290
+ isNu = len & 0x80000000 !=0
291
+ len &= 0x7FFFFFFF
292
+ @root.cload(ofs, isNu ? "" : file.read(len), len)
293
+ end
294
+ mode(HOW_CHANGED)
295
+ end
296
+
297
+ end
298
+
299
+ end
@@ -1,3 +1,5 @@
1
+ require 'singleton'
2
+
1
3
  module Resedit
2
4
 
3
5
  class Colorizer
@@ -12,8 +14,10 @@ module Resedit
12
14
 
13
15
  attr_accessor :on
14
16
 
15
- def initialize(on=true)
16
- @on = on;
17
+ include Singleton
18
+
19
+ def initialize()
20
+ @on = true
17
21
  end
18
22
 
19
23
  def color(col, text)
@@ -1,4 +1,4 @@
1
- require 'resedit/app/app'
1
+ require 'resedit/classes/colorizer'
2
2
 
3
3
  module Resedit
4
4
 
@@ -10,7 +10,7 @@ module Resedit
10
10
  @written = 0
11
11
  @charsInLine = 0x10
12
12
  @addr = addr
13
- @col = App::get().col
13
+ @col = Colorizer.instance()
14
14
  @size = 0
15
15
  @line = nil
16
16
  @cline = ''
@@ -0,0 +1,66 @@
1
+ module Resedit
2
+
3
+ class CodePatch
4
+ FMT_BINARY = 0
5
+ FMT_HEXSTRING = 1
6
+
7
+ class Chunk
8
+ NOP = "\x90"
9
+ attr_reader :data, :ofs, :size, :format
10
+
11
+ def initialize(data, format, splitter=NOP)
12
+ splitter.force_encoding(Encoding::ASCII_8BIT)
13
+ @data, @format = data, format
14
+ @ofs, @size = [], []
15
+ ofs=0
16
+ data.split(splitter).each{ |part|
17
+ @ofs += [ofs]
18
+ @size += [part.length()]
19
+ ofs += part.length+1
20
+ }
21
+ end
22
+
23
+ def addr(idx, adr)
24
+ adr[0] += @ofs[idx]
25
+ return adr
26
+ end
27
+
28
+ def hexdata()
29
+ @data.each_byte.map { |b| sprintf("%02X",b) }.join
30
+ end
31
+
32
+ def value(idx, size, adr = nil, rep = "\xFF\xFF\xFF\xFF")
33
+ NOP.force_encoding(Encoding::ASCII_8BIT)
34
+ rep.force_encoding(Encoding::ASCII_8BIT)
35
+ ret = data[@ofs[idx], @size[idx]]
36
+ if adr and rep
37
+ #replace with seg:ofs
38
+ ret.gsub!(rep, mkadr(adr))
39
+ end
40
+ raise "Code is bigger #{ret.length()} than expected #{size}" if ret.length>size
41
+ while ret.length()<size
42
+ ret += NOP
43
+ end
44
+ if @format == CodePatch::FMT_HEXSTRING
45
+ ret = ret.each_byte.map { |b| sprintf("%02X",b) }.join
46
+ end
47
+ return ret
48
+ end
49
+
50
+ def mkadr(adr)
51
+ ret = (adr[0]&0xFF).chr + ((adr[0]>>8)&0xFF).chr
52
+ ret += (adr[1]&0xFF).chr + ((adr[1]>>8)&0xFF).chr
53
+ return ret
54
+ end
55
+
56
+ end
57
+
58
+ def self.loadPatch(fname, format = FMT_HEXSTRING, chunksplit="\x90\x90\x90\x90\x90")
59
+ chunksplit.force_encoding(Encoding::ASCII_8BIT)
60
+ bytes = File.read(fname, encoding:Encoding::ASCII_8BIT)
61
+ return bytes.split(chunksplit).each.map{|data| CodePatch::Chunk.new(data, format)}
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -1,6 +1,6 @@
1
1
  require 'resedit/mz/mz_header'
2
2
  require 'resedit/mz/mz_body'
3
- require 'resedit/mz/hexwriter'
3
+ require 'resedit/classes/hexwriter'
4
4
  require 'resedit/mz/mzenv'
5
5
 
6
6
  module Resedit
@@ -32,7 +32,7 @@ module Resedit
32
32
  @name = File.basename(@path, ".*")
33
33
  hi = @header.info()
34
34
  env().set(:entry, hi[:CS].to_s+":"+hi[:IP].to_s)
35
- env().set(:append, sprintf("%04X:0",@body.appSeg))
35
+ env().set(:append, sprintf("0:0"))
36
36
  end
37
37
 
38
38
 
@@ -90,8 +90,9 @@ module Resedit
90
90
  end
91
91
 
92
92
 
93
- def append(value, type=nil)
94
- res = @body.append(getValue(value,type))
93
+ def append(value, type=nil, where=nil)
94
+ where = s2i(where) if where
95
+ res = @body.append(getValue(value,type), where)
95
96
  s = ""
96
97
  res.each{|a|
97
98
  if a.is_a?(Array)
@@ -105,9 +106,9 @@ module Resedit
105
106
  end
106
107
 
107
108
 
108
- def replace(value, type=nil)
109
+ def replace(value, type=nil, where=nil)
109
110
  @body.removeAppend()
110
- return append(value,type)
111
+ return append(value,type, where)
111
112
  end
112
113
 
113
114
 
@@ -120,7 +121,7 @@ module Resedit
120
121
  else
121
122
  res = @body.change(ofs,value) + @header.headerSize()
122
123
  end
123
- log("Change added at %08X", res)
124
+ log("Change added at %08X", res) if res
124
125
  end
125
126
 
126
127
  def reloc(ofs)
@@ -167,7 +168,6 @@ module Resedit
167
168
  }
168
169
  end
169
170
 
170
-
171
171
  end
172
172
 
173
173
  end
@@ -1,4 +1,5 @@
1
- require 'resedit/mz/changeable'
1
+ require 'resedit/classes/changeable'
2
+
2
3
  begin
3
4
  require 'crabstone'
4
5
  include Crabstone
@@ -12,10 +13,16 @@ module Resedit
12
13
 
13
14
  class MZBody < Changeable
14
15
 
15
- attr_reader :segments, :appSeg
16
+ attr_reader :segments, :appSeg, :mz
16
17
 
17
18
  def initialize(mz, file, size)
18
- super(mz, file, size)
19
+ @mz = mz
20
+ super(file, size)
21
+ @segments = nil
22
+ @addsz = 0
23
+ end
24
+
25
+ def reloadSegments()
19
26
  @segments = Set.new()
20
27
  for i in 0..@mz.header.info[:NumberOfRelocations]-1
21
28
  r = @mz.header.getRelocation(i)
@@ -23,22 +30,25 @@ module Resedit
23
30
  val = segData(r, 2).unpack('v')[0]
24
31
  @segments.add(val)
25
32
  end
26
- @appSeg = (@realSize >> 4) + 1
27
33
  end
28
34
 
29
-
30
- def loadChanges(f)
31
- super(f)
32
- @appSeg = (@realSize >> 4) + 1
33
- @segments.add(@appSeg)
35
+ def patchRelocs(add)
36
+ @segments = Set.new()
37
+ for i in 0..@mz.header.info[:NumberOfRelocations]-1
38
+ r = @mz.header.getRelocation(i)
39
+ @segments.add(r[1])
40
+ ofs = seg2Linear(r[0], r[1])
41
+ val = getData(ofs, 2).unpack('v')[0] + add
42
+ change(ofs, [val].pack('v'))
43
+ @segments.add(val)
44
+ end
34
45
  end
35
46
 
36
-
37
47
  def seg2Linear(a,s) (s << 4) + a end
38
48
 
39
-
40
49
  def seg4Linear(linear)
41
50
  linear >>= 4
51
+ reloadSegments() if !@segments
42
52
  min = @segments.sort.reverse.find{|e| e <= linear}
43
53
  return min ? min : 0
44
54
  end
@@ -58,51 +68,42 @@ module Resedit
58
68
 
59
69
  def segData(reloc, size, isStr=false)
60
70
  ofs = seg2Linear(reloc[0], reloc[1])
61
- return "None" if ofs>@bytes.length
71
+ #return "None" if ofs > @root.size()
62
72
  return getData(ofs, size) if !isStr
63
73
  return colVal(ofs, size)
64
74
  end
65
75
 
66
76
 
67
77
  def removeAppend()
68
- @segments.each{|s|
69
- @segments.delete(s) if (s << 4) > @realSize
70
- }
71
- super()
78
+ mode(HOW_CHANGED)
79
+ undo(0) if @root.obuf.length==0
80
+ @addsz = 0
72
81
  end
73
82
 
74
-
75
83
  def revert(what)
76
- @realOfs = @mz.header.headerSize()
77
84
  super(what)
85
+ @addsz = 0
78
86
  end
79
87
 
80
-
81
- def append(bytes)
82
- mode(HOW_ORIGINAL)
83
- res = 0
84
- addseg = false
85
- if !@add
86
- addseg = true
87
- res = 0x10 - (@realSize % 0x10)
88
- res = 0 if res == 0x10
89
- bytes = ("\x90" * res).force_encoding(Encoding::ASCII_8BIT) + bytes if res > 0
90
- end
91
- res += super(bytes)
92
- @mz.header.setCodeSize(@bytes.length + @add.length)
88
+ def append(bytes, where=nil)
89
+ mode(HOW_CHANGED)
90
+ res = @addsz
91
+ buf = @addsz>0 ? @root.nbuf[0, @addsz] : ''
92
+ buf += bytes
93
+ removeAppend()
94
+ @addsz = buf.length
95
+ sz = @mz.header.rebuildHeader(@addsz)
96
+ insert(0, bytes + "\x00"*(sz-@addsz))
93
97
  seg = linear2seg(res)
94
- res = [res, seg]
95
- if addseg
96
- raise "Segs not match" if (@appSeg << 4) != res[0]
97
- @segments.add(@appSeg)
98
- res += [ [ 0, @appSeg] ]
99
- end
98
+ res = [res, seg, sz/0x10]
99
+ patchRelocs(sz/0x10)
100
100
  return res
101
101
  end
102
102
 
103
103
 
104
104
  def print(what, how)
105
105
  if what=="header"
106
+ reloadSegments() if !@segments
106
107
  puts "Known segments: " + @segments.sort.map{ |i| sprintf('%04X',i) }.join(", ")
107
108
  return true
108
109
  end
@@ -1,4 +1,4 @@
1
- require 'resedit/mz/changeable'
1
+ require 'resedit/classes/changeable'
2
2
 
3
3
  module Resedit
4
4
 
@@ -8,17 +8,18 @@ module Resedit
8
8
  PARA = 0x10
9
9
  HSIZE = 0x1C
10
10
 
11
- attr_reader :info
11
+ attr_reader :info, :mz
12
12
 
13
13
  def initialize(mz, file, size)
14
14
  raise "Not MZ file" if size < HSIZE
15
- super(mz, file, HSIZE)
15
+ @mz = mz
16
+ super(file, HSIZE)
16
17
  @fsize = size
17
18
  @_infoOrig = loadInfo()
18
19
  @_info = nil
19
20
  @info = @_infoOrig
20
21
  raise "Not MZ file" if MAGIC != @info[:Magic]
21
- readMore(file, headerSize() - HSIZE)
22
+ addData(file, headerSize() - HSIZE)
22
23
  end
23
24
 
24
25
 
@@ -56,8 +57,22 @@ module Resedit
56
57
  change(2, ch.pack('vv'))
57
58
  end
58
59
 
59
- def setCodeSize(size)
60
- changeSize(size + headerSize())
60
+ def rebuildHeader(codesize)
61
+ mode(HOW_ORIGINAL)
62
+ ss = @info[:SS]
63
+ cs = @info[:CS]
64
+ sz = fileSize()-headerSize()
65
+ codesize += PARA - codesize % PARA if codesize % PARA!=0
66
+ changeSize(sz + codesize + headerSize())
67
+ paras = codesize / PARA
68
+ change(14, [ss+paras].pack('v'))
69
+ change(22, [cs+paras].pack('v'))
70
+ for i in 0..@mz.header.info[:NumberOfRelocations]-1
71
+ rel = getRelocation(i)
72
+ rel[1]+=paras
73
+ setRelocation(i, rel)
74
+ end
75
+ return codesize
61
76
  end
62
77
 
63
78
  def addHeaderSize(size)
@@ -88,6 +103,11 @@ module Resedit
88
103
  return getData(@info[:RelocTableOffset] + idx * 4, 4).unpack('vv')
89
104
  end
90
105
 
106
+ def setRelocation(idx, data)
107
+ raise "Wrong relocation index " if idx<0 || idx>@info[:NumberOfRelocations]
108
+ change(@info[:RelocTableOffset] + idx * 4, data.pack('vv'))
109
+ end
110
+
91
111
 
92
112
  def freeSpace(middle = false)
93
113
  return @info[:RelocTableOffset] - HSIZE if middle
@@ -109,14 +129,13 @@ module Resedit
109
129
  mode(HOW_CHANGED)
110
130
  end
111
131
  val = @mz.body.linear2seg(ofs)
112
- puts "VAL"+ val.to_s()
113
132
  pos = @info[:RelocTableOffset]+@info[:NumberOfRelocations]*4
133
+ cnt = @info[:NumberOfRelocations]
114
134
  change(pos, val.pack('vv'))
115
- change(6, [@info[:NumberOfRelocations]+1].pack('v'))
135
+ change(6, [cnt+1].pack('v'))
116
136
  return true
117
137
  end
118
138
 
119
-
120
139
  def print(what, how)
121
140
  mode(parseHow(how))
122
141
  if what == "header"
@@ -128,11 +147,11 @@ module Resedit
128
147
  puts
129
148
  fsz = fileSize()
130
149
  hsz = headerSize()
131
- s = colStr(sprintf("%d (%X)", fsz,fsz), changed?(2,4))
150
+ s = colStr(sprintf("%d (%X)", fsz,fsz), changed?(2, 4))
132
151
  printf("mz file size: %s\treal file size: %d (0x%X)\n", s, @fsize, @fsize)
133
- printf("header size: %s\n", colStr(hsz, changed?(8)))
134
- printf("code size: %s\n", colStr(fsz - hsz, @mz.body.add != nil))
135
- printf("reloc table size: %s\n", colStr(@info[:NumberOfRelocations] * 4, changed?(6)))
152
+ printf("header size: %s\n", colStr(hsz, changed?(8, 2)))
153
+ printf("code size: %s\n", colStr(fsz - hsz, @mz.body.changed?(0)))
154
+ printf("reloc table size: %s\n", colStr(@info[:NumberOfRelocations] * 4, changed?(6, 2)))
136
155
  printf("free space in header: before relocs 0x%X, after relocs 0x%X\n", freeSpace(true), freeSpace())
137
156
  return true
138
157
  end
@@ -148,7 +167,6 @@ module Resedit
148
167
  end
149
168
  return true
150
169
  end
151
- return super(what, how)
152
170
  end
153
171
 
154
172
 
@@ -37,7 +37,7 @@ module Resedit
37
37
  sz = s.length / 2 + s.length % 2 if !sz || sz==0
38
38
  hx = eval('0x'+s, binding())
39
39
  s=""
40
- for i in 0..sz-1
40
+ for _ in 0..sz-1
41
41
  s += sprintf("%02X", hx & 0xFF)
42
42
  hx >>= 8
43
43
  end
@@ -170,7 +170,7 @@ module Resedit
170
170
  bytes.each_byte{|b|
171
171
  raise sprintf("No byte in encode table: %02X", b) if !tbl[b]
172
172
  val = tbl[b][0]
173
- for i in 0..tbl[b][1]-1
173
+ for _ in 0..tbl[b][1]-1
174
174
  byte |= ((val & 1) << bytelen)
175
175
  val >>= 1
176
176
  bytelen += 1
@@ -32,7 +32,7 @@ module Resedit
32
32
  end
33
33
  end
34
34
 
35
- def addLine(line, meta)
35
+ def addLine(line, meta = nil)
36
36
  line.encode!("utf-8",@encoding) if @encoding
37
37
  line.force_encoding('utf-8')
38
38
  @lines += [line]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resedit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: '1.6'
5
5
  platform: ruby
6
6
  authors:
7
7
  - bjfn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-02 00:00:00.000000000 Z
11
+ date: 2017-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chunky_png
@@ -49,20 +49,21 @@ files:
49
49
  - lib/resedit.rb
50
50
  - lib/resedit/app/app.rb
51
51
  - lib/resedit/app/app_command.rb
52
- - lib/resedit/app/colorizer.rb
53
52
  - lib/resedit/app/font_convert.rb
54
53
  - lib/resedit/app/io_commands.rb
55
54
  - lib/resedit/app/mz_command.rb
56
55
  - lib/resedit/app/std_commands.rb
57
56
  - lib/resedit/app/text_convert.rb
57
+ - lib/resedit/classes/changeable.rb
58
+ - lib/resedit/classes/colorizer.rb
59
+ - lib/resedit/classes/hexwriter.rb
58
60
  - lib/resedit/convert/bitconv.rb
61
+ - lib/resedit/convert/codepatch.rb
59
62
  - lib/resedit/font/font.rb
60
63
  - lib/resedit/font/font_char.rb
61
64
  - lib/resedit/image/image.rb
62
65
  - lib/resedit/image/image_factory.rb
63
66
  - lib/resedit/image/png_image.rb
64
- - lib/resedit/mz/changeable.rb
65
- - lib/resedit/mz/hexwriter.rb
66
67
  - lib/resedit/mz/mz.rb
67
68
  - lib/resedit/mz/mz_body.rb
68
69
  - lib/resedit/mz/mz_header.rb
@@ -83,9 +84,9 @@ require_paths:
83
84
  - lib
84
85
  required_ruby_version: !ruby/object:Gem::Requirement
85
86
  requirements:
86
- - - ">="
87
+ - - "~>"
87
88
  - !ruby/object:Gem::Version
88
- version: '0'
89
+ version: '2.0'
89
90
  required_rubygems_version: !ruby/object:Gem::Requirement
90
91
  requirements:
91
92
  - - ">="
@@ -1,248 +0,0 @@
1
- require 'resedit/app/colorizer'
2
- require 'resedit/mz/hexwriter'
3
- require 'resedit/mz/mzenv'
4
-
5
- module Resedit
6
-
7
- class Changeable
8
- HOW_CHANGED = 0
9
- HOW_ORIGINAL = 1
10
- COL_CHANGED = Colorizer::YELLOW
11
- COL_ORIGINAL = Colorizer::PURPLE
12
-
13
- attr_reader :mz, :bytes, :add, :changes, :realSize, :realOfs
14
-
15
- def initialize(mz, file, size)
16
- @mz = mz
17
- @bytes = file.read(size)
18
- @realOfs = 0
19
- @realSize = @bytes.size
20
- @add = nil
21
- @changes = {}
22
- @c2 = []
23
- @col = App::get().col
24
- @mode = HOW_ORIGINAL
25
- end
26
-
27
- def readMore(file, size)
28
- @bytes += file.read(size)
29
- @realSize = @bytes.size
30
- end
31
-
32
-
33
- def mode(how)
34
- return if @mode == how
35
- if how == HOW_CHANGED
36
- @bytes += @add if @add
37
- else
38
- @add = @bytes[@realSize..-1] if @bytes.length > @realSize
39
- @bytes = @bytes[0, @realSize]
40
- end
41
- @changes.each{|c,bts|
42
- @changes[c] = @bytes[c, bts.length]
43
- bts.each_byte{|b|
44
- @bytes[c] = b.chr
45
- c += 1
46
- }
47
- }
48
- @mode = how
49
- end
50
-
51
- def append(bytes)
52
- mode(HOW_ORIGINAL)
53
- pos = @bytes.length + (@add ? @add.length : 0)
54
- @add = @add ? @add + bytes : bytes
55
- return pos
56
- end
57
-
58
- def removeAppend()
59
- mode(HOW_ORIGINAL)
60
- @add = nil
61
- @bytes = @bytes[0,@realSize]
62
- return true
63
- end
64
-
65
-
66
- def changed?(ofs, size=2)
67
- return true if ofs+size > @realSize
68
- lower = @c2.find { |e| e < (ofs + size) }
69
- return false if !lower
70
- return lower + @changes[lower].length > ofs
71
- end
72
-
73
- def nextChange(ofs)
74
- return ofs if changed?(ofs,1)
75
- return @c2.reverse.find { |e| e > ofs }
76
- end
77
-
78
- def checkRange(ofs, size)
79
- raise "Wrong offset: "+ofs.to_s if ofs < 0 || ofs >= @bytes.length
80
- raise "Byte range overflow: " + ((ofs + size)-@bytes.length).to_s if ofs + size > @bytes.length
81
- end
82
-
83
- def bufWrite(buf, str, index)
84
- return buf[0, index] + str + buf[index+str.length .. -1]
85
- end
86
-
87
- def change(ofs, bytes)
88
- if ofs > @realSize
89
- mode(HOW_CHANGED)
90
- checkRange(ofs, bytes.length)
91
- bytes.each_byte{|b|
92
- @bytes[ofs] = b.chr
93
- ofs += 1
94
- }
95
- return ofs
96
- end
97
- mode(HOW_ORIGINAL)
98
- checkRange(ofs, bytes.length)
99
- if changed?(ofs,bytes.length)
100
- lower = @c2.find { |e| e < ofs + bytes.length }
101
- strt = [lower, ofs].min()
102
- en = [lower+@changes[lower].length, ofs+bytes.length].max()
103
- buf = ("\0" * (en-strt)).force_encoding(Encoding::ASCII_8BIT)
104
- buf = bufWrite(buf, @changes[lower], lower - strt)
105
- buf = bufWrite(buf, bytes, ofs - strt)
106
- @changes.delete(lower)
107
- @c2.delete(lower)
108
- change(strt, buf)
109
- else
110
- @changes[ofs] = bytes
111
- @c2 = @changes.keys.reverse
112
- end
113
- return ofs
114
- end
115
-
116
- def revertChange(ofs)
117
- raise sprintf("Change not found at: ") if !@changes[ofs]
118
- mode(HOW_ORIGINAL)
119
- @changes.delete(ofs)
120
- @c2 = @changes.keys.reverse
121
- return ofs
122
- end
123
-
124
- def revert(what)
125
- mode(HOW_ORIGINAL)
126
- if what=='all'
127
- removeAppend()
128
- @changes = {}
129
- @c2=[]
130
- return true
131
- end
132
- if what == 'append' || what==@realSize+@realOfs
133
- removeAppend()
134
- return true
135
- end
136
- return false if !@changes[what-@realOfs]
137
- revertChange(what-@realOfs)
138
- return true
139
- end
140
-
141
-
142
- def curcol() return @mode == HOW_ORIGINAL ? COL_ORIGINAL : COL_CHANGED end
143
-
144
- def colVal(ofs, size)
145
- fmt = "%#{size*2}.#{size*2}X"
146
- u = size == 2 ? "v" : V
147
- return colStr( sprintf(fmt, getData(ofs, size).unpack(u)[0]) , changed?(ofs,size))
148
- end
149
-
150
- def colStr(str, cond=true)
151
- str = sprintf("%04X", str) if !str.is_a?(String)
152
- return str if !cond
153
- return @col.color(curcol(), str)
154
- end
155
-
156
- def getData(ofs, size)
157
- checkRange(ofs, size)
158
- return @bytes[ofs,size]
159
- end
160
-
161
-
162
- def parseHow(how)
163
- return HOW_CHANGED if !how || how == HOW_CHANGED
164
- return HOW_ORIGINAL if how == HOW_ORIGINAL
165
- return HOW_ORIGINAL if how[0] == 'o' || how[0] == 'O'
166
- return HOW_CHANGED
167
- end
168
-
169
- def print(what, how)
170
- mode(parseHow(how))
171
- if what=="changes"
172
- @changes.each{|ofs,bts|
173
- bts = getData(ofs, bts.length)
174
- printf("%08X: %s\n", ofs+@realOfs, colStr(bts.bytes.map { |b| sprintf("%02X",b) }.join))
175
- }
176
- if @add
177
- printf("%08X: %s\n", @realSize+@realOfs, colStr(@add.bytes.map { |b| sprintf("%02X",b) }.join))
178
- end
179
- puts
180
- return true
181
- end
182
- return false
183
- end
184
-
185
-
186
- def hex(writer, ofs, size, how)
187
- mode(parseHow(how))
188
- col = curcol()
189
- return size if ofs > @bytes.length
190
- while size > 0
191
- if ofs>=@realSize
192
- sz = [size, @bytes.length - ofs].min
193
- if sz
194
- writer.addBytes(@bytes[ofs, sz], col)
195
- size -= sz
196
- end
197
- return size
198
- end
199
- x = nextChange(ofs)
200
- x = @realSize if !x
201
- sz = [size, x-ofs].min
202
- if sz
203
- writer.addBytes(@bytes[ofs, sz], nil)
204
- size -= sz
205
- ofs += sz
206
- end
207
- return 0 if size == 0
208
- if @changes[x]
209
- sz = [size, @changes[x].length].min
210
- if sz
211
- writer.addBytes(@bytes[ofs, sz], col)
212
- size -= sz
213
- ofs += sz
214
- end
215
- end
216
- end
217
- end
218
-
219
- def saveData(file)
220
- mode(HOW_CHANGED)
221
- file.write(@bytes)
222
- end
223
-
224
- def saveChanges(file)
225
- mode(HOW_CHANGED)
226
- file.write([@realSize, @changes.length].pack('VV'))
227
- @changes.each{|c,bts|
228
- file.write([c, bts.length].pack('VV'))
229
- file.write(bts)
230
- }
231
- end
232
-
233
- def loadChanges(file)
234
- mode(HOW_CHANGED)
235
- @realSize,clen=file.read(8).unpack('VV')
236
- @add = @bytes[@realSize..-1] if @bytes.length > @realSize
237
- @bytes = @bytes[0, @realSize]
238
- for i in 0..clen-1
239
- ofs, bts = file.read(8).unpack('VV')
240
- @changes[ofs] = file.read(bts)
241
- end
242
- @c2 = @changes.keys.reverse
243
- mode(HOW_ORIGINAL)
244
- end
245
-
246
- end
247
-
248
- end