Merge commit '929f4ea980f93601cf75558cef370046290feca7' as 'fontcharacter'

This commit is contained in:
Memallox 2018-10-01 18:05:44 +02:00
commit 23e74f7c00
33 changed files with 9338 additions and 0 deletions

5
fontcharacter/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/Makefile.cfg
/sets
.*.swp
__pycache__

13
fontcharacter/AUTHORS.md Normal file
View File

@ -0,0 +1,13 @@
# FONTCHARACTER Reference authors
Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <<thomas@touhey.fr>>
Thanks to the other contributors for making FONTCHARACTER great again:
* Lephenixnoir (Planète Casio);
* Zezombye (Planète Casio).
Thanks to the following sources of information:
* Raw OS Data, extracted using a tool based on a technique found by
Simon Lothar;
* “La Casio Graph100”, by Olivier Coupelon (May, 2002);
* Casetta's CASIO Token List, by Florian Birée (May, 2007);
* Various manuals from CASIO.

View File

@ -0,0 +1,29 @@
# Contributing to FONTCHARACTER Reference
Start by reading all of the available documentation, from the `README.md`
to the formats description, `FORMATS.md` -- in order to know how to contribute
to the project, you have to know how to use it!
## What is left to do
The main thing that is left to do is define the sets, and check which
characters appeared in each of the sets.
The FONTCHARACTER extensions do **not** have priority
(to be honest, the addition of C.Basic was not really planned
straight away...), so please try to concentrate on CASIO's sets first.
To achieve this, you can use my [Opcode Table C Extracting Tool][extract], and
the OSes on [Planète Casio's Bible][oses].
## Any mistake?
You have tried using the reference, but it doesn't match the characters on
your calculator? Yes, it indeed could be a mistake, but it might as well be
a compatibility issue!
You should check in the sets if your model/OS is supported. If you could try
to correct the reference while not breaking everything (even though the
maintainers will probably be careful), that would be great!
Otherwise, you can try to contact the current project maintainer(s).
You can find their personal detail in `AUTHORS.md`.
[extract]: http://www.casiopeia.net/forum/viewtopic.php?p=14742#p14742
[oses]: http://bible.planet-casio.com/casio/os_boot_setup/

24
fontcharacter/FORMAT.md Normal file
View File

@ -0,0 +1,24 @@
# FONTCHARACTER reference formats
To know more about the project itself, and what these formats are,
see `README.md`.
There are a few formats used by the present FONTCHARACTER reference:
- The source format: not meant to be used in other projects.
It is the format in which the humans write the reference.
It is not versioned itself, as it is linked to the same commits and
reference project versions;
- The binary formats: these are meant to be used in other projects.
They are versioned, and the version is present in the file so it can be
identified by the decoder, which then decides if it uses it or if it just
spits "Unknown version".
To use files under the binary formats, the installed generated files will
probably be in a common folder such as `/usr/share/casio/fontcharacter/*.set`
on a Unix-like OS such as any GNU/Linux distribution or MacOS/OS X, or
`C:\Program Files\CASIO\FONTCHARACTER\*.set` under Microsoft Windows
(yet to be confirmed).
The formats themselves are described under the `formats/` folder,
see `formats/SOURCE.md` for the source format, and `formats/BINARYx.md` for
binary formats, where `x` represents the version number.

157
fontcharacter/LICENSE.md Normal file
View File

@ -0,0 +1,157 @@
### GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
<http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates the
terms and conditions of version 3 of the GNU General Public License,
supplemented by the additional permissions listed below.
#### 0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the
GNU General Public License.
"The Library" refers to a covered work governed by this License, other
than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
#### 1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
#### 2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
- a) under this License, provided that you make a good faith effort
to ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
- b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
#### 3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from a
header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
- a) Give prominent notice with each copy of the object code that
the Library is used in it and that the Library and its use are
covered by this License.
- b) Accompany the object code with a copy of the GNU GPL and this
license document.
#### 4. Combined Works.
You may convey a Combined Work under terms of your choice that, taken
together, effectively do not restrict modification of the portions of
the Library contained in the Combined Work and reverse engineering for
debugging such modifications, if you also do each of the following:
- a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
- b) Accompany the Combined Work with a copy of the GNU GPL and this
license document.
- c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
- d) Do one of the following:
- 0) Convey the Minimal Corresponding Source under the terms of
this License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
- 1) Use a suitable shared library mechanism for linking with
the Library. A suitable mechanism is one that (a) uses at run
time a copy of the Library already present on the user's
computer system, and (b) will operate properly with a modified
version of the Library that is interface-compatible with the
Linked Version.
- e) Provide Installation Information, but only if you would
otherwise be required to provide such information under section 6
of the GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the Application
with a modified version of the Linked Version. (If you use option
4d0, the Installation Information must accompany the Minimal
Corresponding Source and Corresponding Application Code. If you
use option 4d1, you must provide the Installation Information in
the manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.)
#### 5. Combined Libraries.
You may place library facilities that are a work based on the Library
side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
- a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities, conveyed under the terms of this License.
- b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
#### 6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
as you received it specifies that a certain numbered version of the
GNU Lesser General Public License "or any later version" applies to
it, you have the option of following the terms and conditions either
of that published version or of any later version published by the
Free Software Foundation. If the Library as you received it does not
specify a version number of the GNU Lesser General Public License, you
may choose any version of the GNU Lesser General Public License ever
published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

96
fontcharacter/Makefile Executable file
View File

