Personal tools

FreeArc/Standard API for compression libraries

From HaskellWiki

< FreeArc(Difference between revisions)
Jump to: navigation, search
m
Line 74: Line 74:
 
return CLS_OK;
 
return CLS_OK;
 
}
 
}
}
+
  +
default:
  +
return CLS_ERROR_NOT_IMPLEMENTED;
  +
}
  +
}
 
</pre-cpp>
 
</pre-cpp>
   
Line 111: Line 111:
 
ClsMain(CLS_INIT, cb, NULL);
 
ClsMain(CLS_INIT, cb, NULL);
 
int ret = ClsMain(CLS_COMPRESS, cb, NULL);
 
int ret = ClsMain(CLS_COMPRESS, cb, NULL);
}
+
ClsMain(CLS_DONE, cb, NULL);
  +
  +
return ret;
  +
}
 
</pre-cpp>
 
</pre-cpp>

Revision as of 15:47, 30 September 2008

Idea: at encode.ru forum
Download sources: [1]

Header:

// Operations
const int CLS_INIT         = 1;       // Called once on DLL load
const int CLS_DONE         = 2;       // Called once before DLL unload
const int CLS_COMPRESS     = 3;       // Requests to compress data using i/o via callbacks
const int CLS_DECOMPRESS   = 4;       // Requests to decompress data using i/o via callbacks

// Callbacks
const int CLS_READ         = 1000;    // Read data into buffer ptr:n. Use CLS_READ+i to read i'th stream. Retcode: <0 - error, 0 - EOF, >0 - amount of data read
const int CLS_WRITE        = 2000;    // Write data from buffer ptr:n. CLS_WRITE+i also works. Retcode: the same
const int CLS_MALLOC       = 1;       // Alloc n bytes and make *ptr point to this area
const int CLS_FREE         = 2;       // Free ptr previously allocated by CLS_MALLOC
const int CLS_PARAMETERS   = 3;       // Put ASCIIZ parameters string into buffer ptr:n
// INIT-stage callbacks
const int CLS_ID           = 4;       // Identify itself with unique ASCIIZ string at ptr (for example, "lzma.7zip.org")

// Error codes
const int CLS_OK                                  = 0;     // ALL RIGHT
const int CLS_ERROR_GENERAL                       = -1;    // Unclassified error
const int CLS_ERROR_NOT_IMPLEMENTED               = -2;    // Requested feature isn't supported
const int CLS_ERROR_NOT_ENOUGH_MEMORY             = -3;    // Memory allocation failed
const int CLS_ERROR_READ                          = -4;
const int CLS_ERROR_WRITE                         = -5;
const int CLS_ERROR_ONLY_DECOMPRESS               = -6;    // This DLL supports only decompression
const int CLS_ERROR_INVALID_COMPRESSOR            = -7;    // Invalid compression method parameters
const int CLS_ERROR_BAD_COMPRESSED_DATA           = -8;    // Data can't be decompressed
const int CLS_ERROR_NO_MORE_DATA_REQUIRED         = -9;    // Required part of data was already decompressed
const int CLS_ERROR_OUTBLOCK_TOO_SMALL            = -10;   // Output block size in (de)compressMem is not enough for all output data

// Type of callback passed to ClsMain
typedef int CLS_CALLBACK(void* instance, int op, void *ptr, int n);

/* to do:
- check versions and backward/forward compatibility
- allow multiple codecs in same dll. this may be solved by ClsMain2, ClsMain3... exported but this may be not enough for some more complex scenarios
- codecs need to know how much memory for compression / decompression are they supposed to use.
- some codecs might handle multithreading in a smarter way than splitting streams.
- Also there're threading issues (like, application allowing to use up to N
threads) and whether dll is thread-safe or not (if not, it can be secured
by loading multiple instances of dll - might be a useful feature as many
experimental compressors are not really incapsulated).
- Some interface methods are required for initialization and model flush
(which are not the same as there might be some precalculation required
only once).
- what about detectors and filters
- 
*/


Simplest codec:

#include "cls.h"

int ClsMain (int op, CLS_CALLBACK cb, void* instance)
{
    switch(op)
    {
    case CLS_COMPRESS:
    case CLS_DECOMPRESS:
        {   
            const int BUFSIZE = 4096;
            char buf[BUFSIZE];
            for (int len; (len=cb(instance, CLS_READ, buf, BUFSIZE)) != 0; )
            {
                if (len<0)  return len;  // Return errcode on error
                int ret = cb(instance, CLS_WRITE, buf, len);
                if (ret!=len)  return ret<0? ret : CLS_ERROR_WRITE;
            }
            return CLS_OK;
        }

    default:
        return CLS_ERROR_NOT_IMPLEMENTED;
    }
}


Minimal host:

#include <stdlib.h>
#include <io.h>

#include "cls.h"

int cb(void* instance, int op, void *ptr, int n)
{
    switch(op)
    {
    case CLS_READ:
        return read(0,ptr,n);
    case CLS_WRITE:
        return write(1,ptr,n);
    case CLS_MALLOC:
        *(void**)ptr = malloc(n);
        return *(void**)ptr? CLS_OK : CLS_ERROR_NOT_ENOUGH_MEMORY;
    case CLS_FREE:
        free(ptr);
        return CLS_OK;
    default:
        return CLS_ERROR_NOT_IMPLEMENTED;
    }
}

int main ()
{
    extern int ClsMain (int op, CLS_CALLBACK cb, void* instance);

    ClsMain(CLS_INIT, cb, NULL);
    int ret = ClsMain(CLS_COMPRESS, cb, NULL);
    ClsMain(CLS_DONE, cb, NULL);

    return ret;
}