mapper.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
-------------------------> GNU Sather - sourcefile <-------------------------
-- Copyright (C) 2000 by K Hopper, University of Waikato, New Zealand --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute and/or modify it under the terms of the GNU Library General --
-- Public License (LGPL) as published by the Free Software Foundation; --
-- either version 2 of the license, or (at your option) any later version. --
-- This library is distributed in the hope that it will be useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/LGPL for more details. --
-- The license text is also available from: Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --
--------------> Please email comments to <bug-sather@gnu.org> <--------------
class CODE_MAPPER < $CODE_MAPPER
class CODE_MAPPER < $CODE_MAPPER is
-- This class defines a code mapper which uses data obtained from a file
-- in order to carry out code conversions.
-- The structure of a map file is as follows :-
--
-- (1) A header starting with a magic number 0xb827.
-- (see the MAP_HEADER class for further details).
--
-- (2) A number of code 'sections' each of which starts with a single
-- octet containing the key bit count (eg 8, 16, 32). If, however,
-- the 'size' is zero then the next following octet determines the
-- structure which follows :-
--
-- a. If zero then the end of the map file has been reached.
--
-- b. Otherwise it is followed by the following four single
-- octets -
--
-- source count
-- storage method for the section
-- key value
-- initial target value
--
-- If the size was non-zero (ie a valid size) then the section header
-- continues with the following three octets -
--
-- codes per key
-- target size in bits
-- codes per target value
-- The kinds of storage method for each section has its own structure
-- as given in the following sub-paragraphs :-
--
-- (1) Key Value pairs - as many simple pairs in the appropriate code
-- sizes as indicated by the count.
--
-- (2) All keys followed by all target values - up to the specified
-- count.
--
-- (3) Partial key value 'list' - a number of sub-sections determined
-- by the first 'count' octet. However, if this is null and the next
-- following octet is null then the end of the current section has been
-- reached. If the 'count' octet is non-null then section data follows
-- in one of two forms for both of which the keys are 'compressed' into
-- contiguous key ranges. The target values appear in one of two
-- forms :-
--
-- a. Target values 'compressed' - this form begins with a count
-- octet for a target value range. If this is null and is followed
-- by a further null octet then the section has finished. If the
-- count is non-null then data follows. First there is a target
-- value count which must be less than or equal to the key count.
-- After this there is a target start of range value (in the number
-- of octets for the map target).
--
-- b. Target value NOT 'compressed' - this consists of a sequence
-- of key count target code values (each of the appropriate number
-- of octets).
-- Version 1.0 Oct 98. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 30 Oct 98 kh Original after a Perl script
include BINARY ;
private const Max_Count : CARD := OCTET::Octet_Max ; -- largest partial chunk!
private const Default_Section : MAP_PARTS := MAP_PARTS::Infinite ;
private const Default_Method : MAP_MODES := MAP_MODES::Alternate_Key_Val ;
private const Default_Key_Compression : BOOL := true ;
private const Default_Value_Compression : BOOL := true ;
private const Default_Key_Comp_Val : CARD := 11 ; -- from file format def!
private const Default_Value_Comp_Val : CARD := 14 ;
private const Default_Value_No_Comp_Val : CARD := Default_Value_Comp_Val - 1 ;
private const Codes_per_Entry : CARD := 1 ; -- always seem to be one here!???
private const Unicodes_per_Entry : CARD := 1 ;
private attr header : MAP_HEADER ;
readonly attr section : MAP_PARTS ; -- the initial values!
readonly attr method : MAP_MODES ;
readonly attr key_compression : BOOL ;
readonly attr value_compression : BOOL ;
readonly attr kind : CODE_KINDS ;
private attr to_map : FMAP{CARD,CARD} ; -- to Unicode code value
private attr from_map : FMAP{CARD,CARD} ; -- from Unicode code value
private attr loc_lib : LIBCHARS ; -- local code dummy
private attr uni_lib : LIBCHARS ; -- either a UCS2 or Unicode dummy
private attr codes_per_key : CARD ;
private attr codes_per_value : CARD ;
private attr sizes_done : BOOL ;
-- The above four values are fixed for any one map - so are treated as
-- map attributes.
insert(
non_code : CARD,
uni_code : CARD
)
pre ~void(self)
and ~to_map.test(non_code)
and ~from_map.test(uni_code)
post (to_map.size = (initial(to_map.size) + 1))
and(from_map.size = (initial(from_map.size) + 1))
and from_map.test(uni_code)
and to_map.test(non_code)
is
-- This private routine is provided to produce the to and from map
-- entries from the two codes.
to_map := to_map.insert(non_code,uni_code) ;
from_map := from_map.insert(uni_code,non_code)
end ;
private is_end_marker(
cursor : BIN_CURSOR
) : BOOL
pre ~void(cursor)
and ~cursor.is_done
post true
is
-- This private routine tests if the next two octets on the file are
-- null, which signifies the end of the current section when true is
-- returned, otherwise false and the count parameter is valid.
loc_val : OCTET := cursor.get_item ;
if loc_val = OCTET::null
and cursor.item = OCTET::null then -- yes!
cursor.advance ; -- over the mark!
cursor.advance ; -- and the 'length' flag
return true
else
cursor.retract ;
return false
end
end ;
private handle_param(
cursor : BIN_CURSOR
)
pre ~void(cursor)
post true
is
-- This routine obtains the next octet from the indicated string and,
-- dependent on value, sets one of the map arguments.
if cursor.is_done then -- Oops! run off the end!
SYS_ERROR::create.error(self,
SYS_EXCEPT::Bad_Map,header.code_name.str)
end ;
loc_code : CARD := cursor.get_item.card ;
if loc_code <= MAP_PARTS::cardinality - 1 then
section := MAP_PARTS::create(loc_code + 1)
elsif loc_code <= MAP_MODES::Partial_Key_Val_Map.card then
method := MAP_MODES::create(loc_code)
elsif loc_code <= Default_Key_Comp_Val then
key_compression := (loc_code = Default_Key_Comp_Val)
elsif loc_code <= Default_Value_Comp_Val then
value_compression := (loc_code = Default_Value_Comp_Val)
else -- a real problem in the file
SYS_ERROR::create.error(self,SYS_EXCEPT::Bad_Map,loc_code.str)
end ;
cursor.advance ; -- past the third (null) octet!
return
end ;
private set_compressed(
cursor : BIN_CURSOR,
inout key_count : CARD,
inout key_start : CARD
) : BOOL
pre ~void(cursor)
and ~cursor.is_done
and (key_count > 0)
post ~result
or (from_map.size > initial(from_map.size))
is
-- This private routine is used to set a section of the map for which
-- values are 'compressed'. It returns true if successful or false if there
-- has been a file format error.
value_count : CARD := cursor.get_item.card ;
value_start : CARD := CARD::create(cursor.get_upto(uni_lib.my_size)) ;
if value_start = CHAR_CODE::invalid.card then
return false
end ;
loop -- which sets up the maps
value_count.times! ;
insert(key_start,value_start) ;
key_start := key_start + 1 ;
value_start := value_start + 1
end ;
key_count := key_count - value_count ;
return true
end ;
private set_uncompressed(
cursor : BIN_CURSOR,
inout key_count : CARD,
inout key_start : CARD
) : BOOL
pre ~void(cursor)
and ~cursor.is_done
post (from_map.size = initial(from_map.size) + key_count)
is
-- This private routine sets a section of the map for which no value
-- compression is used.
loop -- over values to set maps
key_count.times! ;
if cursor.is_done then
return false
end ;
insert(key_start,CARD::create(
cursor.get_upto(uni_lib.my_size))) ;
key_start := key_start + 1
end ;
return true
end ;
private get_partial_section(
cursor : BIN_CURSOR
) : BOOL
pre ~void(cursor)
and ~cursor.is_done
post result
or (cursor.index = initial(cursor.index))
is
-- This private routine extracts a partial map from the mapping file,
-- returning true if no error occurred.
loc_section : MAP_PARTS ;
loc_method : MAP_MODES ;
loc_key_comp : BOOL ;
loc_value_comp : BOOL ;
start_index : CARD := cursor.index ;
loop -- over the sub-sections!
if cursor.is_done then -- run off the end!
cursor.set_index(start_index) ;
return false
end ;
loc_section := section ; -- save state!
loc_method := method ;
loc_key_comp := key_compression ;
loc_value_comp := value_compression ;
if is_end_marker(cursor) then
break! -- state has not been altered!
else -- it's a partial count!
key_count : CARD := cursor.get_item.card ;
key_start : CARD := CARD::create(
cursor.get_upto(loc_lib.my_size)) ;
if key_start = CHAR_CODE::invalid.card then
cursor.set_index(start_index) ;
return false
end ;
loop -- over the key values
while!(key_count > 0) ;
if loc_value_comp then -- using value 'compression'
if ~set_compressed(cursor, inout key_count,
inout key_start) then
cursor.set_index(start_index) ;
return false
end
else -- not using value compression
if ~set_uncompressed(cursor,inout key_count,
inout key_start) then
cursor.set_index(start_index) ;
return false
end
end
end
end ;
section := loc_section ; -- restore original state
method := loc_method ;
key_compression := loc_key_comp ;
value_compression := loc_value_comp
end ;
return true
end ;
private get_pairs_section(
cursor : BIN_CURSOR
) : BOOL
pre ~void(cursor)
and ~cursor.is_done
post (from_map.size > initial(from_map.size))
is
-- This private routine sets the map from adjacent pairs of key then
-- value in the file.
first : BOOL := true ;
loop
if cursor.is_done then -- this should never happen!
return false
end ;
if ~first
and is_end_marker(cursor) then
cursor.advance ; -- past the final flag
return true
end ;
key_val : CARD := CARD::create(cursor.get_upto(loc_lib.my_size)) ;
value_val : CARD := CARD::create(cursor.get_upto(uni_lib.my_size)) ;
if first then
first := false
end ;
insert(key_val,value_val)
end
end ;
private get_twin_lists_section(
cursor : BIN_CURSOR
) : BOOL
pre ~void(cursor)
and ~cursor.is_done
and (codes_per_key = codes_per_value)
post (from_map.size > initial(from_map.size))
is
-- This routine handles a mapfile section which is in the form of two
-- lists in sequence, first the key list, then the value list.
return false -- NOT YET IMPLEMENTED!
end ;
private section_header(
cursor : BIN_CURSOR
) : BOOL
pre ~void(cursor)
and ~cursor.is_done
post true
is
-- This routine looks for a section header at the currently indicated
-- buffer position. The expected form is one or more of the following -
--
-- A leading null octet followed by a section kind octet & null octet
-- A leading null octet followed by a method octet and trailing null
loop
if (cursor.item = OCTET::null) then -- it is a header component
cursor.advance ;
if cursor.item = OCTET::null then
cursor.advance ; -- past the third null!!
return false
else
handle_param(cursor)
end
else
return true
end
end
end ;
private get_sizes(
cursor : BIN_CURSOR
) is
-- This private routine retrieves the size key and code size data from
-- the map file - after the first section header.
key_octets : CARD := (cursor.get_item.card + (OCTET::Octet_Bits - 1)) /
OCTET::Octet_Bits ;
if key_octets /= loc_lib.my_size then
SYS_ERROR::create.error(self,
SYS_EXCEPT::Bad_Map,header.code_name.str)
end ;
codes_per_key := cursor.get_item.card ;
value_octets : CARD := (cursor.get_item.card + (OCTET::Octet_Bits - 1)) /
OCTET::Octet_Bits ;
if value_octets = CODE_KINDS::Unicode.size then
uni_lib := LIBCHARS::default.dummy_lib(CODE_KINDS::Unicode)
elsif value_octets = CODE_KINDS::UCS2.size then
uni_lib := LIBCHARS::default.dummy_lib(CODE_KINDS::UCS2)
end ;
codes_per_value := cursor.get_item.card ;
end ;
private retrieve_section(
cursor : BIN_CURSOR,
out is_end : BOOL
) : BOOL
pre ~void(cursor)
and ~cursor.is_done
post ~result
or (from_map.size > initial(from_map.size))
is
-- This private routine handles each section of the map file, inserting
-- appropriate elements of the maps.
start_index : CARD := cursor.index ;
if ~section_header(cursor) then
is_end := (cursor.index /= start_index) ;
return false
end ;
if codes_per_key = 0 then -- they must be here if not
get_sizes(cursor)
end ;
case method
when MAP_MODES::Alternate_Key_Val then
if ~get_pairs_section(cursor) then
return false
end
when MAP_MODES::All_Keys_All_Vals then -- not yet implemented
if ~get_twin_lists_section(cursor) then
return false
end
when MAP_MODES::Partial_Key_Val_Map then
if (section = MAP_PARTS::Infinite)
or (codes_per_key /= 1)
or (codes_per_value /= 1) then -- not yet implemented!
return false
end ;
if ~get_partial_section(cursor) then
return false
end
else -- there is a file format error!
return false
end ;
return true
end ;
build(
cursor : BIN_CURSOR
) : SAME
pre ~void(self)
and ~void(cursor)
post true
is
-- This routine builds a new mapper from the indicated binary string.
start_index : CARD := cursor.index ;
is_end : BOOL := false ;
header := MAP_HEADER::build(cursor) ;
if void(header) then -- failed miserably!
return void
else -- OK to initialise
section := Default_Section ;
method := Default_Method ;
key_compression := Default_Key_Compression ;
value_compression := Default_Value_Compression
end ;
loop -- over the rest of the file!
if cursor.is_done then -- shouldn't really get here!!!!!
break!
end ;
loc_section : MAP_PARTS := section ; -- save state for this pass
loc_method : MAP_MODES := method ;
loc_key_comp : BOOL := key_compression ;
loc_value_comp : BOOL := value_compression ;
if ~retrieve_section(cursor,out is_end) then
if is_end then
break!
else
cursor.set_index(start_index) ;
return void
end
end ;
section := loc_section ; -- restore state!
method := loc_method ;
key_compression := loc_key_comp ;
value_compression := loc_value_comp
end ;
return self
end ;
create(
kind : CODE_KINDS
) : SAME
pre ~void(kind)
post ~void(result)
is
-- This routine returns an empty mapper for the given code keys
-- using the UCS2 code as default output.
me : SAME := new ;
me.key_compression := Default_Key_Compression ;
me.value_compression := Default_Value_Compression ;
me.kind := kind ;
me.loc_lib := LIBCHARS::default.dummy_lib(kind) ;
me.uni_lib := me.loc_lib.dummy_lib(CODE_KINDS::UCS2) ;
me.to_map := FMAP{CARD,CARD}::create ;
me.from_map := FMAP{CARD,CARD}::create ;
return me
end ;
create(
kind : CODE_KINDS,
unicode : BOOL
) : SAME
pre ~void(kind)
post ~void(result)
is
-- This routine returns an empty mapper for the given code keys using
-- Unicode or UCS2 code as output.
me : SAME := new ;
me.key_compression := Default_Key_Compression ;
me.value_compression := Default_Value_Compression ;
me.kind := kind ;
me.loc_lib := LIBCHARS::default.dummy_lib(kind) ;
if unicode then
me.uni_lib := me.loc_lib.dummy_lib(CODE_KINDS::Unicode)
else
me.uni_lib := me.loc_lib.dummy_lib(CODE_KINDS::UCS2)
end ;
me.to_map := FMAP{CARD,CARD}::create ;
me.from_map := FMAP{CARD,CARD}::create ;
return me
end ;
create(
kind : CODE_KINDS,
loc_path : FILE_PATH
) : SAME
pre ~void(loc_path)
post ~void(result) -- or exception has been raised!
is
-- This routine returns a mapper created from the mapping file whose
-- path name is given.
fyle : BIN_FILE := BIN_FILE::open_for_read(loc_path.str) ;
raiser : SYS_ERROR := SYS_ERROR::create ;
if void(fyle) then -- fatal error!
raiser.error(create(kind),SYS_EXCEPT::Bad_Name,loc_path.str)
elsif fyle.error then
raiser.file_error(create(kind),fyle)
end ;
loc_cursor : BIN_CURSOR := fyle.buffer.binstr.cursor ;
fyle.close ;
me : SAME := create(kind) ;
me := me.build(loc_cursor) ;
if void(me) then
raiser.error(create(kind),SYS_EXCEPT::Bad_Map,loc_path.str) ;
return void -- to keep the compiler happy
else
return me
end
end ;
set_header(
val : MAP_HEADER
)
pre ~void(self)
and ~void(val)
and void(header)
post ~void(header)
is
-- This private routine sets the header of the map - providing that it
-- is not yet valid!
header := val
end ;
private adjacent(
first : CARD,
second : CARD
) : BOOL is
-- This private routine returns true if and only if the second argument
-- follows the first and differs only in the final code by one - using
-- a numeric interpretation of the codes.
return (first + 1) = second
end ;
private chunk_size(
vals : ARRAY{CARD},
start_index : CARD
) : CARD
pre ~void(vals)
and (start_index < vals.size)
post (result > 0)
is
-- Given the sorted key array and a start index this routine seeks for
-- an element which is
--
-- (1) not adjacent to the previous element in sequence or
--
-- (2) there is an element of a different size or
--
-- (3) there are 255 adjacent elements or
--
-- (4) the end of the array has been reached
--
-- returning the number of elements scanned.
loc_index : CARD := start_index ;
count : CARD := 0 ;
loop
if loc_index = vals.size then -- singleton last element!
return count + 1
elsif count = Max_Count then -- maximum partial chunk!
return count
elsif ((loc_index + 1) = vals.size) then -- no more to compare!
return count + 1
elsif adjacent(vals[loc_index],vals[loc_index + 1]) then
loc_index := loc_index + 1 ;
count := count + 1
else
return count + 1
end
end
end ;
private card_bin(
val : CARD,
size : CARD
) : BINSTR
pre (size >= ((NUM_BITS::create(val).highest / OCTET::Octet_Bits) + 1))
post result.size = size
is
-- This private routine produces a binary representation of the given
-- value using the given number of octets - providing, of course, that
-- the pre-condition is met.
return val.binstr.tail(size)
end ;
private param_to_bin(
param_code : CARD
) : BINSTR
pre true
post result.size = 3
is
-- This routine prepares a binary representation of the given code,
-- surrounding it with null octets, before returning it.
return BINSTR::create + OCTET::null + OCTET::create(param_code) +
OCTET::null
end ;
private partial_representation(
sect_fixed_hdr : BINSTR,
vals : ARRAY{CARD},
val_start : CARD,
tally : CARD
) : BINSTR
pre ~void(vals)
and (tally > 0)
post true
is
-- This private routine builds the binary representation of a code map
-- section containing a sequence of values of length tally.
res : BINSTR := BINSTR::create +
param_to_bin(MAP_MODES::Partial_Key_Val_Map.card) ;
if value_compression then
res := res + param_to_bin(Default_Value_No_Comp_Val)
end ;
if ~void(sect_fixed_hdr) then
res := res + sect_fixed_hdr
end ;
res := res + OCTET::create(tally) ;
loop
loc_code : CARD := vals.elt!(val_start,tally) ;
res := res + card_bin(loc_code,uni_lib.my_size)
end ;
return res
end ;
private singleton(
sect_fixed_hdr : BINSTR,
keys : ARRAY{CARD},
vals : ARRAY{CARD},
key_index : CARD,
val_index : CARD
) : BINSTR
pre ~void(keys)
and ~void(vals)
post true
is
-- This private routine builds the binary representation of a singleton
-- code map section
res : BINSTR := BINSTR::create + param_to_bin(MAP_MODES::Alternate_Key_Val.card) ;
if ~void(sect_fixed_hdr) then
res := res + sect_fixed_hdr
end ;
res := res + OCTET::create(key_index) +
OCTET::create(val_index) ;
res := res + card_bin(keys[key_index],loc_lib.my_size) +
card_bin(vals[val_index],uni_lib.my_size) ;
return res
end ;
private try_compression(
sect_fixed_hdr : BINSTR,
vals : ARRAY{CARD},
val_count : CARD,
val_index : CARD
) : BINSTR
pre ~void(vals)
and (val_count > 0)
post true
is
-- This private routine builds the binary representation of one section
-- of the map.
res : BINSTR := BINSTR::create +
param_to_bin(MAP_MODES::Partial_Key_Val_Map.card) ;
if ~value_compression then
res := res + param_to_bin(Default_Value_Comp_Val)
end ;
res := res + sect_fixed_hdr + OCTET::create(val_count) +
card_bin(vals[val_index],uni_lib.my_size) ;
return res
end ;
private build_section(
sect_fixed_hdr : BINSTR,
keys : ARRAY{CARD},
vals : ARRAY{CARD},
key_start : CARD,
key_count : CARD
) : BINSTR
pre ~void(keys)
and ~void(vals)
and (key_count > 0)
post true
is
-- This private routine builds the binary representation of one section
-- of the map.
val_start : CARD := 0 ;
key_bin : BINSTR := keys[key_start].binstr ; -- the actual code value!
res : BINSTR := BINSTR::create + OCTET::create(key_count) +
key_bin.tail(loc_lib.my_size) ;
val_index : CARD := val_start ;
key_index : CARD := key_start ;
loop -- over the keys
val_count : CARD := chunk_size(vals,val_start) ;
if val_count > 1 then -- can 'compress'
if ~void(sect_fixed_hdr) then
res := BINSTR::create + sect_fixed_hdr + res
end ;
res := try_compression(res,vals,val_count,val_index) ;
val_start := val_index + val_count ;
val_index := val_start
else -- just tally count of singles
loc_start : CARD := val_start ;
loop -- the tally loop
while!((val_count = 1)
and (loc_start < vals.size)) ;
val_count := chunk_size(vals,loc_start) ;
loc_start := loc_start + 1
end ;
tally : CARD := loc_start - val_start ;
if tally = 1 then -- just like a single key!
res := res + singleton(sect_fixed_hdr,keys,vals,
key_index,val_index)
else
res := res + partial_representation(sect_fixed_hdr,
vals,val_start,tally)
end ;
key_start := key_start + tally ;
key_index := key_start ;
val_start := val_start + tally ;
val_index := val_start
end ;
if val_start = key_count then
return res
end
end
end ;
private section_to_bin(
keys : ARRAY{CARD},
key_start : CARD,
key_count : CARD
) : BINSTR
pre ~void(keys)
and (key_count > 0)
post true
is
-- This routine constructs a single binary string consisting of the
-- mapping file format of count elements from the from_map. There are three
-- cases -
--
-- (1) There is a single element.
--
-- (2) There are chunks of value which are adjacent.
--
-- (3) There are no adjacent values.
res : BINSTR := BINSTR::create ;
fixed_hdr : BINSTR ;
val_index : CARD := 0 ;
vals : ARRAY{CARD} := ARRAY{CARD}::create(key_count) ;
loop -- to fill in value codes
vals.set!(to_map.get(keys.elt!(key_start)))
end ;
if sizes_done then
fixed_hdr := void
else
sizes_done := true ;
fixed_hdr := BINSTR::create +
param_to_bin(MAP_PARTS::Byte_Size.card - 1) ;
-- File format section header - note the 'special' (-1)
-- for the map part!
fixed_hdr := fixed_hdr +
OCTET::create(loc_lib.my_size * OCTET::Octet_Bits) +
OCTET::create(Codes_per_Entry) +
OCTET::create(uni_lib.my_size * OCTET::Octet_Bits) +
OCTET::create(Unicodes_per_Entry)
end ;
if key_count = 1 then
res := res + param_to_bin(MAP_MODES::Alternate_Key_Val.card) ;
if ~void(fixed_hdr) then
res := res + fixed_hdr
end ;
res := res + card_bin(keys[key_start],loc_lib.my_size) +
card_bin(vals[val_index],uni_lib.my_size)
else
res := build_section(fixed_hdr,keys,vals,key_start,key_count)
end ;
res := res + param_to_bin(0) ; -- the end marker!
return res
end ;
binstr : BINSTR
pre ~void(self)
post ~void(result)
is
-- This routine returns a binary string representation of self suitable
-- for filing. Note that this always produces the binary string in Partial
-- mode and (up to) 255 pair chunks.
sizes_done := false ;
key_array : ARRAY{CARD} := ARRAY{CARD}::create(to_map.size) ;
res : BINSTR := BINSTR::create ;
res := res + header.binstr ;
-- First fill in and then sort the keys into ascending order.
loop
key_array.set!(to_map.keys!)
end ;
key_array.sort ;
-- The following loop divides up into chunks which are then
-- converted to binary strings and concatenated onto the end of res.
loc_start : CARD := 0 ; -- initialise loop
loop
if loc_start = key_array.size then
break!
end ;
-- first the section header
loc_count : CARD := chunk_size(key_array,loc_start) ;
if loc_count > OCTET::Octet_Max then
loc_count := OCTET::Octet_Max
end ;
res := res + section_to_bin(key_array,loc_start,loc_count) ;
loc_start := loc_start + loc_count
end ;
res := res + param_to_bin(0) ; -- the null octet end marker
return res
end ;
to_unicode(
ch_code : CHAR_CODE
) : CHAR_CODE
pre ~void(self)
and (ch_code.lib.culture.kind = loc_lib.culture.kind)
and ~ch_code.char.is_control
post result.lib.has_combining
is
-- This routine is designed to convert the single code given into
-- a Unicode encoding using this mapping table. Note that the has_combining
-- property indicates that no conversion is needed.
res : CHAR_CODE ;
if ch_code.lib.has_combining then
res := ch_code
else
res := CHAR_CODE::create(to_map.get(ch_code.card),uni_lib)
end ;
return res
end ;
from_unicode(
ch_code : CHAR_CODE
) : CHAR_CODE
pre ~void(self)
and ch_code.lib.has_combining
post ~result.char.is_control
and ~result.lib.has_combining
is
-- This routine is designed to convert the single code given into
-- a single character using this mapping table.
if from_map.test(ch_code.card) then
return CHAR_CODE::create(from_map.get(ch_code.card),loc_lib)
else
return void
end
end ;
from_unicode(
ch_code : CHAR_CODE,
lib : LIBCHARS
) : CHAR_CODE
pre ~void(self)
and ~void(lib)
and ~ch_code.lib.has_combining
post void(result)
or ~result.char.is_control
is
-- This routine is designed to convert the single code given into
-- a single character using this mapping table.
if from_map.test(ch_code.card) then
return CHAR_CODE::create(from_map.get(ch_code.card),lib)
else
return void
end
end ;
end ; -- CODE_MAPPER