resedit 1.3.1

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.
@@ -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