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,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Resedit
|
4
|
+
|
5
|
+
class KeyboardRuConvertTable < ConvertTable
|
6
|
+
|
7
|
+
def initialize()
|
8
|
+
super()
|
9
|
+
@table={
|
10
|
+
'Q' => 'Й',
|
11
|
+
'W' => 'Ц',
|
12
|
+
'E' => 'У',
|
13
|
+
'R' => 'К',
|
14
|
+
'T' => 'Е',
|
15
|
+
'Y' => 'Н',
|
16
|
+
'U' => 'Г',
|
17
|
+
'I' => 'Ш',
|
18
|
+
'O' => 'Щ',
|
19
|
+
'P' => 'З',
|
20
|
+
'{' => 'Х',
|
21
|
+
'}' => 'Ъ',
|
22
|
+
'A' => 'Ф',
|
23
|
+
'S' => 'Ы',
|
24
|
+
'D' => 'В',
|
25
|
+
'F' => 'А',
|
26
|
+
'G' => 'П',
|
27
|
+
'H' => 'Р',
|
28
|
+
'J' => 'О',
|
29
|
+
'K' => 'Л',
|
30
|
+
'L' => 'Д',
|
31
|
+
':' => 'Ж',
|
32
|
+
"\"" => 'Э',
|
33
|
+
'Z' => 'Я',
|
34
|
+
'X' => 'Ч',
|
35
|
+
'C' => 'С',
|
36
|
+
'V' => 'М',
|
37
|
+
'B' => 'И',
|
38
|
+
'N' => 'Т',
|
39
|
+
'M' => 'Ь',
|
40
|
+
'<' => 'Б',
|
41
|
+
'>' => 'Ю',
|
42
|
+
|
43
|
+
'q' => 'й',
|
44
|
+
'w' => 'ц',
|
45
|
+
'e' => 'у',
|
46
|
+
'r' => 'к',
|
47
|
+
't' => 'е',
|
48
|
+
'y' => 'н',
|
49
|
+
'u' => 'г',
|
50
|
+
'i' => 'ш',
|
51
|
+
'o' => 'щ',
|
52
|
+
'p' => 'з',
|
53
|
+
'[' => 'х',
|
54
|
+
']' => 'ъ',
|
55
|
+
'a' => 'ф',
|
56
|
+
's' => 'ы',
|
57
|
+
'd' => 'в',
|
58
|
+
'f' => 'а',
|
59
|
+
'g' => 'п',
|
60
|
+
'h' => 'р',
|
61
|
+
'j' => 'о',
|
62
|
+
'k' => 'л',
|
63
|
+
'l' => 'д',
|
64
|
+
';' => 'ж',
|
65
|
+
"\'" => 'э',
|
66
|
+
'z' => 'я',
|
67
|
+
'x' => 'ч',
|
68
|
+
'c' => 'с',
|
69
|
+
'v' => 'м',
|
70
|
+
'b' => 'и',
|
71
|
+
'n' => 'т',
|
72
|
+
'm' => 'ь',
|
73
|
+
',' => 'б',
|
74
|
+
'.' => 'ю',
|
75
|
+
|
76
|
+
'~' => 'Ё',
|
77
|
+
'`' => 'ё'
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Resedit
|
2
|
+
|
3
|
+
class TextEscaper
|
4
|
+
|
5
|
+
STD_TABLE = {0x5C=>"\\\\", 0x0A=>"\\n", 0x0D=>"\\r", 0x09=>"\\t", 0x07=>"\\a", 0x08=>"\\b", 0x0C=>"\\f", 0x0B=>"\\v", 0x1B=>"\\e"}
|
6
|
+
|
7
|
+
def escape(line)
|
8
|
+
out=""
|
9
|
+
line.each_byte {|b|
|
10
|
+
out += _escape(b)
|
11
|
+
}
|
12
|
+
return out
|
13
|
+
end
|
14
|
+
|
15
|
+
def unescape(line); end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def tableReplace(str,tbl,numproc=true)
|
20
|
+
ntbl={}
|
21
|
+
if tbl
|
22
|
+
tbl.each{|b,v|
|
23
|
+
ntbl[v[0]]={} if !ntbl[v[0]]
|
24
|
+
ntbl[v[0]][v]=b
|
25
|
+
}
|
26
|
+
end
|
27
|
+
pos=0
|
28
|
+
res=""
|
29
|
+
while pos < str.length
|
30
|
+
val=str[pos]
|
31
|
+
inc=1
|
32
|
+
if ntbl[val]
|
33
|
+
ntbl[val].each{|v,b|
|
34
|
+
next if str.length < pos+v.length+1
|
35
|
+
if v==str[pos,v.length]
|
36
|
+
val=b.chr
|
37
|
+
inc=v.length
|
38
|
+
break
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
if inc==1 && numproc && val=="\\"
|
43
|
+
raise "Bad escape sequence: "+str if str.length < pos+5
|
44
|
+
num = str[pos+1,3]
|
45
|
+
byte = num[0].upcase=="X" ? num[1,2].to_i(16) : num.to_i
|
46
|
+
raise "Bad numeric escape "+num+": "+str if (byte==0 and num!="000" and num!="x00") || byte>255 || byte<0
|
47
|
+
val=byte.chr
|
48
|
+
inc=4
|
49
|
+
end
|
50
|
+
res += val
|
51
|
+
pos += inc
|
52
|
+
end
|
53
|
+
return res
|
54
|
+
end
|
55
|
+
|
56
|
+
def _escape(b); end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
class SlashEscaper < TextEscaper
|
61
|
+
|
62
|
+
def _escape(b)
|
63
|
+
return '\\\\' if b==0x5c
|
64
|
+
b<0x20 ? sprintf("\\x%02X", b) : b.chr
|
65
|
+
end
|
66
|
+
|
67
|
+
def unescape(line)
|
68
|
+
tableReplace(line,{0x5C=>"\\\\"})
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
class StdEscaper < SlashEscaper
|
75
|
+
|
76
|
+
def _escape(b)
|
77
|
+
STD_TABLE[b] ? STD_TABLE[b] : super(b)
|
78
|
+
end
|
79
|
+
|
80
|
+
def unescape(line)
|
81
|
+
tableReplace(line,STD_TABLE)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
class TableEscaper < TextEscaper
|
88
|
+
|
89
|
+
def initialize(table=nil, stdTable=STD_TABLE)
|
90
|
+
@table={}
|
91
|
+
if stdTable
|
92
|
+
stdTable.each {|b, e|
|
93
|
+
add(b, e)
|
94
|
+
}
|
95
|
+
end
|
96
|
+
if table
|
97
|
+
table.each {|b, e|
|
98
|
+
add(b,e)
|
99
|
+
}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def add(byte, esc)
|
104
|
+
@table[byte] = esc
|
105
|
+
end
|
106
|
+
|
107
|
+
def _escape(b)
|
108
|
+
@table[b] ? @table[b] : b.chr
|
109
|
+
end
|
110
|
+
|
111
|
+
def unescape(line)
|
112
|
+
tableReplace(line,@table,false)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
module Resedit
|
3
|
+
|
4
|
+
class TextFormat
|
5
|
+
|
6
|
+
def initialize(encoding)
|
7
|
+
@encoding=encoding
|
8
|
+
end
|
9
|
+
|
10
|
+
def saveLines(fname, lines, meta); end
|
11
|
+
|
12
|
+
def loadLines(fname); end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class FormatTxt < TextFormat
|
17
|
+
|
18
|
+
def initialize(encoding)
|
19
|
+
super((encoding or 'cp1251'))
|
20
|
+
end
|
21
|
+
|
22
|
+
def saveLines(fname, lines, meta)
|
23
|
+
open(fname+".txt", "w:"+@encoding) {|f|
|
24
|
+
lines.each {|l|
|
25
|
+
l.force_encoding('utf-8')
|
26
|
+
f.write(l)
|
27
|
+
f.write("\r\n")
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def loadLines(fname)
|
33
|
+
lns=[]
|
34
|
+
open(fname+".txt", "r:"+@encoding+":utf-8").each_line {|line|
|
35
|
+
lns += [line.chomp]
|
36
|
+
}
|
37
|
+
lns=lns[0..-2] if lns.last == ""
|
38
|
+
return lns
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'resedit/text/format_text'
|
2
|
+
require 'builder'
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
module Resedit
|
6
|
+
|
7
|
+
class FormatXml < TextFormat
|
8
|
+
|
9
|
+
def initialize(encoding)
|
10
|
+
super('utf-8')
|
11
|
+
end
|
12
|
+
|
13
|
+
def saveLines(fname, lines, meta)
|
14
|
+
open(fname+".xml", "w:"+@encoding) {|f|
|
15
|
+
xml=Builder::XmlMarkup.new(:indent => 2 , :target=>f)
|
16
|
+
xml.instruct! :xml, :encoding => @encoding
|
17
|
+
xml.body {|b|
|
18
|
+
lines.each.with_index{|l,i|
|
19
|
+
mt = {'id' => i}
|
20
|
+
mt.update(meta[i]) if meta[i]
|
21
|
+
b.text(l, mt)
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def loadLines(fname)
|
28
|
+
hs={}
|
29
|
+
open(fname+".xml", "r:"+@encoding) {|f|
|
30
|
+
doc=REXML::Document.new(f)
|
31
|
+
doc.elements.each("body/text"){|e|
|
32
|
+
hs[e.attributes['id']] = e.text
|
33
|
+
}
|
34
|
+
}
|
35
|
+
raise "No data in xml" if !hs.length
|
36
|
+
lns=[]
|
37
|
+
for i in 0..hs.length-1
|
38
|
+
raise "Text not found: "+i if !hs[i]
|
39
|
+
lns+=[ hs[i] ]
|
40
|
+
end
|
41
|
+
return lns
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'resedit/app/app'
|
2
|
+
module Resedit
|
3
|
+
|
4
|
+
class Huffman
|
5
|
+
|
6
|
+
class Node
|
7
|
+
attr_accessor :value, :parent, :left, :right
|
8
|
+
|
9
|
+
def initialize(value=nil, parent=nil)
|
10
|
+
@value=value
|
11
|
+
end
|
12
|
+
|
13
|
+
def addNode(isLeft,value=nil)
|
14
|
+
n=Node.new(value)
|
15
|
+
if isLeft
|
16
|
+
@left=n
|
17
|
+
else
|
18
|
+
@right=n
|
19
|
+
end
|
20
|
+
return n
|
21
|
+
end
|
22
|
+
|
23
|
+
def addLeft(value=nil)
|
24
|
+
addNode(true, value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def addRight(value=nil)
|
28
|
+
addNode(false, value)
|
29
|
+
end
|
30
|
+
|
31
|
+
def getLeafs(leftS,rightS,path='')
|
32
|
+
return {path=>@value} if @value
|
33
|
+
l=@left.getLeafs(leftS, rightS, path+leftS)
|
34
|
+
r=@right.getLeafs(leftS, rightS, path+rightS)
|
35
|
+
return l.merge(r)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
class Balancer
|
42
|
+
attr_reader :huff
|
43
|
+
def initialize(huff)
|
44
|
+
@huff = huff
|
45
|
+
@tbl = {}
|
46
|
+
end
|
47
|
+
|
48
|
+
def addData(bytes)
|
49
|
+
bytes.each_byte{|b|
|
50
|
+
@tbl[b] = 0 if !@tbl[b]
|
51
|
+
@tbl[b] += 1
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def balanceValues()
|
56
|
+
end
|
57
|
+
|
58
|
+
def balanceTree()
|
59
|
+
raise "Not implemented."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
attr_reader :tree
|
65
|
+
|
66
|
+
def initialize(zeroLeft, reverseBitsInByte=false)
|
67
|
+
@tree=Huffman::Node.new()
|
68
|
+
@zeroLeft, @reverseBits = zeroLeft,reverseBitsInByte
|
69
|
+
end
|
70
|
+
|
71
|
+
def decodeTable(recalc=false)
|
72
|
+
if @recalc || !@decodeTbl
|
73
|
+
tbl = @tree.getLeafs(@zeroLeft ? '0' : '1', @zeroLeft ? '1' : '0')
|
74
|
+
@decodeTbl = {}
|
75
|
+
tbl.each{|k,v|
|
76
|
+
@decodeTbl[k.length] = {} if !@decodeTbl[k.length]
|
77
|
+
@decodeTbl[k.length][k.to_i(2)] = v
|
78
|
+
}
|
79
|
+
end
|
80
|
+
return @decodeTbl
|
81
|
+
end
|
82
|
+
|
83
|
+
def encodeTable(recalc=false)
|
84
|
+
if @recalc || !@encodeTbl
|
85
|
+
tbl = @tree.getLeafs(@zeroLeft ? '0' : '1', @zeroLeft ? '1' : '0')
|
86
|
+
@encodeTbl = {}
|
87
|
+
tbl.each{|k,v|
|
88
|
+
@encodeTbl[v] = [k.reverse.to_i(2), k.length]
|
89
|
+
}
|
90
|
+
end
|
91
|
+
return @encodeTbl
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def balancer()
|
96
|
+
return Huffman::Balancer.new(self)
|
97
|
+
end
|
98
|
+
|
99
|
+
def debug()
|
100
|
+
tbl=decodeTable()
|
101
|
+
info="---huffman table---\n"
|
102
|
+
bts={}
|
103
|
+
tbl.keys.sort.each{|sz|
|
104
|
+
tbl[sz].each{|k,v|
|
105
|
+
fmt = "0x%02X\t%2d\t%0" + sz.to_s + "b\n"
|
106
|
+
info += sprintf(fmt,v,sz,k)
|
107
|
+
if not bts[v]
|
108
|
+
bts[v] = 1
|
109
|
+
else
|
110
|
+
bts[v] += 1
|
111
|
+
end
|
112
|
+
}
|
113
|
+
}
|
114
|
+
info += sprintf("---%d bytes---\n",bts.length)
|
115
|
+
for i in 0..255
|
116
|
+
if !bts[i]
|
117
|
+
info+=sprintf("0x%02X - ABSENT\n", i)
|
118
|
+
else
|
119
|
+
info+=sprintf("0x%02X - %d times\n", i, bts[i]) if bts[i]!=1
|
120
|
+
end
|
121
|
+
end
|
122
|
+
App.get().logd(info)
|
123
|
+
end
|
124
|
+
|
125
|
+
def revbyte(byte)
|
126
|
+
return byte if !@reverseBits
|
127
|
+
return sprintf("%08b", byte).reverse.to_i(2)
|
128
|
+
end
|
129
|
+
|
130
|
+
def decode(bitstream, endl=0)
|
131
|
+
res = ''
|
132
|
+
tbl = decodeTable()
|
133
|
+
max = tbl.keys.max
|
134
|
+
pos = 0
|
135
|
+
byte = bitstream[pos].ord
|
136
|
+
bytelen = 8
|
137
|
+
buf = 0
|
138
|
+
buflen = 0
|
139
|
+
while true
|
140
|
+
buf <<= 1
|
141
|
+
buflen += 1
|
142
|
+
raise "Huffman decode length overflow" if buflen>max
|
143
|
+
buf |= byte & 1
|
144
|
+
byte >>= 1
|
145
|
+
bytelen -= 1
|
146
|
+
if tbl[buflen] && tbl[buflen][buf]
|
147
|
+
return res if tbl[buflen][buf] == endl
|
148
|
+
res += tbl[buflen][buf].chr
|
149
|
+
buf = 0
|
150
|
+
buflen = 0
|
151
|
+
end
|
152
|
+
|
153
|
+
next if bytelen>0
|
154
|
+
pos += 1
|
155
|
+
break if pos >= bitstream.length
|
156
|
+
bytelen = 8
|
157
|
+
byte = revbyte(bitstream[pos].ord)
|
158
|
+
end
|
159
|
+
return res
|
160
|
+
end
|
161
|
+
|
162
|
+
def encode(bytes, endl=0)
|
163
|
+
if endl != nil && bytes[-1] != endl
|
164
|
+
bytes += endl.chr
|
165
|
+
end
|
166
|
+
res = ''
|
167
|
+
tbl = encodeTable()
|
168
|
+
byte = 0
|
169
|
+
bytelen = 0
|
170
|
+
bytes.each_byte{|b|
|
171
|
+
raise sprintf("No byte in encode table: %02X", b) if !tbl[b]
|
172
|
+
val = tbl[b][0]
|
173
|
+
for i in 0..tbl[b][1]-1
|
174
|
+
byte |= ((val & 1) << bytelen)
|
175
|
+
val >>= 1
|
176
|
+
bytelen += 1
|
177
|
+
if bytelen == 8
|
178
|
+
res += revbyte(byte).chr
|
179
|
+
bytelen = 0
|
180
|
+
byte = 0
|
181
|
+
end
|
182
|
+
end
|
183
|
+
}
|
184
|
+
res += revbyte(byte).chr if bytelen > 0
|
185
|
+
return res
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|