resedit 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/resedit +11 -0
- data/lib/resedit.rb +17 -0
- data/lib/resedit/app/app.rb +160 -0
- data/lib/resedit/app/app_command.rb +100 -0
- data/lib/resedit/app/colorizer.rb +34 -0
- data/lib/resedit/app/font_convert.rb +54 -0
- data/lib/resedit/app/io_commands.rb +74 -0
- data/lib/resedit/app/mz_command.rb +192 -0
- data/lib/resedit/app/std_commands.rb +69 -0
- data/lib/resedit/app/text_convert.rb +60 -0
- data/lib/resedit/convert/bitconv.rb +48 -0
- data/lib/resedit/font/font.rb +82 -0
- data/lib/resedit/font/font_char.rb +49 -0
- data/lib/resedit/image/image.rb +47 -0
- data/lib/resedit/image/image_factory.rb +33 -0
- data/lib/resedit/image/png_image.rb +38 -0
- data/lib/resedit/mz/changeable.rb +248 -0
- data/lib/resedit/mz/hexwriter.rb +88 -0
- data/lib/resedit/mz/mz.rb +166 -0
- data/lib/resedit/mz/mz_body.rb +141 -0
- data/lib/resedit/mz/mz_header.rb +123 -0
- data/lib/resedit/mz/mzenv.rb +82 -0
- data/lib/resedit/text/conv_keybru.rb +84 -0
- data/lib/resedit/text/conv_table.rb +10 -0
- data/lib/resedit/text/escaper.rb +117 -0
- data/lib/resedit/text/format_text.rb +44 -0
- data/lib/resedit/text/format_xml.rb +46 -0
- data/lib/resedit/text/huffman.rb +190 -0
- data/lib/resedit/text/text.rb +73 -0
- metadata +86 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
module Resedit
|
2
|
+
|
3
|
+
class FontChar
|
4
|
+
attr_accessor :index, :data, :realWidth
|
5
|
+
|
6
|
+
def initialize(width, height, index, data=nil, realWidth=nil)
|
7
|
+
@width, @height, @index = width, height, index
|
8
|
+
@realWidth=realWidth
|
9
|
+
@data=data if (data && data.length==width*height)
|
10
|
+
end
|
11
|
+
|
12
|
+
def hasPixel(x, y)
|
13
|
+
@data[y*@width+x] != 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def draw(image, color, x, y, wColor)
|
17
|
+
for j in 0..@height-1
|
18
|
+
for i in 0..@width-1
|
19
|
+
image.setPixel(x+i, y+j, color) if hasPixel(i,j)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
if @realWidth && @realWidth<@width
|
23
|
+
image.setPixel(x+realWidth, y, wColor)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def scan(image, color, x, y, wColor)
|
28
|
+
@data=[0]*@width*@height
|
29
|
+
@realWidth = nil
|
30
|
+
_hasData = false
|
31
|
+
for j in 0..@height-1
|
32
|
+
for i in 0..@width-1
|
33
|
+
col=image.getPixel(x+i, y+j)
|
34
|
+
if col==color
|
35
|
+
@data[j*@width+i]= 1
|
36
|
+
_hasData = true
|
37
|
+
end
|
38
|
+
if col ==wColor
|
39
|
+
@realWidth = i
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
@data=nil if !_hasData
|
44
|
+
return @data!=nil
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
module Resedit
|
3
|
+
|
4
|
+
class Image
|
5
|
+
# Abstract image class
|
6
|
+
attr_accessor :width, :height
|
7
|
+
TYPE_PNG = 'png'
|
8
|
+
TYPE_BMP = 'bmp'
|
9
|
+
FORMAT_INDEXED = 0
|
10
|
+
FORMAT_32BIT = 1
|
11
|
+
|
12
|
+
|
13
|
+
def fill(color)
|
14
|
+
for j in (0..@height-1)
|
15
|
+
for i in (0..@width-1)
|
16
|
+
setPixel(i, j, color)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def hline(y, color)
|
23
|
+
for i in (0..@width-1)
|
24
|
+
setPixel(i, y, color)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def vline(x, color)
|
30
|
+
for j in (0..@height-1)
|
31
|
+
setPixel(x, j, color)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
#abstract interface
|
37
|
+
def getPixel(x, y); end
|
38
|
+
def setPixel(x, y, color); end
|
39
|
+
|
40
|
+
def save(filename); end
|
41
|
+
|
42
|
+
protected
|
43
|
+
def create(width, height, format); end
|
44
|
+
def load(filename); end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'resedit/image/png_image'
|
2
|
+
require 'resedit/image/image'
|
3
|
+
|
4
|
+
module Resedit
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def createImage(width, height, type=Image::TYPE_PNG, format=Image::FORMAT_INDEXED)
|
9
|
+
type = type[-3..-1] if type.length>3
|
10
|
+
case type
|
11
|
+
when Image::TYPE_PNG
|
12
|
+
img = PngImage.new()
|
13
|
+
else
|
14
|
+
raise "Unknown format #{type}"
|
15
|
+
end
|
16
|
+
img.create(width, height, format)
|
17
|
+
return img
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def loadImage(filename)
|
22
|
+
ext = filename[-3..-1].downcase()
|
23
|
+
case ext
|
24
|
+
when Image::TYPE_PNG
|
25
|
+
img=PngImage.new()
|
26
|
+
else
|
27
|
+
raise "Unknown file format #{filename}"
|
28
|
+
end
|
29
|
+
img.load(filename)
|
30
|
+
return img
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'resedit/image/image'
|
2
|
+
require 'chunky_png'
|
3
|
+
|
4
|
+
module Resedit
|
5
|
+
|
6
|
+
class PngImage < Image
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@img = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def getPixel(x, y)
|
13
|
+
col = @img[x, y]
|
14
|
+
return (col<<24 & 0xFFFFFFFF) | (col>>8)
|
15
|
+
end
|
16
|
+
|
17
|
+
def setPixel(x, y, color)
|
18
|
+
@img[x, y] = ((color<<8 & 0xFFFFFFFF) | (color>>24))
|
19
|
+
end
|
20
|
+
|
21
|
+
def create(width, height, format)
|
22
|
+
@width, @height = width, height
|
23
|
+
@img = ChunkyPNG::Image.new(width, height, ChunkyPNG::Color::TRANSPARENT)
|
24
|
+
end
|
25
|
+
|
26
|
+
def save(filename)
|
27
|
+
filename+='.png' if filename[-4..-1].downcase() != '.png'
|
28
|
+
@img.save(filename)
|
29
|
+
end
|
30
|
+
|
31
|
+
def load(filename)
|
32
|
+
@img = ChunkyPNG::Image.from_file(filename)
|
33
|
+
@width = @img.width
|
34
|
+
@height = @img.height
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,248 @@
|
|
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
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'resedit/app/app'
|
2
|
+
|
3
|
+
module Resedit
|
4
|
+
|
5
|
+
class HexWriter
|
6
|
+
|
7
|
+
attr_accessor :written
|
8
|
+
|
9
|
+
def initialize(addr)
|
10
|
+
@written = 0
|
11
|
+
@charsInLine = 0x10
|
12
|
+
@addr = addr
|
13
|
+
@col = App::get().col
|
14
|
+
@size = 0
|
15
|
+
@line = nil
|
16
|
+
@cline = ''
|
17
|
+
@chr = ''
|
18
|
+
@cchr = ''
|
19
|
+
@pcol = nil
|
20
|
+
@segments = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def setSegments(segments, sfix)
|
24
|
+
@segments = segments.sort.reverse
|
25
|
+
@sfix = sfix
|
26
|
+
end
|
27
|
+
|
28
|
+
def addrFormat()
|
29
|
+
add = ''
|
30
|
+
if @segments
|
31
|
+
seg = (@addr-@sfix) >> 4
|
32
|
+
min = @segments.find{|e| e <= seg}
|
33
|
+
min = 0 if !min
|
34
|
+
add = sprintf(" %04X:%04X", min, @addr - @sfix - (min << 4))
|
35
|
+
end
|
36
|
+
res = sprintf("%08X%s | ", @addr, add)
|
37
|
+
@addr += @charsInLine
|
38
|
+
return res
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def addBytes(bytes, color=nil)
|
43
|
+
bytes.each_byte{|b| addChar(b, color)}
|
44
|
+
end
|
45
|
+
|
46
|
+
def procColored()
|
47
|
+
@line += @col.color(@pcol, @cline)
|
48
|
+
@chr += @col.color(@pcol, @cchr)
|
49
|
+
@cline = ''
|
50
|
+
@cchr = ''
|
51
|
+
end
|
52
|
+
|
53
|
+
def buildLine()
|
54
|
+
procColored() if @pcol
|
55
|
+
puts @line+" | "+@chr
|
56
|
+
@line = nil
|
57
|
+
@chr=''
|
58
|
+
@size = 0
|
59
|
+
end
|
60
|
+
|
61
|
+
def addChar(c, color = nil)
|
62
|
+
c = c.ord
|
63
|
+
@line = addrFormat if !@line
|
64
|
+
procColored if color != @pcol && @pcol
|
65
|
+
if !color
|
66
|
+
@line += sprintf("%02X ",c)
|
67
|
+
@chr += (c<0x20 || c>0x7E) ? '.' : c.chr
|
68
|
+
else
|
69
|
+
@cline += sprintf("%02X ",c)
|
70
|
+
@cchr += (c<0x20 || c>0x7E) ? '.' : c.chr
|
71
|
+
end
|
72
|
+
@pcol = color
|
73
|
+
@size += 1
|
74
|
+
@written += 1
|
75
|
+
if @size == @charsInLine
|
76
|
+
buildLine()
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def finish()
|
81
|
+
return if @size == 0
|
82
|
+
procColored() if @pcol
|
83
|
+
@line += " " * (@charsInLine - @size)
|
84
|
+
buildLine()
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|