Parent

GetText::MOFile

Constants

Header
MAGIC_BIG_ENDIAN
MAGIC_LITTLE_ENDIAN
HASHWORDBITS

Attributes

filename[R]
little_endian[RW]
path[RW]
last_modified[RW]
charset[R]
nplurals[R]
plural[R]

Public Class Methods

new(output_charset = nil) click to toggle source
    # File lib/gettext/runtime/mofile.rb, line 52
52:     def initialize(output_charset = nil)
53:       @filename = nil
54:       @last_modified = nil
55:       @little_endian = true
56:       @output_charset = output_charset
57:       @plural_proc = nil
58:       super()
59:     end
open(arg = nil, output_charset = nil) click to toggle source
    # File lib/gettext/runtime/mofile.rb, line 47
47:     def self.open(arg = nil, output_charset = nil)
48:       result = self.new(output_charset)
49:       result.load(arg)
50:     end

Public Instance Methods

hash_string(str) click to toggle source

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
load(arg) click to toggle source
    # 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
load_from_file(filename) click to toggle source
     # 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
load_from_stream(io) click to toggle source
     # 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
next_prime(seed) click to toggle source
     # File lib/gettext/runtime/mofile.rb, line 172
172:       def next_prime(seed)
173:         Prime.instance.find{|x| x > seed }
174:       end
next_prime(seed) click to toggle source
     # 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
plural_as_proc() click to toggle source
     # 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
prime?(number) click to toggle source
     # File lib/gettext/runtime/mofile.rb, line 166
166:     def prime?(number)
167:       ('1' * number) !~ /^1?$|^(11+?)\11++$/
168:     end
save_to_file(filename) click to toggle source
     # 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_to_stream(io) click to toggle source

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
set_comment(msgid_or_sym, comment) click to toggle source
     # File lib/gettext/runtime/mofile.rb, line 287
287:     def set_comment(msgid_or_sym, comment)
288:       #Do nothing
289:     end
update!() click to toggle source
    # 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.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.