@ -0,0 +1,96 @@
#!/usr/bin/make -f
#*****************************************************************************#
# Include variables and message subsystem #
#*****************************************************************************#
include Makefile.vars Makefile.msg
#*****************************************************************************#
# General targets #
#*****************************************************************************#
# Build everything.
all: all-sets
# Mostly clean everything.
mostlyclean mclean: mostlyclean-sets
# Clean everything.
fclean clean: clean-sets
# Clean to original state.
mrproper: clean
$(call rmsg,Removing configuration.)
$(call qcmd,$(RM) Makefile.cfg)
# Remake everything (clean and build).
re: clean all
# Install everything.
install: install-sets
# Make a distribution tarball.
dist: mrproper
$(call bcmd,mkdir,$(NAME)-$(VERSION), $(MD) .dist)
$(call bcmd,cp,* $(NAME)-$(VERSION), $(CP) -R * .dist)
$(call qcmd,$(MV) .dist $(NAME)-$(VERSION))
$(call bcmd,tarball,$(NAME)-$(VERSION),\
tar czf $(NAME)-$(VERSION).tar.gz --exclude .git $(NAME)-$(VERSION))
$(call qcmd,$(RM) -r $(NAME)-$(VERSION))
.PHONY: all mostlyclean mclean clean fclean mrproper re
.PHONY: dist install
#*****************************************************************************#
# Configuration (version) checking dependencies #
#*****************************************************************************#
# Define the dependencies.
CHECKCFG := $(if $(shell test -f Makefile.cfg || echo y),check-config, \
$(if $(shell [ "$(VERSION)" = "$(CONFIG_VERSION)" ] || echo y), \
check-config-version))
# Define the rules.
check-config:
@echo -e "\033[1;31mNo configuration file found!"
@echo -e "You should configure before re-running this target.\033[0m"
@false
check-config-version:
@echo -e "\033[1;31mConfiguration version is incorrect!"
@echo -e "You should re-configure before re-running this target.\033[0m"
@false
.PHONY: check-config check-config-version
#*****************************************************************************#
# Information getting from the Makefile variables #
#*****************************************************************************#
# Get the project name.
getname:
@echo $(NAME)
# Get the project version.
getversion:
@echo $(VERSION)
# Get the maintainer.
getmaintainer:
@echo "Thomas \"Cakeisalie5\" Touhey <thomas@touhey.fr>"
.PHONY: getname getversion getmaintainer
#*****************************************************************************#
# Sets-related targets #
#*****************************************************************************#
# Make the sets.
all-sets: $(SET_FILES)
$(SET_FILES): $(CHECKCFG) $(REF) tools/makebin.py
$(call bcmd,makebin,$(SETDIR),\
tools/makebin.py --output $(SETDIR) --refpath $(REFDIR))
# Clean all of the sets
clean-sets:
$(call rmsg,Cleaning the sets.)
$(call qcmd,rm -rf $(SETDIR))
# Install all of the sets.
install-sets: all-sets
$(call imsg,Installing the sets.)
$(call qcmd,$(MD) "$(ISETDIR)")
$(call qcmd,$(INSTALL) $(SETS) "$(ISETDIR)")
.PHONY: all-sets clean-sets install-sets
# End of file.

57
fontcharacter/Makefile.msg Executable file
View File

@ -0,0 +1,57 @@
#!/usr/bin/make -f
# The Makefile message subsystem.
# For nice logs. 5 dollars per log only.
#*****************************************************************************#
# Colors and misc #
#*****************************************************************************#
# Used colors ANSI modifiers escape codes
color_green := 32
color_red := 31
color_yellow := 33
# Newline - comes handy in some situations
define \n
endef
#*****************************************************************************#
# General messages #
#*****************************************************************************#
# Command message - display basic info about the command, and run it.
define cmd
@$(if $(MAKE_FULL_LOG),,\
printf "\033[1;""$4""m>\033[0m \033[1m%s\033[0m %s\n" "$1" "$2";)
$(if $(MAKE_FULL_LOG),,@)$3
endef
# Quiet command - make it non-quiet if full log is enabled.
define qcmd
$(if $(MAKE_FULL_LOG),,@)$1
endef
# Normal message - display it.
define msg
$(if $(MAKE_FULL_LOG),,\
@printf "\033[1;""$2""m>\033[0m \033[1m%s\033[0m\n" "$1")
endef
#*****************************************************************************#
# Commands #
#*****************************************************************************#
# Build command
define bcmd
$(call cmd,$1,$2,$3,$(color_green))
endef
#*****************************************************************************#
# Messages #
#*****************************************************************************#
# Remove message
define rmsg
$(call msg,$1,$(color_red))
endef
# Install message
define imsg
$(call msg,$1,$(color_yellow))
endef
# End of file

62
fontcharacter/Makefile.vars Executable file
View File

@ -0,0 +1,62 @@
#!/usr/bin/make -f
# Include the configuration.
-include Makefile.cfg
#*****************************************************************************#
# Project main information. #
#*****************************************************************************#
# Project name and description.
NAME := refc
DESC := The FONTCHARACTER reference.
# Project version.
MAJOR := 0
MINOR := 1
INDEV := yes
# Project version string.
VERSION := $(MAJOR).$(MINOR)$(if $(INDEV),-indev)
#*****************************************************************************#
# Project directories #
#*****************************************************************************#
# Reference directory.
REFDIR := ./reference
# Sets (output) directory.
SETDIR := ./sets
#*****************************************************************************#
# Sets-related information #
#*****************************************************************************#
# List the sets.
SETS := $(shell tools/listsets.py --refpath $(REFDIR))
# List the set files.
SET_FILES := $(SETS:%=$(SETDIR)/%.set)
#*****************************************************************************#
# Binary utilities #
#*****************************************************************************#
# Make the binary file.
MAKEBIN := tools/makebin.py
# Make a directory.
MD := mkdir -p
# Install.
INSTALL := /usr/bin/install
# Remove a file.
RM := rm -f
#*****************************************************************************#
# Check for DESTDIR (add as prefix to installation root) #
#*****************************************************************************#
# Save original sets dir.
OISETDIR := $(ISETDIR)
# Make it.
define add-dest-dir
$1 = $(DESTDIR)$($1)
endef
$(if $(DESTDIR), $(foreach idir,\
ISETDIR,\
$(eval $(call add-dest-dir,$(idir)))))
# End of file.

23
fontcharacter/README.md Normal file
View File

