2

I am trying to create a utility for generating palmdoc/mobipocket format ebook files, it is said that mobi uses LZ77 compression technique to compress their records, but I found that there is quite a deviation from standard LZ77, My main source of reference is Calibre ebook creator with C implementation for palmdoc

In this file, uncompress works well, but I have not been able to compress a mobi record identically similar either using other implementation or this (Calibre code doent decompress the same).

I found some differences like, (<-- my comments follow in code)

static Py_ssize_t <-- can replaced with size_t
cpalmdoc_do_compress(buffer *b, char *output) {
    Py_ssize_t i = 0, j, chunk_len, dist;
    unsigned int compound;
    Byte c, n;
    bool found;
    char *head;
    buffer temp; 
    head = output;
    temp.data = (Byte *)PyMem_Malloc(sizeof(Byte)*8); temp.len = 0;
    if (temp.data == NULL) return 0;
    while (i < b->len) {
        c = b->data[i];
        //do repeats
        if ( i > 10 && (b->len - i) > 10) { <-- ignores any match outside this range
            found = false;
            for (chunk_len = 10; chunk_len > 2; chunk_len--) {
                j = cpalmdoc_rfind(b->data, i, chunk_len);
                dist = i - j;
                if (j < i && dist <= 2047) { <-- 2048 window size instead of 4096
                    found = true;
                    compound = (unsigned int)((dist << 3) + chunk_len-3);
                    *(output++) = CHAR(0x80 + (compound >> 8 ));
                    *(output++) = CHAR(compound & 0xFF);
                    i += chunk_len;
                    break;
                }
            }
            if (found) continue;
        }

        //write single character
        i++;
        if (c == 32 && i < b->len) { <-- if space is encountered skip char & check for next sequence for match otherwise do this, due to this code had wrong result.
            n = b->data[i];
            if ( n >= 0x40 && n <= 0x7F) {
                *(output++) = CHAR(n^0x80); i++; continue;
            }
        }
        if (c == 0 || (c > 8 && c < 0x80))
            *(output++) = CHAR(c);
        else { // Write binary data <-- why binary data? LZ is for text encoding
            j = i;
            temp.data[0] = c; temp.len = 1;
            while (j < b->len && temp.len < 8) {
                c = b->data[j];
                if (c == 0 || (c > 8 && c < 0x80)) break;
                temp.data[temp.len++] = c; j++;
            }
            i += temp.len - 1;
            *(output++) = (char)temp.len;
            for (j=0; j < temp.len; j++) *(output++) = (char)temp.data[j];
        }
    }
    PyMem_Free(temp.data);
    return output - head;
}

is this implementation correct?

duckduckgo
  • 1,280
  • 1
  • 18
  • 32

1 Answers1

1

PalmDoc compression essentially is byte pair compression, i.e. a variant of LZ77

silpol
  • 347
  • 1
  • 10
  • 29