Hash
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.]
# File lib/gettext/runtime/mofile.rb, line 190
190: def hash_string(str)
191: hval = 0
192: i = 0
193: str.each_byte do |b|
194: break if b == '\0'
195: hval <<= 4
196: hval += b.to_i
197: g = hval & (0xf << (HASHWORDBITS - 4))
198: if (g != 0)
199: hval ^= g >> (HASHWORDBITS - 8)
200: hval ^= g
201: end
202: end
203: hval
204: end
# File lib/gettext/runtime/mofile.rb, line 72
72: def load(arg)
73: if arg.kind_of? String
74: begin
75: st = File.stat(arg)
76: @last_modified = [st.ctime, st.mtime]
77: rescue Exception
78: end
79: load_from_file(arg)
80: else
81: load_from_stream(arg)
82: end
83: @filename = arg
84: self
85: end
# File lib/gettext/runtime/mofile.rb, line 273
273: def load_from_file(filename)
274: @filename = filename
275: begin
276: File.open(filename, 'rb'){|f| load_from_stream(f)}
277: rescue => e
278: e.set_backtrace("File: #{@filename}")
279: raise e
280: end
281: end
# File lib/gettext/runtime/mofile.rb, line 87
87: def load_from_stream(io)
88: magic = io.read(4)
89: case magic
90: when MAGIC_BIG_ENDIAN
91: @little_endian = false
92: when MAGIC_LITTLE_ENDIAN
93: @little_endian = true
94: else
95: raise InvalidFormat.new(sprintf("Unknown signature %s", magic.dump))
96: end
97:
98: endian_type6 = @little_endian ? 'V6' : 'N6'
99: endian_type_astr = @little_endian ? 'V*' : 'N*'
100:
101: header = HeaderRev1.new(magic, *(io.read(4 * 6).unpack(endian_type6)))
102:
103: if header.revision == 1
104: # FIXME: It doesn't support sysdep correctly.
105: header.n_sysdep_segments = io.read(4).unpack(endian_type6)
106: header.sysdep_segments_offset = io.read(4).unpack(endian_type6)
107: header.n_sysdep_strings = io.read(4).unpack(endian_type6)
108: header.orig_sysdep_tab_offset = io.read(4).unpack(endian_type6)
109: header.trans_sysdep_tab_offset = io.read(4).unpack(endian_type6)
110: elsif header.revision > 1
111: raise InvalidFormat.new(sprintf("file format revision %d isn't supported", header.revision))
112: end
113: io.pos = header.orig_table_offset
114: orig_table_data = io.read((4 * 2) * header.nstrings).unpack(endian_type_astr)
115:
116: io.pos = header.translated_table_offset
117: trans_table_data = io.read((4 * 2) * header.nstrings).unpack(endian_type_astr)
118:
119: original_strings = Array.new(header.nstrings)
120: for i in 0...header.nstrings
121: io.pos = orig_table_data[i * 2 + 1]
122: original_strings[i] = io.read(orig_table_data[i * 2 + 0])
123: end
124:
125: clear
126: for i in 0...header.nstrings
127: io.pos = trans_table_data[i * 2 + 1]
128: str = io.read(trans_table_data[i * 2 + 0])
129:
130: if (! original_strings[i]) || original_strings[i] == ""
131: if str
132: @charset = nil
133: @nplurals = nil
134: @plural = nil
135: str.each_line{|line|
136: if /^Content-Type:/ =~ line and /charset=((?:\w|-)+)/ =~ line
137: @charset = $1
138: elsif /^Plural-Forms:\s*nplurals\s*\=\s*(\d*);\s*plural\s*\=\s*([^;]*)\n?/ =~ line
139: @nplurals = $1
140: @plural = $2
141: end
142: break if @charset and @nplurals
143: }
144: @nplurals = "1" unless @nplurals
145: @plural = "0" unless @plural
146: end
147: else
148: if @output_charset
149: begin
150: str = Iconv.conv(@output_charset, @charset, str) if @charset
151: rescue Iconv::Failure
152: if $DEBUG
153: warn "@charset = ", @charset
154: warn"@output_charset = ", @output_charset
155: warn "msgid = ", original_strings[i]
156: warn "msgstr = ", str
157: end
158: end
159: end
160: end
161: self[original_strings[i]] = str.freeze
162: end
163: self
164: end
# File lib/gettext/runtime/mofile.rb, line 172
172: def next_prime(seed)
173: Prime.instance.find{|x| x > seed }
174: end
# File lib/gettext/runtime/mofile.rb, line 176
176: def next_prime(seed)
177: require 'mathn'
178: prime = Prime.new
179: while current = prime.succ
180: return current if current > seed
181: end
182: end
# File lib/gettext/runtime/mofile.rb, line 291
291: def plural_as_proc
292: unless @plural_proc
293: @plural_proc = Proc.new{|n| eval(@plural)}
294: begin
295: @plural_proc.call(1)
296: rescue
297: @plural_proc = Proc.new{|n| 0}
298: end
299: end
300: @plural_proc
301: end
# File lib/gettext/runtime/mofile.rb, line 166
166: def prime?(number)
167: ('1' * number) !~ /^1?$|^(11+?)\11++$/
168: end
# File lib/gettext/runtime/mofile.rb, line 283
283: def save_to_file(filename)
284: File.open(filename, 'wb'){|f| save_to_stream(f)}
285: end
Save data as little endian format.
# File lib/gettext/runtime/mofile.rb, line 207
207: def save_to_stream(io)
208: header_size = 4 * 7
209: table_size = 4 * 2 * size
210:
211: hash_table_size = next_prime((size * 4) / 3)
212: hash_table_size = 3 if hash_table_size <= 2
213: header = Header.new(
214: MAGIC_LITTLE_ENDIAN, # magic
215: 0, # revision
216: size, # nstrings
217: header_size, # orig_table_offset
218: header_size + table_size, # translated_table_offset
219: hash_table_size, # hash_table_size
220: header_size + table_size * 2 # hash_table_offset
221: )
222: io.write(header.to_a.pack('a4V*'))
223:
224: ary = to_a
225: ary.sort!{|a, b| a[0] <=> b[0]} # sort by original string
226:
227: pos = header.hash_table_size * 4 + header.hash_table_offset
228:
229: orig_table_data = Array.new()
230: ary.each{|item, _|
231: orig_table_data.push(item.bytesize)
232: orig_table_data.push(pos)
233: pos += item.bytesize + 1 # +1 is <NUL>
234: }
235: io.write(orig_table_data.pack('V*'))
236:
237: trans_table_data = Array.new()
238: ary.each{|_, item|
239: trans_table_data.push(item.bytesize)
240: trans_table_data.push(pos)
241: pos += item.bytesize + 1 # +1 is <NUL>
242: }
243: io.write(trans_table_data.pack('V*'))
244:
245: hash_tab = Array.new(hash_table_size)
246: j = 0
247: ary[0...size].each {|key, _|
248: hash_val = hash_string(key)
249: idx = hash_val % hash_table_size
250: if hash_tab[idx] != nil
251: incr = 1 + (hash_val % (hash_table_size - 2))
252: begin
253: if (idx >= hash_table_size - incr)
254: idx -= hash_table_size - incr
255: else
256: idx += incr
257: end
258: end until (hash_tab[idx] == nil)
259: end
260: hash_tab[idx] = j + 1
261: j += 1
262: }
263: hash_tab.collect!{|i| i ? i : 0}
264:
265: io.write(hash_tab.pack('V*'))
266:
267: ary.each{|item, _| io.write(item); io.write("\00"") }
268: ary.each{|_, item| io.write(item); io.write("\00"") }
269:
270: self
271: end
# File lib/gettext/runtime/mofile.rb, line 287
287: def set_comment(msgid_or_sym, comment)
288: #Do nothing
289: end
# File lib/gettext/runtime/mofile.rb, line 61
61: def update!
62: if FileTest.exist?(@filename)
63: st = File.stat(@filename)
64: load(@filename) unless (@last_modified == [st.ctime, st.mtime])
65: else
66: warn "#{@filename} was lost." if $DEBUG
67: clear
68: end
69: self
70: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.