@ -0,0 +1,23 @@
# FONTCHARACTER Reference
## Introduction
`FONTCHARACTER` is how, in the CASIO community, we call CASIO's encoding.
It is an encoding made up for CASIO calculators. It is partially
ASCII retrocompatible.
It is a simple multi-byte encoding, where some characters are multi-byte
sequence leaders. Each character can occupy up to two bytes (leading character,
then whatever -- a leading character after another one isn't).
For example, if 0xE5 is a leading character, 0xE5 followed by 0xE5 forms
the 0xE5E5 character, and if 0x46 isn't, it forms the 0x46 character.
This project is here to centralize all the info about it : existing characters,
their appearance in the standard fonts, their Unicode equivalents and defines.
The goal of this project is to give the ability to any project (thanks to
[LGPL3][lgpl3]) to be able to read, write, describe and convert from or to
CASIO's proprietary encoding.
You can use this reference through its source format, through its binary
format (better), or through [libfontcharacter][libfc] (recommended!).
[libfc]: https://github.com/PlaneteCasio/libfontcharacter
[lgpl3]: https://www.gnu.org/licenses/lgpl-3.0.en.html

3
fontcharacter/TODO.md Normal file
View File

@ -0,0 +1,3 @@
# TODO in FONTCHARACTER Reference
- Check out the unknown/undocumented characters (`UNKNOWN.md`);
- Develop the set systems, make them represent the encoding history;

94
fontcharacter/UNKNOWN.md Normal file
View File

@ -0,0 +1,94 @@
# Unknown/unused/undocumented characters (in default set)
People should investigate on these. Maybe they're used but I forgot to include
them. Maybe they're not used ('@' or 0xLL40 where 0xLL is the lead character),
yet. Oh, and I may have forgotten some.
0x90
0x9D
0xD2
0x7F03
0x7F07
0x7F13
0x7F17
0x7F1B-0x7F1C
0x7F31-0x7F39
0x7F58-0x7F5F
0x7F69
0x7F70-0x7F75
0x7F7E-0x7F83
0x7F8B
0x7F99-0x7F9B
0x7F9D-0x7F9F
0x7FAF
0x7FB2
0x7FB8
0x7FBF
0x7FCF
0x7FDF
0x7FE5-0x7FE8
0x7FF5-0x7FFA
0x7FFF
0xF70F
0xF717
0xF737-0xF739
0xF73B
0xF73D-0xF73E
0xF754
0xF766
0xF772-0xF775
0xF77B-0xF77C
0xF77F
0xF781-0xF786
0xF78A-0xF78B
0xF79B-0xF79D
0xF7AE
0xF7CF
0xF7DE-0xF7FF
0xF900
0xF90D-0xF90F
0xF91A
0xF91F
0xF923
0xF940-0xF949
0xF94C-0xF95A
0xF95C-0xF95D
0xF95F-0xF96C
0xF96E-0xF97F
0xF998-0xF99F
0xF9BE-0xF9DF
0xF9E4-0xF9E7
0xF9F3-0xF9FA
0xF9FF
0xE500
0xE51F
0xE536-0xE53F
0xE559-0xE55F
0xE57F
0xE5A8-0xE5AF
0xE5E0-0xE5FF
0xE600
0xE636-0xE63F
0xE659-0xE65F
0xE67F
0xE6BA
0xE6DF-0xE6FF
0xE700
0xE718
0xE730-0xE740
0xE77B-0xE7AF
0xE7B1
0xE7BC
0xE7BE
0xE7C1
0xE7C6
0xE7D6
0xE7E0-0xE7E1
0xE7E5-0xE7E7
0xE7F6-0xE7FA
0xE7FC-0xE7FF

123
fontcharacter/configure vendored Executable file
View File

@ -0,0 +1,123 @@
#!/bin/sh
cd "$(dirname $0)"
#*****************************************************************************#
# Defaults #
#*****************************************************************************#
# Project variables
[ -f Makefile.cfg ] && mv Makefile.cfg Makefile.cfg.tmp
name="$(make -s getname)"
version="$(make -s getversion)"
maintainer="$(make -s getmaintainer)"
[ -f Makefile.cfg.tmp ] && mv Makefile.cfg.tmp Makefile.cfg
# Make options.
make_full_log=
# Build options.
no_unicode=
# Installation directories.
root=''
prefix='${root}/opt/p7-project'
setdir='${prefix}/share/casio-fontcharacter/'
#*****************************************************************************#
# Help message #
#*****************************************************************************#
usage() {
cat <<EOF
\`configure\` configures the FONTCHARACTER reference to bend it to your will.
Usage: $0 [OPTION...]
Defaults for the options are specified in brackets.
General options:
--help display this help and exit
--version display version information and quit
--make-full-log display full commands while making
Build options:
--no-unicode do not include Unicode translations in the files
Installation options:
--root=ROOT installation root [$root]
--prefix=PREFIX main installation prefix [$prefix]
Fine tuning of the installation directories:
--setdir=SETDIR sets directory [$setdir]
Report bugs to ${maintainer}.
EOF
exit 0
}
#*****************************************************************************#
# Version message #
#*****************************************************************************#
version() {
cat <<EOF
${name} configure script v${version }
Hand-written by Thomas "Cakeisalie5" Touhey.
This configure script is free software.
There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
EOF
exit 0
}
#*****************************************************************************#
# Check for help and version #
#*****************************************************************************#
put_version=
put_help=
for arg ; do case "$arg" in
--help|-h) put_help=1 ;;
--version|-v) put_version=1 ;;
esac; done
[ $put_version ] && version
[ $put_help ] && usage
#*****************************************************************************#
# Parse arguments #
#*****************************************************************************#
for arg ; do case "$arg" in
--make-full-log) make_full_log=yes ;;
--no-unicode) no_unicode=yes ;;
--root=*) root="${arg#*=}" ;;
--prefix=*) prefix="${arg#*=}" ;;
--setdir=*) setdir="${arg#*=}" ;;
esac; done
# Evaluate variables
vars="prefix setdir"
for var in $vars; do
eval $var'='$(eval 'echo $'$var)
done
#*****************************************************************************#
# Create Makefile configuration #
#*****************************************************************************#
# Clean before.
make clean MAKE_FULL_LOG=y 1>/dev/null 2>/dev/null
# Do it!
exec 3>&1 1>Makefile.cfg
cat <<EOF
#*****************************************************************************#
# Makefile configuration generated by ./configure #
#*****************************************************************************#
# Configuration version and messages configuration
CONFIG_VERSION := $version
MAKE_FULL_LOG := $make_full_log
# Build options.
NO_UNICODE := $no_unicode
# Installation directories
ISETDIR := $setdir
# End of file.
EOF
exec 1>&3 3>&-
chmod +x Makefile.cfg
# Print the end message.
echo "Configuration loaded, you can make now."
# End of file.

View File

@ -0,0 +1,113 @@
# Binary format (Version 1)
**This format is a draft. It will be completed as the version 1.0 of the**
**reference is release.**
The binary file is divided into four zones:
- the overall header;
- the leading character pool;
- the character pool;
- the data pool.
Multi-byte integer fields are encoded as **big endian**.
## Overall header
The file starts with an overall header, describing the structure of the rest
of the file. As all of the files under any binary format representing
a FONTCHARACTER reference set, the file starts with:
- Magic string (8 bytes): "CASIOFC\x7F";
- Version byte (1 byte) -- in this version of the format, it is 0x01.
If the magic string is not verified, the file is either corrupted or of an
other file. If the version byte isn't verified, then the file uses a different
version from the current one, and you should return that the user needs an
upgraded version of your utility (because you'll keep updating it... right?),
or a more recent utility.
From there, the file is under this specific version of the format.
The overall header continues with the following fields:
- Number of majors (1 byte): this is the number of entries in the leading
characters pool (second zone of the file);
- Number of characters (2 bytes): the total number of characters;
- Flags (1 byte): the flags:
- 0x01: Unicode is enabled (see character entry);
- 0x02: CAT tokens are enabled (see character entry);
- 0x04: Newcat tokens are enabled (see character entry);
- 0x08: CTF tokens are enabled (see character entry);
- 0x10: Casemul tokens are enabled (see character entry);
- Picture height (1 byte): the picture width;
- Picture format (2 bytes): the picture format used to represent the
characters, taken from libcasio's [picture.h][picture.h].
Allowed formats are:
- 0x0100: monochrome with fill bits;
- Reserved (4 bytes): should be zero;
- Checksum (4 bytes): basic checksum for the leading character pool,
character pool, and data pool (if zero, do not check the checksum);
- File size (4 bytes): the file size;
- Data zone size (4 bytes): the data zone size.
The checksumming technique is simple: you add all of the data, byte per byte,
in a 32-bit variable. For example, the checksum of \[0xFF, 0x02, 0x03\] is
0x00000104. Overflow is allowed (0xFFFFFFFF + 2 = 0x00000001).
## Leading character pool
This pool provides quick access to the characters under a leading-character.
Each entry is made of the following:
- Leading character byte (1 byte), e.g. 0x00 or 0xE5;
- Reserved (1 byte), always zero;
- Starting entry ID in the character pool (2 bytes);
The offset is to be multiplied by the size of a character entry (which is
constant).
## Character pool
This pool provides the character entries. For quick access, each entry is
the same size, the variable data being stored in the data pool.
Each entry has the following format:
- Leading character (1 byte), e.g. 0x00 or 0xE5;
- Main character (1 byte), e.g. 0x45 for 0xE545;
- FONTCHARACTER sequence size (1 byte), 0 if not a FONTCHARACTER sequence;
- Unicode string size (1 byte), 0 if no unicode string;
- CAT token size (1 byte), 0 if no CAT token;
- Newcat token size (1 byte), 0 if no Newcat token;
- CTF token size (1 byte), 0 if no CTF token;
- Casemul token size (1 byte), 0 if no Casemul token;
- FONTCHARACTER sequence offset in data pool (4 bytes);
- (only if Unicode is enabled in the flags)
Unicode string offset in data pool (4 bytes);
- (only if CAT is enabled in the flags)
CAT token offset in data pool (4 bytes);
- (only if Newcat tokens are enabled in the flags)
Newcat token offset in data pool (4 bytes);
- (only if CTF tokens are enabled in the flags)
CTF token offset in data pool (4 bytes);
- (only if Casemul tokens are enabled in the flags)
Casemul token offset in data pool (4 bytes);
The entry size is indeed different among all of the files, but constant for
one file, as the flags correspond to the overall header flags.
## Data pool
Raw data is stored here. To get the size of this zone, take the file size
in the overall header and remove the size of the three previous zones.
This size is duplicated in the header, and the correlation between the
calculated and given sizes should be checked.
Notice that bytes don't need to be in the same order than characters, and
can be indexed several times, which can lead to space optimizations.
For example, if a character points to [0x02, 0x03] and another
one points to [0x01, 0x02] (in any order), you can put [0x01, 0x02, 0x03] in
the data pool, then make the first character point to the offset + 1 of
this tab, and the second one point to the offset of this tab.
This system allows space optimizations to be done to this zone at build time,
although optimizing this depends on the [shortest superstring][superstr]
problem.
[picture.h]: https://github.com/PlaneteCasio/libcasio/blob/master/include/libcasio/picture.h
[superstr]: https://en.wikipedia.org/wiki/Shortest_common_supersequence_problem

View File

@ -0,0 +1,176 @@
# Source format
This format is yet to stabilize. If you just want to use the reference for
conversions between FONTCHARACTER and other character sets (which should
be managed by [libcasio][libcasio] anyway), check out the latest binary
format (`BINARYx.md`).
YAML has been chosen to store the information, as it's a storage format that
a machine and a human can read and write quite easily.
## Main file
`main.yml` is the file containing the main information about the source
reference. It only contains two fields for now:
- `version` is the version of the source reference (`0.1` corresponds to this
version);
- `source` is the link to the FONTCHARACTER reference's source repository,
managed through a VCS (Git, for that matter).
## Sets
A set is basically a pack of characters appeared at the same time on CASIO
calculators, or in an extension (alternative CASIO Basic
interpreters/compilers).
`sets.yml` is the sets file. For each set:
- the `description` field is the description of the set;
- if the `default` field is there, then it is the default set to use
(generally the most recent set made by CASIO);
- if the `leading` field is there, the list of leading characters is in it,
separated by commas;
- if the `parent` field is there, then the set inherits all of the characters
of its parents, and, if the child has no `leading` field, its parent's
leading characters.
## Categories
`categories.yml` is the categories file. Each category has an `id` field, which
is the identification string, an optional `prefix` field and an optional `sub`
list, which is the subcategories with each an `id` and a `prefix` fields.
To access the subcategory "Latin Capital" in the category "Letter", the
`category` field in the character information will have to be
`Letter/Latin Capital/Mini`. The name of the character will then be prefixed by
`Mini Latin Capital Letter ` (with the spaces between prefixes and an ending
space); the subcategory prefix goes first. If there is a suffix, a space then
it are appended to the character name, for example, ` Digit`.
There are some more fields -- see the _Embedded CASIO BASIC documentation_
section.
## Characters
There are two systems of characters on CASIO calculators: Simon Lothar calls
them the "characters" and the "opcodes". The "characters" are simple characters
with a display, and the "opcodes", which are defined by a set of characters
(e.g. "Locate "). The two are described in two different tables on the
calculator, but the two describe the same encoding, so that's why this
reference considers all "characters" and "opcodes" as characters ("opcodes"
are here called multi-characters).
`characters.yml` is the file containing data about the characters. For each
character, the `code` field is its `FONTCHARACTER` code, the `name` field is
the complete description of the character, the `flags` are the character flags
and the `category` field is the category(/subcategory) ID (see in the last
paragraph). If there is no category field, the category is "Other", with no
prefix.
Flags is a list of flag strings. Current flags are:
* `nl`: the character should be followed by a newline;
* `esc`: the character's CTF token is escaped with a reverse solidus;
* `sep`: the character is a Basic separator;
* `base`: only accessible in BASE programs.
Some characters have an ASCII token representation, mostly for the *cat*,
*newcat*, *ctf* and *casemul* formats. If the `tokens` field exists, then
it is a dictionary of the tokens in the different formats.
- If the `cat` field of the dictionary doesn't exist, its value is deduced
recursively using the `multi` field is there, or from the `unicode` field
(if all-`ASCII`), and prefixed by a reverse solidus '\\';
- If the `newcat` field of the dictionary doesn't exist, it takes its
value from the `cat` field;
- If the `ctf` field of the dictionary doesn't exist, it takes its value from
the `cat` field if it was not deduced, otherwise, it is deduced the same way
as the `cat` field, but it is not prefixed with a reverse solidus '\\';
- If the `casemul` field of the dictionary doesn't exist, it is deduced the
same way than the `ctf` field;
- If the `ref` field of the dictionary doesn't exist, it takes the
(first) value of the `ctf` field.
There can be multiple tokens for one format; in this case, the value of the
format field is a list.
It is possible to obtain an ASCII/HTML representation of most characters:
- If tokens exist, take the `ref` token;
- Otherwise, if the `multi` field is specified, then the representation can be
obtained recursively by querying this field's elements;
- Otherwise, no ASCII representation is available.
The `id` field is an identifier for the character, composed of letters,
numbers and underscores. It can be used for C defines.
If there is no `id` field, it is the value in the `ascii` field if it can
be deduced (or the `name` field if it can't), with hyphens turned into
underscores, and other non-valid characters removed (spaces, parenthesis, ...).
You have to distinguish multi-characters opcodes and simple opcodes.
Multi-character opcodes are characters that simply are a sequence of simple
characters. You can distinguish them from simple opcodes by checking the
presence of a `multi` field, which then is the `FONTCHARACTER` codes of the
characters in the sequence, separated with commas.
Multi-characters are distinguishable from simple characters by checking the
presence of a `multi` field. The `multi` field is the `FONTCHARACTER` codes of
the characters composing it, separated by commas. Be careful: there can be
only one character for the multi-character, and Yaml won't interpret this as
a string, but as a number directly!
If the character is simple, then if there is a unicode sequence equivalent of
the character, the Unicode codes of the sequences separated with commas will be
in the `unicode` field; otherwise, the field doesn't exist.
If the character data has a `set` field, then the character is in a set;
otherwise, it should be considered as part of the default set.
### Embedded CASIO BASIC documentation
Some characters will have the `type` field. This type means they have a special
meaning in CASIO Basic. There are two types: `function` and `object`. There is
an associated syntax, which is either `<name>(arg1, arg2)` or
`<name> arg1,arg2`, the first syntax is when `par` is `true` and the second one
is when it is `false`.
Note that for the first syntax, the ending parenthesis is not mandatory.
If `par` is `false` (or non-existent), then the `fix` field can be
set to `infix`, which means the function will be used with either
`arg1 <name>` or `arg1 <name> arg2`.
If the function/object should receive arguments, it can be documented using the
`args` field, and if it has, after these arguments, optional arguments, it can
be documented with the `optn` field. These fields receives a list of argument
strings. An argument type can be imposed by add-in `:<code>` at the end of the
argument string; for example, here are the `For` and `To` entries:
-
code: 0xF704
name: For
category: Statement
args: ["to:0xF705"]
action: ...
multi: [0x46, 0x6F, 0x72, 0x20]
-
code: 0xF705
name: To
category: Operator
args: ["assign:0x0E"]
optn: ["step:0xF706"]
action: ...
multi: [0x20, 0x54, 0x6F, 0x20]
If the function is supposed to make an action, this action can be documented
using the `action` field. If it is supposed to return something, it should can
be documented using the `return` field.
## Fonts
`fonts.yml` is the file containing the fonts information. For each font,
`id` is the ID string, `name` is the complete name, `author` is the complete
author name, `width` and `height` are the dimensions of each character in
the font.
For each font, there is a corresponding folder, named with the font ID.
This folder contains the characters images, organized by the leading multi-byte
character; if there is none, the file `0xXX.pbm` will be chosen, otherwise,
the file `0xLLXX.pbm` will be chosen, where `0xLL` is the leading character.
If the file doesn't exist, the character is to be considered as blank.
Each existing file is a set of 256 tiles of `width * height` each. Each row is
the tiles going from `0xR0` to `0xRF`, where `0xR` is the row number
(0x0 to 0xF).
[libcasio]: https://libcasio.planet-casio.com/

View File

@ -0,0 +1,123 @@
#******************************************************************************#
# Letters #
#******************************************************************************#
-
id: Letter
prefix: Letter
sub:
-
id: Latin Capital
prefix: Latin Capital
sub:
-
id: Squared
prefix: Squared
sub:
-
id: Negative
prefix: Negative
-
id: Mini
prefix: Mini
-
id: Latin Small
prefix: Latin Small
sub:
-
id: Mini
prefix: Mini
-
id: Greek Capital
prefix: Greek Capital
-
id: Greek Small
prefix: Greek Small
-
id: Cyrillic Capital
prefix: Cyrillic Capital
-
id: Cyrillic Small
prefix: Cyrillic Small
-
id: Ligature
prefix: Ligature
sub:
-
id: Latin Capital
prefix: Latin Capital
-
id: Latin Small
prefix: Latin Small
#******************************************************************************#
# Other "normal" categories #
#******************************************************************************#
-
id: Digit
prefix: Digit
-
id: Superscript
prefix: Superscript
sub:
-
id: Sign
suffix: Sign
-
id: Small
prefix: Small
-
id: Subscript
prefix: Subscript
sub:
-
id: Small
prefix: Small
-
id: Sign
suffix: Sign
-
id: Sign
suffix: Sign
-
id: Symbol
suffix: Symbol
#******************************************************************************#
# CASIO-related categories #
#******************************************************************************#
-
id: Statement
type: function
par: true
suffix: Statement
-
id: Operator
type: function
fix: infix
suffix: Operator
sub:
- id: Prefix
fix: prefix
suffix: Prefix
-
id: Register
type: function
args: []
suffix: Register
-
id: Object
type: object
par: false
suffix: Statement
sub:
-
id: Infix
fix: infix
-
id: Function
type: function
par: true
suffix: Function
-
id: Unit
suffix: Unit

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
-
id: normal
name: CASIO normal font
author: CASIO
width: 5
height: 7
-
id: mini
name: CASIO mini font
author: CASIO
width: 5
height: 5

View File

@ -0,0 +1,2 @@
version: "0.1"
source: https://github.com/planetecasio/fontcharacter_reference

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,29 @@
#******************************************************************************#
# CASIOWIN character sets #
#******************************************************************************#
-
id: CASIOWIN_1.00
default: true
leading: 0x7F,0xF7,0xF9,0xE5,0xE6
description: Original CASIOWIN (CASIO's SuperH custom OS) encoding.
-
id: CASIOWIN_1.05
parent: CASIOWIN_1.00
description: Added in OS 1.05 (or before, don't know yet).
-
id: CASIOWIN_2.00
parent: CASIOWIN_1.05
leading: 0x7F,0xF7,0xF9,0xE5,0xE6,0xE7
description: Added in OS 2.00.
-
id: CASIOWIN_2.04
parent: CASIOWIN_2.00
description: Added in OS 2.04.
#******************************************************************************#
# Extensions #
#******************************************************************************#
-
id: C.Basic
description: Added with C.Basic, an alternative interpreter made by Sentaro21.
parent: CASIOWIN_2.00

216
fontcharacter/tools/dumpbin.py Executable file
View File

@ -0,0 +1,216 @@
#!/usr/bin/env python3
""" Utility to dump data from a set binary file.
Mainly here to check that the format is correct for now.
"""
import os, unicodedata
from functools import cmp_to_key
from argparse import ArgumentParser
# ---
# Decoding function.
# ---
def frombytes(bnum):
if type(bnum) == int: return bnum
return int.from_bytes(bnum, byteorder='big', signed=False)
leaders = {}
def decode_set1(braw, only_check=True):
# Get the rest of the header, check the sum and filesize
cmajors = frombytes(braw[9])
cchars = frombytes(braw[10:12])
flags = frombytes(braw[12])
pic_h = frombytes(braw[13])
pic_fmt = frombytes(braw[14:16])
checksum = frombytes(braw[20:24])
filesize = frombytes(braw[24:28])
datasize = frombytes(braw[28:32])
# Get the flags.
with_unicode = flags & 0x01 != 0
with_cat = flags & 0x02 != 0
with_newcat = flags & 0x04 != 0
with_ctf = flags & 0x08 != 0
with_casemul = flags & 0x10 != 0
# Make the entry size.
centsize = 8 + 4 + 4 * \
(with_unicode + with_cat + with_newcat + with_ctf + with_casemul)
# Check the sizes and the checksum.
if filesize != len(braw):
print("ERROR: Invalid filesize!",
"Declared %dB, calculated %dB"%(filesize, len(braw)))
return 1
calc_datasize = filesize - 32 - 4 * cmajors - centsize * cchars
if datasize != calc_datasize:
print("ERROR: Invalid datasize!",
"Declared %dB, calculated %dB"%(datasize, calc_datasize))
return 1
calc_checksum = sum(braw[32:])
if checksum != calc_checksum:
print("ERROR: Invalid checksum!",
"Declared 0x%08X, calculated 0x%08X"%(checksum, calc_checksum))
return 1
# Get the binary data.
data_off = filesize - datasize
bdata = braw[data_off:]
# Get leaders.
braw = braw[32:data_off]
leads = []
for id_major in range(cmajors):
bmajor = braw[id_major * 4:id_major * 4 + 4]
code = frombytes(bmajor[0])
if code in leads:
print("ERROR: Duplicate major 0x%02X."%code)
return 1
leads += [code]
leaders[code] = {
'start': frombytes(bmajor[2:]),
'count': 0,
'chars': {},
'pos': id_major
}
# Sort leaders.
def cmp_lead(x, y):
global leaders
if leaders[x]['start'] == leaders[y]['start']:
return x if leaders[x]['pos'] < leaders[y]['pos'] else y
return x if leaders[x]['start'] < leaders[y]['start'] else y
leads.sort(key=cmp_to_key(cmp_lead))
# Get counts.
for id in range(len(leads) - 1):
leaders[leads[id]]['count'] = \
leaders[leads[id + 1]]['start'] - leaders[leads[id]]['start']
leaders[leads[-1]]['count'] = cchars - leaders[leads[-1]]['start']
# Get characters according to their leader.
braw = braw[cmajors * 4:]
for lead in leaders:
for id_char in range(leaders[lead]['start'], \
leaders[lead]['start'] + leaders[lead]['count']):
bchar = braw[id_char * centsize:id_char * centsize + centsize]
code = frombytes(bchar[:2])
if code >> 8 != lead:
print("ERROR: character 0x%04X at position %d"%(code, id_char),
"should have leader 0x%02X but"%lead,
"has leader 0x%02X!"%(code >> 8))
return 1
if code in leaders[lead]['chars']:
print("ERROR: duplicate character 0x%04X"%code,
"at position %d"%id_char,
"(prev. %d)"%leaders[lead]['chars']['pos'])
return 1
# Get the FONTCHARACTER sequence.
mul_off = frombytes(bchar[8:12])
mul_sz = frombytes(bchar[2])
mul = None
if mul_sz:
rmul = bdata[mul_off:mul_off + mul_sz]
mul = []
while rmul:
if rmul[0] in leaders:
mul += [(rmul[0] << 8) | rmul[1]]
rmul = rmul[2:]
continue
mul += [rmul[0]]
rmul = rmul[1:]
# Get the Unicode string.
uni = None
off = 12
if with_unicode:
uni_sz = frombytes(bchar[3])
uni_off = frombytes(bchar[off:off + 4])
off += 4
if uni_sz:
runi = bdata[uni_off:uni_off + uni_sz]
uni = runi.decode('utf-8')
# TODO: get the rest
leaders[lead]['chars'][code] = {
'uni': uni,
'mul': mul,
'pos': id_char
}
if only_check:
return 0
print("OVERALL HEADER")
print("%d bytes (data zone is %dB)"%(filesize, datasize))
print("%d leader characters, %d characters"%(cmajors, cchars))
print("")
print("Tokens and sequences in this file:")
print("- FONTCHARACTER sequences")
if with_unicode: print("- Unicode equivalents")
if with_cat: print("- CAT tokens")
if with_newcat: print("- Newcat tokens")
if with_ctf: print("- CTF tokens")
if with_casemul: print("- Casemul tokens")
print("")
for lead, data in leaders.items():
print("0x%02X LEADER"%lead)
print("Starts at character 0x%04X, stops at 0x%04X (count: %d)"
%(data['start'], data['start'] + data['count'] - 1,
data['count']))
if data['chars']:
print("")
for code, char in data['chars'].items():
print("- 0x%0*X"%(4 if code > 0xFF else 2, code), end='')
mul = char['mul']
if mul:
m = ', '.join(map(lambda x:"0x%0*X"%(4 if x > 0xFF else 2, x),
mul))
print(" - seq: %s"%m, end='')
uni = char['uni']
if uni:
if any(map(lambda c:unicodedata.category(c).startswith('C'), \
uni)):
uni = ''.join(map(lambda x:'\\x%02X'%ord(x), uni))
print(" - unicode: \"%s\""%uni, end='')
print("")
print("")
return 0
def decode_set(braw, only_check=True):
global leaders
# Check the magic.
bmagic = braw[:9]
if bmagic[:8] != b"CASIOFC\x7f":
print("ERROR: Invalid magic string!")
return 1
if bmagic[8] == 0x01:
return decode_set1(braw, only_check)
else:
print("ERROR: Unmanaged version 0x%02X!"%bmagic[8])
return 1
# ---
# Main function.
# ---
if __name__ == '__main__':
# Parse the arguments.
ap = ArgumentParser(description='FONTCHARACTER binary file dumper')
ap.add_argument('--only-check', help='Should only check if the file is valid',
action="store_true")
ap.add_argument('input', help='The file which to dump the content.')
args = ap.parse_args()
# Obtain the file.
braw = open(args.input, "rb").read()
# Decode it.
exit(decode_set(braw, args.only_check))
# End of file.

View File

@ -0,0 +1,190 @@
#!/usr/bin/env python3
""" The FONTCHARACTER Python module is used for manipulating the source
and binary formats. See <../../formats/SOURCE.md> for more information.
"""
import os, sys, string, yaml
# Sainitize for the `id` field
def sanitize_id(s):
return ''.join(ch for ch in s \
if ch in string.ascii_letters + string.digits)
class Reference:
""" The FONTCHARACTER source object.
Loads the characters and corrects the data. """
def __init__(self, path, sets_only=False):
# Load sets
self.__load_sets(yaml.load(open(\
os.path.join(path, 'sets.yml')).read()))
if sets_only: return
# Load categories
self.categories = {}
for c in yaml.load(open(os.path.join(path, 'categories.yml')).read()):
self.__explore_category(c, '', '', '')
# Load all of the YAML files
self.__load_characters(yaml.load(open(\
os.path.join(path, 'characters.yml')).read()))
# Gather leaders [TODO: `leading` field?]
for st in self.sets.keys():
lead = []
for code in self.sets[st]['characters'].keys():
lead += [code >> 8]
self.sets[st]['leading'] = set(lead)
def __explore_category(self, c, id, prefix, suffix):
""" Explore a category. """
# Iterate on things
id += c['id']
try: prefix = c['prefix'] + ' ' + prefix
except: True
try: suffix = suffix + ' ' + c['suffix']
except: True
# Add current (sub)category
self.categories[id] = {'prefix': prefix, 'suffix': suffix}
# Explore subcategories
if c.get('sub'):
for s in c['sub']:
self.__explore_category(s, id + '/', prefix, suffix)
def __load_sets(self, raw):
""" Explore sets. """
self.default_set = ''
self.sets = {}
# Initialize kids
kids = {}
# Read raw entries
for s in raw:
self.sets[s['id']] = {
'description': s['description'],
'characters': {},
'parent': s.get('parent'),
'kids': []}
if s.get('default'): self.default_set = s['id']
if s.get('parent'):
if not kids.get(s['parent']): kids[s['parent']] = []
kids[s['parent']] += [s['id']]
# Add kids to real elements
for parent, k in kids.items():
self.sets[parent]['kids'] += kids[parent]
def __inherit_character(self, id, code, inherit, pr):
""" Inherit character.
`id`: id of the set, code: code of the character,
`inherit`: the set to inherit it from,
`pr`: priority (starting from 0, the more the further). """
if not self.sets[id]['characters'].get(code) \
or self.sets[id]['characters'][code]['_pr'] > pr:
self.sets[id]['characters'][code] = {'inherit': inherit, '_pr': pr}
for k in self.sets[id]['kids']:
self.__inherit_character(k, code, inherit, pr + 1)
def __load_characters(self, raw):
""" Load characters. """
# Main loop
for c in raw:
# Get the complete name
n = c['name']
if c.get('category'):
ct = self.categories[c['category']]
n = ct['prefix'] + n + ct['suffix']
# Get the character set, and the priority
try: st = c['set']
except: st = self.default_set
# Make the character
code = c['code']
char = {'name': n, '_pr': 0}
# Check the multi thingy
m = c.get('multi')
if type(m) == list and m:
char['multi'] = \
list(map(lambda x:int(x, 16) if type(x) == str else x, m))
elif type(m) == int:
char['multi'] = [m]
# Check the unicode thingy
u = c.get('unicode')
if type(u) == list and u:
char['unicode'] = \
list(map(lambda x:int(x, 16) if type(x) == str else x, u))
elif type(u) == int:
char['unicode'] = [u]
# Check the ascii thingy
if c.get('ascii'):
char['ascii'] = c['ascii']
elif char.get('unicode') \
and all(0x00 <= c <= 0xFF for c in char['unicode']):
char['ascii'] = ''.join(map(chr,char['unicode']))
# Check the id thingy
if c.get('id'):
char['id'] = c['id']
elif char.get('ascii'):
char['id'] = sanitize_id(char['ascii'])
if not char.get('id') and not char.get('multi'):
char['id'] = sanitize_id(char['name'])
# Add it to the set
self.sets[st]['characters'][code] = char
for k in self.sets[st]['kids']:
self.__inherit_character(k, code, st, 1)
# Get ascii/unicode equivalents
for id, st in self.sets.items():
for code in st['characters'].keys():
self.__deduce_character_id(id, code)
def __deduce_character_id(self, id, code):
""" Calculate a multi-character's ID. """
char = self.sets[id]['characters'][code]
if char['_pr'] > 0 or char.get('id'): return
m = ""
if not char.get('multi'): m = sanitize_id(char.get('name'))
else:
for num, c in map(lambda x:(x, self.sets[id]['characters'][x]), \
char['multi']):
parent = id
if c['_pr'] > 0:
parent = c['inherit']
c = self.sets[parent]['characters'][num]
if c.get('multi'):
self.__deduce_character_id(parent, num)
m += c['id']
char['id'] = m
def list(self):
""" Get the list of sets. """
l = list(self.sets.keys())
l.remove(self.default_set)
return [self.default_set] + l
def get(self, id = None):
""" Get a set. """
if type(id) != str:
id = self.default_set
st = self.sets[id]
st['id'] = id
return st
# End of file.

26
fontcharacter/tools/listsets.py Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env python3
""" Utility to list the available sets.
Mainly there for the Makefile to use it. """
import os
from argparse import ArgumentParser
from fontcharacter import Reference
# ---
# Main function.
# ---
if __name__ == '__main__':
# Parse the arguments.
ap = ArgumentParser(description="FONTCHARACTER reference sets lister")
ap.add_argument('--refpath', help='The reference path.', default=os.getcwd())
args = ap.parse_args()
# Obtain the reference.
ref = Reference(args.refpath, True)
# List the sets.
print('\n'.join(ref.list()))
# End of file.

183
fontcharacter/tools/makebin.py Executable file
View File

@ -0,0 +1,183 @@
#!/usr/bin/env python3
""" Utility to make the set binary files. """
import os, shutil
from argparse import ArgumentParser
from fontcharacter import Reference
# ---
# Function for encoding.
# ---
def tobytes(num, length):
return num.to_bytes(length, byteorder='big', signed=False)
def charbytes(char):
return tobytes(char, 2) if char > 0xFF else tobytes(char, 1)
def make_pool(pool):
# TODO: make this function optimize space, some day?
bdata = b''
offsets = []
for data in pool:
offsets += [len(bdata)]
bdata += bytes(data)
return bdata, offsets
def encode_set(ref, fset):
global args
bheader = bytes()
blead = bytes()
bchars = bytes()
bdata = bytes()
# Prepare characters data
leading = {}
char_count = 0
dchars = []
pool = []
for char_id, (code, char) in enumerate(fset['characters'].items()):
char_count = char_id + 1
# Check if we should inherit.
if char['_pr'] > 0:
char = ref.get(char['inherit'])['characters'][code]
# Check the leader.
lead = code >> 8
if not lead in leading:
leading[lead] = char_id
# Get the multi size, feed the pool if needed.
mul_sz = 0
if char.get('multi') and char['multi']:
mul = b''.join(map(charbytes, char['multi']))
pool += [mul]
mul_sz = len(mul)
# Get the unicode size, feed the pool if needed.
uni_sz = 0
if not args.no_unicode and char.get('unicode') and char['unicode']:
uni = ''.join(map(chr, char['unicode'])).encode('utf-8')
pool += [uni]
uni_sz = len(uni)
# Get the CAT token size, feed the pool if needed.
cat_sz = 0
# Get the Newcat token size
newcat_sz = 0
# Get the CTF token size
ctf_sz = 0
# Get the Casemul token size
casemul_sz = 0
# Add all of these elements to the chars data tab.
dchars += [{
'code': code,
'mul_sz': mul_sz,
'uni_sz': uni_sz,
'cat_sz': cat_sz,
'newcat_sz': newcat_sz,
'ctf_sz': ctf_sz,
'casemul_sz': casemul_sz
}]
# Make the pool.
bdata, offsets = make_pool(pool)
# Prepare pool.
offsets = iter(offsets)
for char in dchars:
ent = tobytes(char['code'], 2) + tobytes(char['mul_sz'], 1) \
+ tobytes(char['uni_sz'], 1) + tobytes(char['cat_sz'], 1) \
+ tobytes(char['newcat_sz'], 1) + tobytes(char['ctf_sz'], 1) \
+ tobytes(char['casemul_sz'], 1)
# Offsets
ent += tobytes(next(offsets) if char['mul_sz'] > 0 else 0, 4)
if not args.no_unicode:
ent += tobytes(next(offsets) if char['uni_sz'] > 0 else 0, 4)
if not args.no_cat:
ent += tobytes(next(offsets) if char['cat_sz'] > 0 else 0, 4)
if not args.no_newcat:
ent += tobytes(next(offsets) if char['newcat_sz'] > 0 else 0, 4)
if not args.no_ctf:
ent += tobytes(next(offsets) if char['ctf_sz'] > 0 else 0, 4)
if not args.no_casemul:
ent += tobytes(next(offsets) if char['casemul_sz'] > 0 else 0, 4)
bchars += ent
# Correct the leading.
for lead in fset['leading']:
if not lead in leading:
leading[lead] = char_count
# Make the leading tab.
for lead, off in leading.items():
ent = bytes([lead, 0]) + tobytes(off, 2)
blead += bytes(ent)
# Make the flags.
flags = 0x1F
if args.no_unicode: flags &= ~0x01
if args.no_cat: flags &= ~0x02
if args.no_newcat: flags &= ~0x04
if args.no_ctf: flags &= ~0x08
if args.no_casemul: flags &= ~0x10
# Make the checksum.
csum = (sum(blead) + sum(bchars) + sum(bdata)) & 0xFFFFFFFF
# Make the lengths.
datalen = len(bdata)
filesize = 32 + len(blead) + len(bchars) + datalen
# Finish making the main header.
bheader = bytes(list(map(ord, "CASIOFC\x7F")) + [0x01]) \
+ tobytes(len(leading), 1) + tobytes(char_count, 2) \
+ tobytes(flags, 1) + tobytes(0, 1) + tobytes(0, 2) + tobytes(0, 4) \
+ tobytes(csum, 4) + tobytes(filesize, 4) + tobytes(datalen, 4)
return bheader + blead + bchars + bdata
# ---
# Main function.
# ---
if __name__ == '__main__':
ap = ArgumentParser(description="FONTCHARACTER reference binary generator")
ap.add_argument('--no-unicode', help='No Unicode equivalents?',
action="store_true")
ap.add_argument('--no-cat', help='No CAT tokens?', action="store_true")
ap.add_argument('--no-newcat', help='No Newcat tokens?',
action="store_true")
ap.add_argument('--no-ctf', help='No CTF tokens?', action="store_true")
ap.add_argument('--no-casemul', help="No Casemul tokens?",
action="store_true")
ap.add_argument('--output', '-o', help='The output directory path.',
default=os.path.join(os.getcwd(), 'generated_sets'))
ap.add_argument('--refpath', help='The reference path.',
default=os.getcwd())
args = ap.parse_args()
# Obtain the reference.
ref = Reference(args.refpath)
# Make the directory.
if os.path.isdir(args.output):
shutil.rmtree(args.output)
elif os.path.exists(args.output):
os.remove(args.output)
os.makedirs(args.output)
# For each set, make the file.
for set_name, set_val in map(lambda x: (x, ref.get(x)), ref.list()):
with open(os.path.join(args.output, set_name + '.set'), 'wb') as f:
f.write(encode_set(ref, set_val))
# End of file.