Fwd: Sample code: stored deflate blocks

Cosmin Truta <[email protected]>
Newsgroups gmane.comp.graphics.png.general
Message-ID <CAAoVtZxLTBgp1WOzbE6mr_F9sxr4ESSe1kTzDEWd9niVjASOSw@mail.gmail.com>
Hi,

Regardless whether the eXIf specification ends up with or without
deflate encoding, I wrote some sample code that can be used to store a
metadata block in uncompressed form. For example, this code can be
used for iCCP, as well as any future chunk data that is not required
to be compressed.

This code (or a variation of it) may go in a non-normative Annex in a
future version of the PNG spec.

The code was written to be as simple to use as possible. The user
application requires one macro calculation (to get the encoded stream
size) and one function call (to store the encoded stream in a memory
block). The function is secured in a manner similar to snprintf.

I tested this code only briefly, encoding a small buffer. It Worked For Me (tm).

***

/* Copyright (C) 2017 Cosmin Truta. */
/* This software is distributed under the zlib license. */

#define ZSTORE_STREAM_SIZE(raw_size) \
    ( \
     /* magic header size */ 2 + \
     /* leading blocks */ (raw_size / 0xffffU) * (5 + 0xffffU) + \
     /* trailing block */ (raw_size % 0xffffU + 5) + \
     /* Adler-32 checksum */ 4 \
    )

size_t zstore(void *out_zbuf,
              size_t out_zbuf_size,
              const void *in_buf,
              size_t in_buf_size)
{
    size_t result = ZSTORE_STREAM_SIZE(in_buf_size);
    if (out_zbuf_size >= result)
    {
        /* Initialize the magic constants. See RFC-1950. */
        const char cmf = '\x08';
        const char flg = '\x1d';
        /* Initialize the stored block headers. See RFC-1951. */
        static const char leading_block_header[5] =
            { '\x00', '\xff', '\xff', '\x00', '\x00' };
        /* Initialize the trailing Adler-32 checksum. See RFC-1950. */
        unsigned long checksum = adler32(1L, in_buf, in_buf_size);
        /* Initialize the in/out pointers. */
        char *out_ptr = (char *)out_zbuf;
        const char *in_ptr = (const char *)in_buf;
        size_t in_remainder = in_buf_size;
        /* Write the deflate header. */
        *out_ptr++ = cmf;
        *out_ptr++ = flg;
        /* Write the leading blocks, if any. */
        while (in_remainder > 0xffffU)
        {
            memcpy(out_ptr, leading_block_header, 5);
            memcpy(out_ptr + 5, in_ptr, 0xffffU);
            out_ptr += 5 + 0xffffU;
            in_ptr += 0xffffU;
            in_remainder -= 0xffffU;
        }
        /* Write the trailing block. */
        out_ptr[0] = '\x01';
        out_ptr[1] = (char)(in_remainder & 0xffU);
        out_ptr[2] = (char)((in_remainder >> 8) & 0xffU);
        out_ptr[3] = (char)(~out_ptr[1] & 0xffU);
        out_ptr[4] = (char)(~out_ptr[2] & 0xffU);
        memcpy(out_ptr + 5, in_ptr, in_remainder);
        out_ptr += 5 + in_remainder;
        /* Write the Adler32 checksum. */
        out_ptr[0] = (char)((checksum >> 24) & 0xffU);
        out_ptr[1] = (char)((checksum >> 16) & 0xffU);
        out_ptr[2] = (char)((checksum >> 8) & 0xffU);
        out_ptr[3] = (char)(checksum & 0xffU);
    }
    return result;
}

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.