# Copyright (C) 2002-2004 Kouichirou Eto, All rights reserved.
-# "rbchise.so" ext compatible library by eto 2003-0317
-require "bdb"
-require "pathname"
-require "fileutils"
-require "chise/util"
-
-module CHISE
- class DataSource
- NONE = 0
- Berkeley_DB = 1
-
- def initialize(type=Berkeley_DB, loc=nil, subtype=0, modemask=0755)
- @type = type
- loc = Config.instance.db_dir if loc.nil?
- @location = loc.path
- @subtype = subtype
- @modemask = modemask
- @fdb = {}
- @cdb = {}
- end
- attr_reader :type, :location, :subtype, :modemask
-
- def get_feature(f)
- @fdb[f] = FeatureTable.new(self, f) if @fdb[f].nil?
- @fdb[f]
- end
-
- def get_ccs(ccs)
- @cdb[ccs] = CCSTable.new(self, ccs) if @cdb[ccs].nil?
- @cdb[ccs]
- end
-
- def each_feature
- dir = @location + "character/feature"
- dir.each_entry {|f|
- next if f.to_s == "." || f.to_s == ".."
- f = f.unescape_win_filename
- f = f.unescape
- yield(f.to_s)
- }
- end
-
- def load_feature(name, cid)
- ft = get_feature(name)
- return nil if ft.nil?
- ft.get_value(cid)
- end
-
- def decode_char(ccs, code_point)
- ct = get_ccs(ccs)
- return nil if ct.nil?
- ct.decode(code_point)
- end
- end
-
- module ChiseValue; end
-
- class AttributeTable
- def initialize(dir, cat, keytype, name, amask, mmask)
- dbdir = dir + cat + keytype
- #FileUtils.mkdir_p(dbdir.to_s) unless dbdir.directory?
- name = name.path
- name = name.escape
- name = name.escape_win_filename
- path = dbdir + name
-# qp path, amask, mmask
- raise unless path.exist?
-# @db = BDB::Hash.open(path.to_s, amask, mmask)
- @db = BDB::Hash.open(path.to_s)
- at_exit {
- close
- }
- end
-
- def close
- return if @db.nil?
- begin
- @db.sync
- @db.close
- rescue
- end
- end
-
- def get(k)
- @db.get(k)
- end
-
- def put(k, v)
- @db.put(k, v)
- end
-
- def each
- @db.each {|k, v| yield(k, v) }
- end
- end
-
- module TableAccessModule
- def initialize(ds, name)
- @ds, @name = ds, name
- @db = nil
- @access = 0
- end
-
- def sync
- @db.close if @db
- @db = nil
- @access = 0
- end
- alias close sync
-
- def setup_db_exec(writable, cat, key)
- if writable
- sync if @access & BDB::CREATE == 0
- @access = BDB::CREATE
- else
- @access = BDB::RDONLY
- end
-
- return if @db
-
- begin
- @db = AttributeTable.new(@ds.location, cat, key,
- @name, @access, @ds.modemask)
- rescue
- @db = nil
- end
- #raise if @db.nil?
- end
- end
-
- class FeatureTable
- include ChiseValue
- include TableAccessModule
-
- def set_value(cid, value)
- setup_db(true)
- return nil if @db.nil?
- key = format_char_id(cid)
- @db.put(key, value)
- end
-
- def get_value(cid)
- setup_db
- return nil if @db.nil?
- key = format_char_id(cid)
- @db.get(key)
- end
-
- def each
- setup_db
- return nil if @db.nil?
- @db.each {|k, v|
- cid = parse_c_string(k)
- yield(cid, v)
- }
- end
-
- private
- def setup_db(writable=nil)
- setup_db_exec(writable, "character", "feature")
- end
- end
-
- class CCSTable
- include ChiseValue
- include TableAccessModule
-
- def decode(code_point)
- setup_db
- k = code_point.to_s
- v = @db.get(k)
- return nil if v.nil?
- cid = parse_c_string(v)
- cid
- end
-
- def set_decoded_char(code_point, cid)
- setup_db(true)
- k = code_point.to_s
- v = format_char_id(cid)
- @db.put(k, v)
- end
-
- private
- def setup_db(writable=nil)
- setup_db_exec(writable, "character", "by_feature")
- end
- end
-
- module ChiseValue
- def parse_c_string(str)
- i = 0
- c = str[i]
- i += 1
- len = str.length
-
- raise unless 2 <= len && c == ?\?
-
- c = str[i]
- i += 1
-
- if (c == ?\\)
- raise if (len < 3)
- c = str[i]
- i += 1
- if (c == ?^)
- raise if (len < 4)
- c = str[i]
- i += 1
- if c == ?\?
- return 0x7F
- else
- return c & (0x80 | 0x1F)
- end
- end
- # raise # ?
- end
-
- if ( c < 0xC0 )
- cid = c
- counter = 0
- elsif ( c < 0xE0 )
- cid = c & 0x1f
- counter = 1
- elsif ( c < 0xF0 )
- cid = c & 0x0f
- counter = 2
- elsif ( c < 0xF8 )
- cid = c & 0x07
- counter = 3
- elsif ( c < 0xFC )
- cid = c & 0x03
- counter = 4
- else
- cid = c & 0x01
- counter = 5
- end
-
- if (counter + 2 <= len)
- (0...counter).each {|j|
- cid = (cid << 6) | (str[j + i] & 0x3F)
- }
- return cid
- end
-
- raise
- end
-
- def format_char_id(cid)
- case cid
- when ?\t then return "?\t"
- when ?\n then return "?\n"
- when ?\r then return "?\r"
- when 0x1C then return "?\^\\"
- end
-
- if cid <= 0x1F
- return "?\\^"+(?@+cid).chr
- elsif (cid == ?\s) || (cid == ?\") ||
- (cid == ?\#) || (cid == ?\') ||
- (cid == ?\() || (cid == ?\)) ||
- (cid == ?\,) || (cid == ?\.) ||
- (cid == ?\;) || (cid == ?\?) ||
- (cid == ?\[) || (cid == ?\\) ||
- (cid == ?\]) || (cid == ?\`)
- return "?\\"+cid.chr
- elsif (cid <= 0x7E)
- return("?"+cid.chr)
- elsif (cid == 0x7F)
- return "?\\^?"+0.chr
- elsif (cid <= 0x9F)
- dest = "?\\^"
- dest += (((cid + ?@) >> 6) | 0xC0).chr
- dest += (((cid + ?@) & 0x3F) | 0x80).chr
- return dest
- elsif (cid <= 0x7FF)
- dest = "? "
- dest[1] = (cid >> 6) | 0xC0
- dest[2] = (cid & 0x3F) | 0x80
- return dest
- elsif (cid <= 0xFFFF)
- dest = "? "
- dest[1] = (cid >> 12) | 0xE0
- dest[2] = ((cid >> 6) & 0x3F) | 0x80
- dest[3] = (cid & 0x3F) | 0x80
- return dest
- elsif (cid <= 0x1FFFFF)
- dest = "? "
- dest[1] = (cid >> 18) | 0xF0
- dest[2] = ((cid >> 12) & 0x3F) | 0x80
- dest[3] = ((cid >> 6) & 0x3F) | 0x80
- dest[4] = (cid & 0x3F) | 0x80
- return dest
- elsif (cid <= 0x3FFFFFF)
- dest = "? "
- dest[1] = (cid >> 24) | 0xF8
- dest[2] = ((cid >> 18) & 0x3F) | 0x80
- dest[3] = ((cid >> 12) & 0x3F) | 0x80
- dest[4] = ((cid >> 6) & 0x3F) | 0x80
- dest[5] = (cid & 0x3F) | 0x80
- return dest
- else
- dest = "? "
- dest[1] = (cid >> 30) | 0xFC
- dest[2] = ((cid >> 24) & 0x3F) | 0x80
- dest[3] = ((cid >> 18) & 0x3F) | 0x80
- dest[4] = ((cid >> 12) & 0x3F) | 0x80
- dest[5] = ((cid >> 6) & 0x3F) | 0x80
- dest[6] = (cid & 0x3F) | 0x80
- return dest
- end
- raise
- end
- end
-end
+require "chise/libchise"