| Class | MOFile |
| In: |
lib/gettext/mo.rb
|
| Parent: | Hash |
| Header | = | Struct.new(:magic, :revision, :nstrings, :orig_table_offset, :translated_table_offset, :hash_table_size, :hash_table_offset) | ||
| MAGIC_BIG_ENDIAN | = | "\x95\x04\x12\xde" | ||
| MAGIC_LITTLE_ENDIAN | = | "\xde\x12\x04\x95" | ||
| HASHWORDBITS | = | 32 | From gettext-0.12.1/gettext-runtime/intl/hash-string.h Defines the so called `hashpjw’ function by P.J. Weinberger [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, 1986, 1987 Bell Telephone Laboratories, Inc.] |
| charset | [R] | |
| filename | [R] | |
| last_modified | [RW] | |
| little_endian | [RW] | |
| nplurals | [R] | |
| path | [RW] | |
| plural | [R] |
# File lib/gettext/mo.rb, line 42
42: def initialize(output_charset = nil)
43: @filename = nil
44: @last_modified = nil
45: @little_endian = true
46: @output_charset = output_charset
47: super()
48: end
# File lib/gettext/mo.rb, line 37
37: def self.open(arg = nil, output_charset = nil)
38: result = self.new(output_charset)
39: result.load(arg)
40: end
# File lib/gettext/mo.rb, line 170
170: def hash_string(str)
171: hval = 0
172: i = 0
173: str.each_byte do |b|
174: break if b == '\0'
175: hval <<= 4
176: hval += b.to_i
177: g = hval & (0xf << (HASHWORDBITS - 4))
178: if (g != 0)
179: hval ^= g >> (HASHWORDBITS - 8)
180: hval ^= g
181: end
182: end
183: hval
184: end
# File lib/gettext/mo.rb, line 61
61: def load(arg)
62: if arg.kind_of? String
63: begin
64: st = File.stat(arg)
65: @last_modified = [st.ctime, st.mtime]
66: rescue Exception
67: end
68: load_from_file(arg)
69: else
70: load_from_stream(arg)
71: end
72: @filename = arg
73: self
74: end
# File lib/gettext/mo.rb, line 253
253: def load_from_file(filename)
254: @filename = filename
255: File.open(filename, 'rb'){|f| load_from_stream(f)}
256: end
# File lib/gettext/mo.rb, line 76
76: def load_from_stream(io)
77: magic = io.read(4)
78: case magic
79: when MAGIC_BIG_ENDIAN
80: @little_endian = false
81: when MAGIC_LITTLE_ENDIAN
82: @little_endian = true
83: else
84: raise InvalidFormat.new(sprintf("Unknown signature %s", magic.dump))
85: end
86:
87: header = Header.new(magic, *(io.read(4 * 6).unpack(@little_endian ? 'V6' : 'N6')))
88: raise InvalidFormat.new(sprintf("file format revision %d isn't supported", header.revision)) if header.revision > 0
89:
90: io.pos = header.orig_table_offset
91: orig_table_data = io.read((4 * 2) * header.nstrings).unpack(@little_endian ? 'V*' : 'N*')
92:
93: io.pos = header.translated_table_offset
94: trans_table_data = io.read((4 * 2) * header.nstrings).unpack(@little_endian ? 'V*' : 'N*')
95:
96: original_strings = Array.new(header.nstrings)
97: for i in 0...header.nstrings
98: io.pos = orig_table_data[i * 2 + 1]
99: original_strings[i] = io.read(orig_table_data[i * 2 + 0])
100: end
101:
102: clear
103: for i in 0...header.nstrings
104: io.pos = trans_table_data[i * 2 + 1]
105: str = io.read(trans_table_data[i * 2 + 0])
106:
107: if (! original_strings[i]) || original_strings[i] == ""
108: if str
109: @charset = nil
110: @nplurals = nil
111: @plural = nil
112: str.each_line{|line|
113: if /^Content-Type:/i =~ line and /charset=((?:\w|-)+)/i =~ line
114: @charset = $1
115: elsif /^Plural-Forms:\s*nplurals\s*\=\s*(\d*);\s*plural\s*\=\s*([^;]*)\n?/ =~ line
116: @nplurals = $1
117: @plural = $2
118: end
119: break if @charset and @nplurals
120: }
121: @nplurals = "1" unless @nplurals
122: @plural = "0" unless @plural
123: end
124: else
125: if @output_charset
126: begin
127: str = Iconv.conv(@output_charset, @charset, str) if @charset
128: rescue Iconv::Failure
129: if $DEBUG
130: $stderr.print "@charset = ", @charset, "\n"
131: $stderr.print "@output_charset = ", @output_charset, "\n"
132: $stderr.print "msgid = ", original_strings[i], "\n"
133: $stderr.print "msgstr = ", str, "\n"
134: end
135: end
136: end
137: end
138: self[original_strings[i]] = str
139: end
140: self
141: end
From gettext-0.12.1/gettext-tools/lib/hash.c
# File lib/gettext/mo.rb, line 157
157: def next_prime(seed)
158: seed |= 1
159: while (! prime?(seed))
160: seed += 2
161: end
162: seed
163: end
From gettext-0.12.1/gettext-tools/lib/hash.c
# File lib/gettext/mo.rb, line 144
144: def prime?(candidate)
145: divn = 3
146: sq = divn * divn
147:
148: while (sq < candidate && candidate % divn != 0)
149: divn += 1
150: sq += 4 * divn
151: divn += 1
152: end
153: candidate % divn != 0
154: end
# File lib/gettext/mo.rb, line 258
258: def save_to_file(filename)
259: File.open(filename, 'wb'){|f| save_to_stream(f)}
260: end
# File lib/gettext/mo.rb, line 186
186: def save_to_stream(io)
187: #Save data as little endian format.
188: header_size = 4 * 7
189: table_size = 4 * 2 * size
190:
191: hash_table_size = next_prime((size * 4) / 3)
192: hash_table_size = 3 if hash_table_size <= 2
193: header = Header.new(
194: MAGIC_LITTLE_ENDIAN, # magic
195: 0, # revision
196: size, # nstrings
197: header_size, # orig_table_offset
198: header_size + table_size, # translated_table_offset
199: hash_table_size, # hash_table_size
200: header_size + table_size * 2 # hash_table_offset
201: )
202: io.write(header.to_a.pack('a4V*'))
203:
204: ary = to_a
205: ary.sort!{|a, b| a[0] <=> b[0]} # sort by original string
206:
207: pos = header.hash_table_size * 4 + header.hash_table_offset
208:
209: orig_table_data = Array.new()
210: ary.each{|item, _|
211: orig_table_data.push(item.size)
212: orig_table_data.push(pos)
213: pos += item.size + 1 # +1 is <NUL>
214: }
215: io.write(orig_table_data.pack('V*'))
216:
217: trans_table_data = Array.new()
218: ary.each{|_, item|
219: trans_table_data.push(item.size)
220: trans_table_data.push(pos)
221: pos += item.size + 1 # +1 is <NUL>
222: }
223: io.write(trans_table_data.pack('V*'))
224:
225: hash_tab = Array.new(hash_table_size)
226: j = 0
227: ary[0...size].each {|key, _|
228: hash_val = hash_string(key)
229: idx = hash_val % hash_table_size
230: if hash_tab[idx] != nil
231: incr = 1 + (hash_val % (hash_table_size - 2))
232: begin
233: if (idx >= hash_table_size - incr)
234: idx -= hash_table_size - incr
235: else
236: idx += incr
237: end
238: end until (hash_tab[idx] == nil)
239: end
240: hash_tab[idx] = j + 1
241: j += 1
242: }
243: hash_tab.collect!{|i| i ? i : 0}
244:
245: io.write(hash_tab.pack('V*'))
246:
247: ary.each{|item, _| io.write(item); io.write("\0") }
248: ary.each{|_, item| io.write(item); io.write("\0") }
249:
250: self
251: end