resedit 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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