# "rbchise.so" ext compatible library by eto 2003-0317
require "bdb"
-require "chise/config"
+require "pathname"
+require "fileutils"
+require "chise/util"
module CHISE
class DataSource
NONE = 0
Berkeley_DB = 1
- def initialize(type = Berkeley_DB, location = nil)
- @type, @location = type, location
- @location = Config.instance.db_dir if @location.nil?
- @fnames = {}
- @cnames_names = {}
- at_exit {
- @fnames.each {|k, db| db.close }
- @cnames.each {|k, db| db.close }
- }
+ 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(feature)
- @fnames[feature] = open_feature(feature) if @fnames[feature].nil?
- @fnames[feature]
+ def get_feature(f)
+ @fdb[f] = FeatureTable.new(self, f) if @fdb[f].nil?
+ @fdb[f]
end
- def decode_char(name, code_point)
- ccs = get_ccs(name)
- ccs.decode(code_point)
+ def get_ccs(ccs)
+ @cdb[ccs] = CCSTable.new(self, ccs) if @cdb[ccs].nil?
+ @cdb[ccs]
end
- def get_ccs(name)
- db = open(name, "system-char-id")
- CCSTable.new(name, db)
+ 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 open_feature_table(feature)
- db = open("system-char-id", feature)
- FeatureTable.new(feature, db)
+ def load_feature(name, cid)
+ ft = get_feature(name)
+ return nil if ft.nil?
+ ft.get_value(cid)
end
- def open(from, to) # real_subtpe, accessmask, modemask
- name = from+"/"+to
- return @dbs[name] if @dbs[name]
- file = @location+"/"+name
- @dbs[name] = BDB::Hash.open(file, nil, 0)
+ def decode_char(ccs, code_point)
+ ct = get_ccs(ccs)
+ return nil if ct.nil?
+ ct.decode(code_point)
end
end
- class AttributeTable # abstract class
+ 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
-
- class CCSTable < AttributeTable
- def initialize(ccs, db)
- @ccs, @db = ccs, db
+
+ module TableAccessModule
+ def initialize(ds, name)
+ @ds, @name = ds, name
+ @db = nil
+ @access = 0
end
- def get_char(code_point)
- @db.get(code_point)
+ def sync
+ @db.close if @db
+ @db = nil
+ @access = 0
end
+ alias close sync
- def put_char(code_point, cid)
- @db.put(code_point, cid)
+ 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 < AttributeTable
- def initialize(feature, db)
- @feature, @db = feature, db
+ 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(char_id)
- @db.get(char_id)
+ 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