Fxi is the format used by the popular software Fx-Interface, very used in Europe. Fxi is a binary format, and can contain any kind of data excepted backups. Fxi files are ended by .fxi

This format is very complex, its access is done in two step.

Read a fxi file

First step: decoding the file

We must first convert each byte of the fxi file by its equivalent in the raw format. A tutorial of Alexis Soulard, le format FXI (in french), explain the ugly algorithm to build an equivalence table (thank you very much Alexis!). Here is the algorithm of Alexis in php:

<table border="1" width="120" cellpadding="2">
<tr>
<td width="50%" align="center" bgcolor="#F0F0F0"><b>ASCII</b></td>
<td width="50%" align="center" bgcolor="#F0F0F0"><b>FXI</b></td>
</tr>
<?php
//au début l'équivalence 255 (DEC) est 24 en FXI
$num = 24;
//chaine maximale de nombres qui se suivent
$chaineMaxi = 8;
//nombre de cycle à suivre avant changements
$nbMaxiCycles = 4;
 
$compteNum = 1;
$nbCycle = 1;
$numDebCycle = $num;
$chaineAllValues = ""; $chaineAllValues2 = "";
for ($i=255; $i>=0; $i--){
    echo "<tr>n";
 
    echo "<td width="50%" align="right" bgcolor="#F0F0F0"><b>".$i."</b></td>n";
    echo "<td width="50%" align="right">".$num."</td>n";
 
    $chaineAllValues .= $i."=>".$num.",";
    $chaineAllValues2 .= $num."=>".$i.",";
 
    $num++;
    $compteNum++;
 
    if ($compteNum > $chaineMaxi){
        $compteNum = 1;
        $num -= $chaineMaxi * 2;
        $nbCycle++;
    }
 
    if ($nbCycle > $nbMaxiCycles){
        $num = $numDebCycle + $chaineMaxi * $nbMaxiCycles;
        $numDebCycle = $num;
        $nbCycle = 1;
    }
 
    echo "</tr>n";
}
?>
</table>
 
<?php
echo "<br><br>$tabFxiDec = array(";
echo $chaineAllValues;
echo ");";
 
echo "<br><br>$tabDecFxi = array(";
echo $chaineAllValues2;
echo ");";
?>

And here is the same algorithm in python:

#Build the raw2fxi dic
#Thanks to http://www.casioland.net/tutoriaux.php?idTuto=3&noHeader=1
r2f = {}
dep, a, i, j = 23, 255, 0, 0
v = dep
while a >= 0 :
    v = v + 1
    r2f[a] = v
    a -= 1
    i += 1
    if i == 8 :
        dep -= 8
        j += 1
        i = 0
        v = dep
    if j == 4 :
        j = 0
        dep += 8 * 8
        v = dep
 
#Build the fxi2raw dic
f2r = {}
for a, f in r2f.items():
    f2r[f] = a
 
# Function to convert fxi data in raw data:
 
def fxiDecode(fxiData):
    """ Convert fxi-like data to raw data """
    out = ''
    for c in range(len(fxiData)) :
        out += chr(f2r[ord(fxiData[c])])
    return out

Second step: read records

As many formats, the fxi formats can contain many record in a single file, and some metadata.

Program record

The more easier way to extract programs from a fxi file is to use a regular expression (here in python with the re module, and using the fxi_decode function from the last example):

fxi_file = open(filename, 'r')
# Get the raw data
ctn = fxi_decode(fxi_file.read())
fxi_file.close()
# Make the regular expression
data_pattern = re.compile('''
(TXT)           # data format (but fxi txt is not really text :-/)
.               # separator
(PG)            # type of data
.{4}            # 4 characters
([^\xff]{1,8})  # data name
\xff{16,23}     # between 16 and 23 (16+8-len(data name)) 0xFF
(NL|BN)         # Option1 (Normal or Base)
\xff{12}        # 12 0xFF
([^\xff]+\xff)  # any non 0xFF characters ended by one 0xFF : raw data
''', re.VERBOSE)
# Extract records from raw data using the regular expression
data_list = data_pattern.findall(ctn)
for record in data_list:
    format, data_type, name, optn, data = record
    # You can use data_type to know the record type, name for the program name.
    # optn == "BN" for a base program, optn == "NL" instead, and data contain
    # raw data of the program.

