# Differences

This shows you the differences between two versions of the page.

formats:fxi [2010/05/28 22:53]
188.180.67.207 WsBeAcunmHTtudIv
formats:fxi [2010/06/16 11:08] (current)
thesa old revision restored
Line 1: Line 1:
+Fxi is the format used by the popular software [[http://www.fx-interface.de/products/fxi/f_fxi_info.html|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, [[http://www.casioland.net/tutoriaux.php?idTuto=3&noHeader=1|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:
+
+<code php>
+<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 ");";
+?>
+</code>
+
+And here is the same algorithm in python:
+
+<code python>
+#Build the raw2fxi dic
+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
+</code>
+
+===== 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):
+
+<code python>
+fxi_file = open(filename, 'r')
+# Get the raw data
+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.
+</code>
+
+==== 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):
+
+<code python>
+fxi_file = open(filename, 'r')
+# Get the raw data
+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.
+</code>
+
+The picture raw data is in the [[raw#pictures|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.
+
+
+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.
+
+<code python>
+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
+</code>
+
+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:
+  - "\x01\x80" followed by 6 "\x00" bytes
+  - "\x02\x00\x01\x00\xba\x1e\x00\x00\x22\x00"
+  - 1 byte: the length of the program name (in raw format)
+  - The program name (length undetermined)
+  - "\x83\x80"
+  - 42 "\x00" bytes
+  - The program name
+  - (8 - length of program name) "\xff" (or sometimes "\x00", but "\xff" always work - this complete the program name to have a constant length)
+  - 24 "\x00" bytes
+  - "\x01\x00\x01\x00"
+  - 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).
+  - "TXT" (type of data)
+  - "\x00"
+  - "PG" (program record)
+  - 4 bytes: the length of the program (in raw format, with the end byte) + 2. Bytes are in the right order.
+  - The program name
+  - (8 - length of program name) "\xff" (this complete the program name to have a constant length)
+  - 16 "\xff" bytes
+  - 2 bytes: "BN" if the program use bases, "NL" else.
+  - 12 "\xff" bytes
+  - 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:
+  - "\x00\x00\x00\x00"
+  - 1 byte: the number of picture records
+  - "\x00"
+
+=== Picture record ===
+
+A picture record is composed by a record header, and the picture itself. The record is composed as:
+  - "\x01\x80" followed by 6 "\x00" bytes
+  - "\x02\x00\x01\x00\x3a\x1c\x00\x00\x21\x00"
+  - 1 byte: the length of the picture name (in raw format)
+  - The picture name (length undetermined)
+  - "\x83\x80"
+  - 42 "\x00" bytes
+  - The picture name
+  - (8 - length of picture name) "\xff" (or sometimes "\x00", but "\xff" always work - this complete the picture name to have a constant length)
+  - 24 "\x00" bytes
+  - "\x01\x00\x01\x00"
+  - "\x40\x10" (more or less the length of the picture)
+  - "IMG" (type of data)
+  - "\x00"
+  - "PC" (picture record)
+  - "\x00\x40\x00\x80" (more or less the length of the picture)
+  - The picture name
+  - (8 - length of program name) "\xff" (this complete the picture name to have a constant length)
+  - 8 "\xff" bytes
+  - "DRUWF"
+  - "\x00\x04\x00\x01"
+  - 13 "\xff" bytes
+  - The raw picture, in the [[raw#pictures|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:
+
+<code python>
+# Build the raw2fxi dic
+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()
+</code>

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