ConvertLIT (openclit)
| Language | C |
|---|---|
| License | GPL-2.0-or-later |
| Repository | source zips on convertlit.com (clit18src.zip); Debian packaging at packages.debian.org/convlit |
| Documentation | clit man page, comments in lib/*.c |
| Depends on | nothing for the library (it includes its own LZX, DES and SHA-1 code); the clit tool also needs LibTomMath for DRM5 keys |
| Read / write | reads all LIT files; writes LIT only to re-seal (downgrade DRM) or inscribe an existing book |
ConvertLIT is the program that reverse-engineered the LIT format. It has two parts:
lib/, the “openclit” library: parses the LIT container, decompresses LZX sections, decrypts sealed DES sections, reads the manifest and turns the binary-encoded HTML back into text.clit18/, theclittool: “explodes” a LIT book into an OEB package directory (.opffile, HTML, CSS, images), or downgrades a DRM5 book to DRM1 when you supply your own keys.
The code dates from 2002-2004 and is stable: LIT hasn’t changed since. It’s not distributed as a shared library and has no installed headers. To use the library you add lib/*.c to your build, or, more practically, run clit as a separate process. The GPL applies to any program that links the library.
Installation#
The clit tool is packaged:
# Debian / Ubuntu
sudo apt install convlit
# macOS
brew install convertlit
To build from source, get clit18src.zip from convertlit.com:
unzip clit18src.zip
cd lib && make # builds the static library openclit.a
The clit18/Makefile builds the clit program and expects the LibTomMath sources in ../libtommath-0.30/; edit the paths to use a system LibTomMath (libtommath-dev) instead.
Basic usage: extract a LIT book#
# explode book.lit into an OEB package (note the trailing slash)
clit book.lit book/
# result: book/book.opf, book/*.htm, book/*.css, images
ls book/
Zip the folder or open book.opf in calibre to produce an EPUB. Add -d to keep all files in one directory instead of recreating the original subdirectories.
How to open a LIT file with the library#
The library reads through a callback you provide (readat) and reports errors through lit_error, which your program must define. This is how clit itself opens a file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "litlib.h"
/* the library calls this on errors; your program must define it */
void lit_error(int what, char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
}
/* the library calls this to read 'size' bytes at 'offset'; it frees the buffer */
static U8 *readat(void *v, U32 offset, int size) {
FILE *f = (FILE *)v;
U8 *mem = malloc(size);
if (!mem) return NULL;
if (fseek(f, offset, SEEK_SET) != 0 || fread(mem, 1, size, f) != (size_t)size) {
free(mem);
return NULL;
}
return mem;
}
int main(int argc, char **argv) {
if (argc < 2) return 1;
FILE *fh = fopen(argv[1], "rb");
if (!fh) return 1;
lit_file lit;
memset(&lit, 0, sizeof(lit));
lit.file_pointer = fh;
lit.readat = readat;
fseek(fh, 0, SEEK_END);
lit.filesize = ftell(fh);
int status = lit_read_from_file(&lit);
if (status && status != E_LIT_DRM_ERROR) {
lit_close(&lit);
fclose(fh);
return 1;
}
printf("DRM level: %d\n", lit.drmlevel);
lit_close(&lit);
fclose(fh);
return 0;
}
Build it against the library: cc -funsigned-char main.c -Ilib lib/openclit.a.
How to list the files in a LIT book#
lit_read_manifest returns the mapping from internal names to original file names and MIME types, in 4 groups (HTML in the spine, other HTML, CSS, images):
manifest_type manifest;
memset(&manifest, 0, sizeof(manifest));
if (lit_read_manifest(&lit, &manifest) == 0) {
for (int group = 0; group < NUM_MANIFEST_MAPS; group++) {
for (int i = 0; i < manifest.num_mappings[group]; i++) {
name_mapping *m = &manifest.mappings[group][i];
printf("%s -> %s (%s)\n", m->sInternal, m->sOriginal, m->sType);
}
}
lit_free_manifest(&manifest);
}
How to read one stored file#
lit_get_file decompresses (and decrypts) one internal file. Internal paths are /data/ plus the internal name from the manifest. Images and CSS come out as-is; HTML documents (/data/<name>/content) are still in LIT’s binary tag encoding, which clit18/explode.c converts back to HTML with lit_reconstitute_html:
U8 *data = NULL;
int size = 0;
/* m is a name_mapping from the manifest, e.g. an image */
char path[512];
snprintf(path, sizeof(path), "/data/%s", (char *)m->sInternal);
if (lit_get_file(&lit, path, &data, &size) == 0) {
FILE *out = fopen((char *)m->sOriginal, "wb");
fwrite(data, 1, size, out);
fclose(out);
free(data);
}
Tips#
- For DRM5 (owner-exclusive) books
clitneeds akeys.txtfile with your own private keys; without itlit_read_from_filereturnsE_LIT_DRM_ERROR. - The README in the zip says
cd ../clit16; the folder is actuallyclit18. - Compile with
-funsigned-char, like the original Makefile: the code assumescharis unsigned. - If you only need the content, running
clitor calibre’sebook-convertis simpler and keeps your program free of the GPL.