ZCI

From Just Solve the File Format Problem
(Difference between revisions)
Jump to: navigation, search
(Created page with "{{FormatInfo |formattype=electronic |subcat=Video |extensions={{ext|zci}} |released=≤1994 }} '''.ZCI''' is a multimedia-related aggregate format that was mainly used on educ...")
 
(Partial file spec)
Line 9: Line 9:
 
''[More research is needed to understand the nature of this format.]''
 
''[More research is needed to understand the nature of this format.]''
  
== Identification ==
+
== Specification ==
Files are observed to start wih ASCII "{{magic|CRRW}}".
+
 
 +
A partial specification of the format is below:
 +
 
 +
The format contains three sections
 +
 
 +
* Files are start with ASCII "{{magic|CRRW}}".
 +
* Version? (<code>unsigned int</code>)
 +
* Table of contents offset (<code>unsigned int</code>)
 +
* File count (<code>unsigned int</code>)
 +
 
 +
The purpose of the bytes between 16-2096 is unknown. It appears to include file offsets references, but often skip files or contains sequences low values (i.e. 0, 1, 2, 3).
 +
 
 +
The '''Table of contents''' appears at the end of the file and has entries in the format:
 +
 
 +
* File name (8.3 format, null encoded)
 +
* ''unk1'' (<code>unsigned int</code>)
 +
* Offset (<code>unsigned int</code>)
 +
 
 +
Each entry's offset refers to another structure within the file with the following format:
 +
 
 +
* File name (8.3 format, null encoded)
 +
* ''unk2'' (<code>unsigned int</code>)
 +
* ''unk3'' (<code>unsigned int</code>)
 +
* File size (<code>unsigned int</code>)
 +
* ''unk4'' (<code>unsigned int</code>)
 +
* ''unk5'' (<code>unsigned int</code>)
 +
 
 +
Entry data appears to be in a custom format (as noted by the extension not matching the data). Assumed the entries are compressed. Entries often being with the magic bytes <code>CRCW</code>.
 +
 
 +
== Extract ==
 +
 
 +
The following Python source can be used to partially inspect and extract files within a <code>.zci</code> file:
 +
 
 +
<pre>
 +
import struct
 +
import os
 +
 
 +
header_format = '<4sIII'
 +
header_format_size = struct.calcsize(header_format)
 +
 
 +
entry_format = '<13sII'
 +
entry_format_size = struct.calcsize(entry_format)
 +
 
 +
file_data_format = '<13sbIIII'
 +
file_data_format_size = struct.calcsize(file_data_format)
 +
 
 +
with open('PRESBASE.ZCI', 'rb') as f:
 +
[magic_bytes, version, table_offset, file_count] = struct.unpack(header_format, f.read(header_format_size))
 +
 +
print("Magic bytes: {}".format(magic_bytes))
 +
print("Version: {}".format(version))
 +
print("Table offset: {}".format(table_offset))
 +
print("File count: {}".format(file_count))
 +
 +
assert magic_bytes == b'CRRW'
 +
assert version == 2
 +
assert table_offset > 0
 +
assert file_count > 0
 +
 
 +
entries = {}
 +
f.seek(table_offset)
 +
 
 +
for _ in range(file_count):
 +
[file_name_bytes, unk1, offset] = struct.unpack(entry_format, f.read(entry_format_size))
 +
file_name = file_name_bytes.decode('ascii').rstrip('\x00')
 +
 
 +
entries[file_name] = {
 +
'file_name': file_name,
 +
'unk1': unk1,
 +
'offset': offset,
 +
}
 +
 +
for key, entry in entries.items():
 +
f.seek(entry['offset'])
 +
[file_name_bytes, unk2, unk3, file_size, unk4, unk5] = struct.unpack(file_data_format, f.read(file_data_format_size))
 +
file_name = file_name_bytes.decode('ascii').rstrip('\x00')
 +
assert file_name == entry['file_name']
 +
 
 +
file_data = f.read(file_size)
 +
 +
entries[key].update({
 +
'unk2': unk2,
 +
'unk3': unk3,
 +
'unk4': unk4,
 +
'unk5': unk5,
 +
'file_size': file_size,
 +
'file_data': file_data,
 +
})
 +
 
 +
for key, entry in entries.items():
 +
with open(os.path.join('output', key), 'wb+') as f:
 +
f.write(entry['file_data'])
 +
</pre>
  
 
== Sample files ==
 
== Sample files ==

Revision as of 17:07, 3 January 2023

File Format
Name ZCI
Ontology
Extension(s) .zci
Released ≤1994

.ZCI is a multimedia-related aggregate format that was mainly used on educational CD-ROMs by Zane Publishing. It is sometimes called PowerCD Multimedia format.

[More research is needed to understand the nature of this format.]

Contents

Specification

A partial specification of the format is below:

The format contains three sections

  • Files are start with ASCII "CRRW".
  • Version? (unsigned int)
  • Table of contents offset (unsigned int)
  • File count (unsigned int)

The purpose of the bytes between 16-2096 is unknown. It appears to include file offsets references, but often skip files or contains sequences low values (i.e. 0, 1, 2, 3).

The Table of contents appears at the end of the file and has entries in the format:

  • File name (8.3 format, null encoded)
  • unk1 (unsigned int)
  • Offset (unsigned int)

Each entry's offset refers to another structure within the file with the following format:

  • File name (8.3 format, null encoded)
  • unk2 (unsigned int)
  • unk3 (unsigned int)
  • File size (unsigned int)
  • unk4 (unsigned int)
  • unk5 (unsigned int)

Entry data appears to be in a custom format (as noted by the extension not matching the data). Assumed the entries are compressed. Entries often being with the magic bytes CRCW.

Extract

The following Python source can be used to partially inspect and extract files within a .zci file:

import struct
import os

header_format = '<4sIII'
header_format_size = struct.calcsize(header_format)

entry_format = '<13sII'
entry_format_size = struct.calcsize(entry_format)

file_data_format = '<13sbIIII'
file_data_format_size = struct.calcsize(file_data_format)

with open('PRESBASE.ZCI', 'rb') as f:
	[magic_bytes, version, table_offset, file_count] = struct.unpack(header_format, f.read(header_format_size))
	
	print("Magic bytes: {}".format(magic_bytes))
	print("Version: {}".format(version))
	print("Table offset: {}".format(table_offset))
	print("File count: {}".format(file_count))
	
	assert magic_bytes == b'CRRW'
	assert version == 2
	assert table_offset > 0
	assert file_count > 0

	entries = {}
	f.seek(table_offset)

	for _ in range(file_count):
		[file_name_bytes, unk1, offset] = struct.unpack(entry_format, f.read(entry_format_size))
		file_name = file_name_bytes.decode('ascii').rstrip('\x00')

		entries[file_name] = {
			'file_name': file_name,
			'unk1': unk1,
			'offset': offset,
		}
	
	for key, entry in entries.items():
		f.seek(entry['offset'])
		[file_name_bytes, unk2, unk3, file_size, unk4, unk5] = struct.unpack(file_data_format, f.read(file_data_format_size))
		file_name = file_name_bytes.decode('ascii').rstrip('\x00')
		assert file_name == entry['file_name']

		file_data = f.read(file_size)
		
		entries[key].update({
			'unk2': unk2,
			'unk3': unk3,
			'unk4': unk4,
			'unk5': unk5,
			'file_size': file_size,
			'file_data': file_data,
		})

	for key, entry in entries.items():
		with open(os.path.join('output', key), 'wb+') as f:
			f.write(entry['file_data'])

Sample files

  • Examples of CDs containing ZCI files: [1], [2], [3]

Links

Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox