Task 357: .LL File Format
Task 357: .LL File Format
The .LL file format is the Preview Format used by the combit List & Label reporting tool. It is a proprietary format based on the Microsoft Compound File (OLE2) format, used to store report previews as graphics of printed pages. The full specifications are not publicly available, as it is a proprietary format developed by combit GmbH. However, known details are derived from file extension databases and official documentation.
- Based on available information, the following are the known properties intrinsic to the .LL file format (e.g., header signature, associated GUIDs/CLSID, typical sizes, and content description):
- Magic header/signature: Hex D0 CF 11 E0 A1 B1 1A E1 (OLE Compound Document identifier at offset 0).
- CLSID/GUID: 8008b000-dcc7-11d0-b183-0040e994b57c or 8008b001-dcc7-11d0-b183-0040e994b57c (stored at offset 0x30 in the header).
- Internal application names: cmll10.dll [10,30,0,0 (05-08-02 1117)], CM32L8.DLL [8,7,0,0 (01-08-21 1348)], cm32L8.dll [8,7,0,0 (01-08-21 1348)].
- Typical file size: 32 KB to 2 MB (up to 160 MB maximum).
- Common filename: preview.ll.
- Content description: Contains all printed pages as graphics for preview viewing (viewable with LLVIEW application).
- File extension: .LL (fixed).
- Format basis: Microsoft Compound File Binary Format (structured storage with streams and storages for report design and layout).
No public direct download links for .LL files were found during the search, as they are generated by the List & Label software and are not typically shared or hosted publicly for download. Users generally create them using the tool's preview printing feature.
Below is a standalone HTML file with embedded JavaScript for a simple Ghost (or any blog) embeddable widget. It allows drag-and-drop of a .LL file, reads it as binary, checks the magic header and CLSID, and dumps the known properties to the screen if it matches the format. Since the full specs are proprietary, parsing is limited to known header details; full decoding is not possible without proprietary knowledge.
- Below is a Python class that can open a .LL file, decode the known header and CLSID, read and print the properties. Since the format is proprietary, full decoding/reading/writing is not possible; the class checks the known details and prints them. For write, it creates a minimal stub file with the header and CLSID (not a full valid .LL, as specs are missing).
import struct
import os
class LLFile:
def __init__(self, filepath):
self.filepath = filepath
self.magic = b'\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1'
self.expected_clsids = [
b'\x00\xB0\x08\x80\xC7\xDC\xD0\x11\xB1\x83\x00\x40\xE9\x94\xB5\x7C',
b'\x01\xB0\x08\x80\xC7\xDC\xD0\x11\xB1\x83\x00\x40\xE9\x94\xB5\x7C'
]
self.properties = {
'internal_app_names': 'cmll10.dll [10,30,0,0 (05-08-02 1117)], CM32L8.DLL [8,7,0,0 (01-08-21 1348)], cm32L8.dll [8,7,0,0 (01-08-21 1348)]',
'typical_size': '32 KB - 2 MB (up to 160 MB)',
'common_filename': 'preview.ll',
'content_description': 'Contains printed pages as graphics for preview'
}
def read(self):
with open(self.filepath, 'rb') as f:
header = f.read(8)
if header != self.magic:
print('Not a valid .LL file (invalid magic header).')
return
f.seek(48)
clsid = f.read(16)
if clsid not in self.expected_clsids:
print('Not a matching .LL file CLSID.')
return
file_size = os.path.getsize(self.filepath)
print(f'Magic Header: {header.hex().upper()}')
print(f'CLSID/GUID: {clsid.hex().upper()}')
for key, value in self.properties.items():
print(f'{key.capitalize().replace("_", " ")}: {value}')
print(f'File Size: {file_size} bytes')
def write(self, output_path):
# Write minimal stub (header + CLSID + padding; not full format)
with open(output_path, 'wb') as f:
f.write(self.magic)
f.write(b'\x00' * 40) # Padding to CLSID offset
f.write(self.expected_clsids[0]) # Use first CLSID
f.write(b'\x00' * 100) # Arbitrary padding for minimal file
print(f'Minimal .LL stub written to {output_path}')
# Example usage
# ll = LLFile('example.ll')
# ll.read()
# ll.write('new.ll')
- Below is a Java class that can open a .LL file, decode the known header and CLSID, read and print the properties. Similar limitations as above for proprietary format.
import java.io.RandomAccessFile;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
public class LLFile {
private String filepath;
private byte[] magic = {(byte)0xD0, (byte)0xCF, 0x11, (byte)0xE0, (byte)0xA1, (byte)0xB1, 0x1A, (byte)0xE1};
private byte[][] expectedClsids = {
{(byte)0x00, (byte)0xB0, 0x08, (byte)0x80, (byte)0xC7, (byte)0xDC, (byte)0xD0, 0x11, (byte)0xB1, (byte)0x83, 0x00, 0x40, (byte)0xE9, (byte)0x94, (byte)0xB5, 0x7C},
{(byte)0x01, (byte)0xB0, 0x08, (byte)0x80, (byte)0xC7, (byte)0xDC, (byte)0xD0, 0x11, (byte)0xB1, (byte)0x83, 0x00, 0x40, (byte)0xE9, (byte)0x94, (byte)0xB5, 0x7C}
};
private String internalAppNames = "cmll10.dll [10,30,0,0 (05-08-02 1117)], CM32L8.DLL [8,7,0,0 (01-08-21 1348)], cm32L8.dll [8,7,0,0 (01-08-21 1348)]";
private String typicalSize = "32 KB - 2 MB (up to 160 MB)";
private String commonFilename = "preview.ll";
private String contentDescription = "Contains printed pages as graphics for preview";
public LLFile(String filepath) {
this.filepath = filepath;
}
public void read() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(filepath, "r")) {
byte[] header = new byte[8];
raf.read(header);
if (!ByteBuffer.wrap(header).equals(ByteBuffer.wrap(magic))) {
System.out.println("Not a valid .LL file (invalid magic header).");
return;
}
raf.seek(48);
byte[] clsid = new byte[16];
raf.read(clsid);
boolean match = false;
for (byte[] exp : expectedClsids) {
if (ByteBuffer.wrap(clsid).equals(ByteBuffer.wrap(exp))) {
match = true;
break;
}
}
if (!match) {
System.out.println("Not a matching .LL file CLSID.");
return;
}
long fileSize = new File(filepath).length();
System.out.println("Magic Header: " + bytesToHex(header));
System.out.println("CLSID/GUID: " + bytesToHex(clsid));
System.out.println("Internal App Names: " + internalAppNames);
System.out.println("Typical Size: " + typicalSize);
System.out.println("Common Filename: " + commonFilename);
System.out.println("Content Description: " + contentDescription);
System.out.println("File Size: " + fileSize + " bytes");
}
}
public void write(String outputPath) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(outputPath, "rw")) {
raf.write(magic);
raf.seek(48);
raf.write(expectedClsids[0]);
raf.setLength(512); // Minimal size stub
}
System.out.println("Minimal .LL stub written to " + outputPath);
}
private String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString().trim();
}
// Example usage
// public static void main(String[] args) throws IOException {
// LLFile ll = new LLFile("example.ll");
// ll.read();
// ll.write("new.ll");
// }
}
- Below is a JavaScript class that can open a .LL file (using Node.js fs module), decode the known header and CLSID, read and print the properties to console. Similar limitations.
const fs = require('fs');
class LLFile {
constructor(filepath) {
this.filepath = filepath;
this.magic = Buffer.from([0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1]);
this.expectedClsids = [
Buffer.from([0x00, 0xB0, 0x08, 0x80, 0xC7, 0xDC, 0xD0, 0x11, 0xB1, 0x83, 0x00, 0x40, 0xE9, 0x94, 0xB5, 0x7C]),
Buffer.from([0x01, 0xB0, 0x08, 0x80, 0xC7, 0xDC, 0xD0, 0x11, 0xB1, 0x83, 0x00, 0x40, 0xE9, 0x94, 0xB5, 0x7C])
];
this.properties = {
internalAppNames: 'cmll10.dll [10,30,0,0 (05-08-02 1117)], CM32L8.DLL [8,7,0,0 (01-08-21 1348)], cm32L8.dll [8,7,0,0 (01-08-21 1348)]',
typicalSize: '32 KB - 2 MB (up to 160 MB)',
commonFilename: 'preview.ll',
contentDescription: 'Contains printed pages as graphics for preview'
};
}
read() {
const data = fs.readFileSync(this.filepath);
const header = data.slice(0, 8);
if (!header.equals(this.magic)) {
console.log('Not a valid .LL file (invalid magic header).');
return;
}
const clsid = data.slice(48, 64);
const match = this.expectedClsids.some(exp => clsid.equals(exp));
if (!match) {
console.log('Not a matching .LL file CLSID.');
return;
}
const fileSize = fs.statSync(this.filepath).size;
console.log(`Magic Header: ${header.toString('hex').toUpperCase()}`);
console.log(`CLSID/GUID: ${clsid.toString('hex').toUpperCase()}`);
Object.entries(this.properties).forEach(([key, value]) => {
console.log(`${key.charAt(0).toUpperCase() + key.slice(1).replace(/([A-Z])/g, ' $1')}: ${value}`);
});
console.log(`File Size: ${fileSize} bytes`);
}
write(outputPath) {
const buffer = Buffer.alloc(512); // Minimal stub
this.magic.copy(buffer, 0);
this.expectedClsids[0].copy(buffer, 48);
fs.writeFileSync(outputPath, buffer);
console.log(`Minimal .LL stub written to ${outputPath}`);
}
}
// Example usage
// const ll = new LLFile('example.ll');
// ll.read();
// ll.write('new.ll');
- Below is a C "class" (using struct and functions, as C has no classes) that can open a .LL file, decode the known header and CLSID, read and print the properties to console. Similar limitations.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
typedef struct {
const char *filepath;
unsigned char magic[8];
unsigned char expected_clsids[2][16];
const char *internal_app_names;
const char *typical_size;
const char *common_filename;
const char *content_description;
} LLFile;
void llfile_init(LLFile *self, const char *filepath) {
self->filepath = filepath;
unsigned char m[] = {0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1};
memcpy(self->magic, m, 8);
unsigned char c1[] = {0x00, 0xB0, 0x08, 0x80, 0xC7, 0xDC, 0xD0, 0x11, 0xB1, 0x83, 0x00, 0x40, 0xE9, 0x94, 0xB5, 0x7C};
unsigned char c2[] = {0x01, 0xB0, 0x08, 0x80, 0xC7, 0xDC, 0xD0, 0x11, 0xB1, 0x83, 0x00, 0x40, 0xE9, 0x94, 0xB5, 0x7C};
memcpy(self->expected_clsids[0], c1, 16);
memcpy(self->expected_clsids[1], c2, 16);
self->internal_app_names = "cmll10.dll [10,30,0,0 (05-08-02 1117)], CM32L8.DLL [8,7,0,0 (01-08-21 1348)], cm32L8.dll [8,7,0,0 (01-08-21 1348)]";
self->typical_size = "32 KB - 2 MB (up to 160 MB)";
self->common_filename = "preview.ll";
self->content_description = "Contains printed pages as graphics for preview";
}
void llfile_read(LLFile *self) {
FILE *f = fopen(self->filepath, "rb");
if (!f) {
printf("Failed to open file.\n");
return;
}
unsigned char header[8];
fread(header, 1, 8, f);
if (memcmp(header, self->magic, 8) != 0) {
printf("Not a valid .LL file (invalid magic header).\n");
fclose(f);
return;
}
fseek(f, 48, SEEK_SET);
unsigned char clsid[16];
fread(clsid, 1, 16, f);
fclose(f);
int match = 0;
for (int i = 0; i < 2; i++) {
if (memcmp(clsid, self->expected_clsids[i], 16) == 0) {
match = 1;
break;
}
}
if (!match) {
printf("Not a matching .LL file CLSID.\n");
return;
}
struct stat st;
stat(self->filepath, &st);
printf("Magic Header: ");
for (int i = 0; i < 8; i++) printf("%02X ", header[i]);
printf("\n");
printf("CLSID/GUID: ");
for (int i = 0; i < 16; i++) printf("%02X ", clsid[i]);
printf("\n");
printf("Internal App Names: %s\n", self->internal_app_names);
printf("Typical Size: %s\n", self->typical_size);
printf("Common Filename: %s\n", self->common_filename);
printf("Content Description: %s\n", self->content_description);
printf("File Size: %ld bytes\n", st.st_size);
}
void llfile_write(LLFile *self, const char *output_path) {
FILE *f = fopen(output_path, "wb");
if (!f) {
printf("Failed to create file.\n");
return;
}
fwrite(self->magic, 1, 8, f);
fseek(f, 48, SEEK_SET);
fwrite(self->expected_clsids[0], 1, 16, f);
fseek(f, 512, SEEK_SET); // Minimal size
fclose(f);
printf("Minimal .LL stub written to %s\n", output_path);
}
// Example usage
// int main() {
// LLFile ll;
// llfile_init(&ll, "example.ll");
// llfile_read(&ll);
// llfile_write(&ll, "new.ll");
// return 0;
// }