Picture record

The more easier way to extract pictures from a fxi file is to use a regular expression (here in python with the re module, and using the fxi_decode function from the last example):

fxi_file = open(filename, 'r')
# Get the raw data
ctn = fxi_decode(fxi_file.read())
fxi_file.close()
# Make the regular expression
pict_pattern = re.compile('''
        (IMG)           # data format
        .               # separator
        (PC)            # type of data
        .{4}            # 4 characters
        ([^\xff]+)      # data name (old:([^\xff]{1,8}))
        \xff{1,23}      # between 8 and 23 (16+8-len(data name)) 0xFF (o:{16,23})
        (DRUWF)         # Sens of reading
        .{4}            # 4 bytes
        \xff{13}        # Separator
        (.{4112})       # (( sheet of 16 * 64 byte ) + 4 header byte) 
                        #* 4 colors
        ''', re.VERBOSE)
# Extract records from raw data using the regular expression
data_list = pict_pattern.findall(ctn)
for record in data_list:
    format, data_type, name, optn, data = record
    # You can use data_type to know the record type, name for the picture name.
    # data contain raw data of the picture.

The picture raw data is in the casio picture format, with the pallet [orange, blue, green, white], the colour byte is 3.

Write a fxi file

First step: write records

A fxi file begin by a file header, followed by data records.

File header

The file header is composed as follow, with static data. Here it's done as python code, strings like \x2a mean a byte with the hexadecimal value 2a.

file_header = '\xd5\xd7\x1fFX-INTERFACE - YELLOW COMPUTING'
file_header += '\x00'*40 + '\x06' + '\x00'*81 + '\x07\x00'
file_header += '\xff'*2 + '\x00'*2 + '\x0f\x00CYCFXListItemNP' + '\x00'*8
file_header += '\x03\x00\x15\x18' + '\x00'*5 + '\x4a\xa0' + '\x00'*76
file_header += '\x01\x80\x00\x00\x01' + '\x00'*3 + '\x01\x00\x03\x00\x55\x1a'
file_header += '\x00'*2 + '\x04' + '\x00'*2 + '\x5b\x80' + '\x00'*76 + '\x01\x80'
file_header += '\x00'*2 + '\x02' + '\x00'*3 + '\x02' + '\x00'*3 + '\x08\x13'
file_header += '\x00'*2 + '\x22\x00\x00\x83\x80' + '\x00'*76 + '\x01\x80'
file_header += '\x00'*2 + '\x03' + '\x00'*3 + '\x01\x00\x03\x00\x55\x1a\x00\x00'
file_header += '\x20' + '\x00'*2 + '\x1f\x81' + '\x00'*76 + '\x01\x80' + '\x00'*2
file_header += '\x04' + '\x00'*3 + '\x02' + '\x00'*3 + '\x08\x13' + '\x00'*2
file_header += '\x21' + '\x00'*2 + '\x83\x80' + '\x00'*76 + '\x01\x80' + '\x00'*2
file_header += '\x05' + '\x00'*5 + '\x02\x00\x58\x10' + '\x00'*2 + '\x1e'
file_header += '\x00'*2 + '\xcc\x80' + '\x00'*76 + '\x01\x80' + '\x00'*2 + '\x06'
file_header += '\x00'*3 + '\x01' + '\x00'*3 + '\x08\x11' + '\x00'*2 + '\x1e'
file_header += '\x00'*2 + '\x83\x80' + '\x00'*76

After this header, the file is sorted by data type block, in the right order: first the program block, next the picture block.

Program block

If there is no program to save, and no data in a next block, the program block is empty. Else, if there is no program to save, but a non empty block after, the program block is '\x00\x00'.

If the program block is not empty, it begin by two byte: the first has for value the number of program records, and the second is null ('\x00'). After this two byte, each program is in one record.

Program record

A program record is composed by a record header, and the program itself. The record is composed as:

  1. “\x01\x80” followed by 6 “\x00” bytes
  2. “\x02\x00\x01\x00\xba\x1e\x00\x00\x22\x00”
  3. 1 byte: the length of the program name (in raw format)
  4. The program name (length undetermined)
  5. “\x83\x80”
  6. 42 “\x00” bytes
  7. The program name
  8. (8 - length of program name) “\xff” (or sometimes “\x00”, but “\xff” always work - this complete the program name to have a constant length)
  9. 24 “\x00” bytes
  10. “\x01\x00\x01\x00”
  11. 2 bytes: the length of the program (in raw format, with the end byte) + 48. Bytes are inversed (by example, if the length is (in hexadecimal) 0x0123, bytes are \x23 \x01).
  12. “TXT” (type of data)
  13. “\x00”
  14. “PG” (program record)
  15. 4 bytes: the length of the program (in raw format, with the end byte) + 2. Bytes are in the right order.
  16. The program name
  17. (8 - length of program name) “\xff” (this complete the program name to have a constant length)
  18. 16 “\xff” bytes
  19. 2 bytes: “BN” if the program use bases, “NL” else.
  20. 12 “\xff” bytes
  21. Program data (in raw format, ended with the “\xff” end byte

A fxi file made by Fx-Interface may also contain at the end of the record, inside some “\xff” bytes, some data you have deleted from your program. Saved deleted data in the file is fully optional, if you want write a fxi file, you can forgot this.

Warning: if the first program length must be coded on more than 2 bytes, the organization of the record change. This is not documented for the moment.

Picture block

If there is no picture to save, the picture block is empty.

If the picture block is not empty, it begin by:

  1. “\x00\x00\x00\x00”
  2. 1 byte: the number of picture records
  3. “\x00”

Picture record

A picture record is composed by a record header, and the picture itself. The record is composed as:

  1. “\x01\x80” followed by 6 “\x00” bytes
  2. “\x02\x00\x01\x00\x3a\x1c\x00\x00\x21\x00”
  3. 1 byte: the length of the picture name (in raw format)
  4. The picture name (length undetermined)
  5. “\x83\x80”
  6. 42 “\x00” bytes
  7. The picture name
  8. (8 - length of picture name) “\xff” (or sometimes “\x00”, but “\xff” always work - this complete the picture name to have a constant length)
  9. 24 “\x00” bytes
  10. “\x01\x00\x01\x00”
  11. “\x40\x10” (more or less the length of the picture)
  12. “IMG” (type of data)
  13. “\x00”
  14. “PC” (picture record)
  15. “\x00\x40\x00\x80” (more or less the length of the picture)
  16. The picture name
  17. (8 - length of program name) “\xff” (this complete the picture name to have a constant length)
  18. 8 “\xff” bytes
  19. “DRUWF”
  20. “\x00\x04\x00\x01”
  21. 13 “\xff” bytes
  22. The raw picture, in the casio picture format, with the pallet [orange, blue, green, white], a colour byte of 3, and for each sheet this sheet header: “\x00\x01\x00”

End of file

The file is ended by 6 or7 “\x00” bytes.

Second step: encode the file

Using the work of Alexis Soulard (see before), we just to the opposite. Here is a python function to encode in fxi format:

# Build the raw2fxi dic
# Thanks to http://www.casioland.net/tutoriaux.php?idTuto=3&noHeader=1
r2f = {}
dep, chrNumber, fxi_index, fxi_index2 = 23, 255, 0, 0
chr_value = dep
while chrNumber >= 0:
    chr_value = chr_value + 1
    r2f[chrNumber] = chr_value
    chrNumber -= 1
    fxi_index += 1
    if fxi_index == 8:
        dep -= 8
        fxi_index2 += 1
        fxi_index = 0
        chr_value = dep
    if fxi_index2 == 4:
        fxi_index2 = 0
        dep += 8 * 8
        chr_value = dep
 
# Encode function
def fxi_encode(raw_data):
    """Convert raw data to fxi-like data"""
    out = ''
    for car in range(len(raw_data)):
        out += chr(r2f[ord(raw_data[car])])
    return out
 
# If your file content is in the string variable 'content', you can save your file by:
myfile = open('path/to/my.fxi', 'w')
myfile.write(fxi_encode(content))
myfile.close()
 

Powered by PHP Valid XHTML 1.0 strict Valid CSS Driven by DokuWiki

The content of this website is, without another mention, under the GNU Free Documentation License.