I am trying to made a generic "ClientCoder" on Linux.
'ClientCoder codec.so i' : displays name of the coder with 'getMethodProperty(NMethodPropID::kName)'
'ClientCoder codec.so e file1 file2' : encodes file1 into file2 (with default parameters for the coder)
To get the 'ICompressCoder' object, I use
getMethodProperty(0,NMethodPropID::kEncoder,&propVariant);
createObjectFunc((const GUID *)propVariant.bstrVal, &IID_ICompressCoder, (void **)&outCoder)
'ClientCoder codec.so d file2 file3' : decodes file2 into file3 (with default parameters for the coder)
To get the 'ICompressCoder' object, I use
getMethodProperty(0,NMethodPropID::kDecoder,&propVariant);
createObjectFunc((const GUID *)propVariant.bstrVal, &IID_ICompressCoder, (void **)&outCoder)
'file1' and 'file3' should have the same data.
This method seems to work for :
- Copy.so
- Deflate.so
- BZip2.so
This method does not work for :
- LZMA.so (the program crashes during the decoding)
- PPMD.so (the program crashes during the encoding !)
The LZMA decoding crashes because SetDecoderProperties2 was not called ?
Why does not the LZMA decoder use the same default parameters as the encoder ?
For PPMD.so, I have not try to debug ...
I don't understand the goal of the COM-like interface 'ICompressCoder' ?
This COM-like interface does not give the list of the encoder/decoder parameters ?
Is the COM-like interface not generic ?
Does the developper must know what kind of encoder/decoder he tries to handle ?
For example, how does he know if a decoder supports 'SetDecoderProperties2' ?
- Why does not the LZMA decoder use the same default parameters as the encoder?
I can change default properties. For example, default LZMA dictionary was 2 MB. Now default is 4 MB.
Encoding
--------
1)Try to get ICompressSetCoderProperties and call SetCoderProperties(...);
2) Try to get ICompressWriteCoderProperties
interface and call WriteCoderProperties(propsStream);
Step 1) is optional.
Write to stream:
1) Size of properties
2) Propereties
3) Uncompressed size for LZMA (if you don't use EOS marker).
4) Compressed Data
Decoding
--------
Try to get
ICompressSetDecoderProperties2.
If you can get it, call
SetDecoderProperties2(const Byte *data, UInt32 size);
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Igor Pavlov,
I am trying to made a generic "ClientCoder" on Linux.
'ClientCoder codec.so i' : displays name of the coder with 'getMethodProperty(NMethodPropID::kName)'
'ClientCoder codec.so e file1 file2' : encodes file1 into file2 (with default parameters for the coder)
To get the 'ICompressCoder' object, I use
getMethodProperty(0,NMethodPropID::kEncoder,&propVariant);
createObjectFunc((const GUID *)propVariant.bstrVal, &IID_ICompressCoder, (void **)&outCoder)
'ClientCoder codec.so d file2 file3' : decodes file2 into file3 (with default parameters for the coder)
To get the 'ICompressCoder' object, I use
getMethodProperty(0,NMethodPropID::kDecoder,&propVariant);
createObjectFunc((const GUID *)propVariant.bstrVal, &IID_ICompressCoder, (void **)&outCoder)
'file1' and 'file3' should have the same data.
This method seems to work for :
- Copy.so
- Deflate.so
- BZip2.so
This method does not work for :
- LZMA.so (the program crashes during the decoding)
- PPMD.so (the program crashes during the encoding !)
The LZMA decoding crashes because SetDecoderProperties2 was not called ?
Why does not the LZMA decoder use the same default parameters as the encoder ?
For PPMD.so, I have not try to debug ...
I don't understand the goal of the COM-like interface 'ICompressCoder' ?
This COM-like interface does not give the list of the encoder/decoder parameters ?
Is the COM-like interface not generic ?
Does the developper must know what kind of encoder/decoder he tries to handle ?
For example, how does he know if a decoder supports 'SetDecoderProperties2' ?
Here is the code :
// ClientCoder.cpp
#include "StdAfx.h"
#ifdef _WIN32
#include <initguid.h>
#else
#include "Common/MyInitGuid.h"
#endif
#include "Windows/DLL.h"
#include "../../ICoder.h"
#include "Windows/PropVariant.h"
#include "Common/MyCom.h"
using namespace NWindows;
class CFileIn : public ISequentialInStream, public CMyUnknownImp
{
FILE *file_;
public:
MY_UNKNOWN_IMP
CFileIn() : file_(0) { }
~CFileIn() { this->close(); }
HRESULT open(const char *name)
{
file_ = fopen(name,"rb");
if (file_) return S_OK;
return E_FAIL;
}
void close()
{
if (file_) fclose(file_);
file_ = 0;
}
HRESULT Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (file_)
{
size_t ret = fread (data, 1, size, file_);
*processedSize = ret;
// TBD : if ret == 0, test for feof/ferror
return S_OK;
}
return E_FAIL;
}
};
class CFileOut : public ISequentialOutStream, public CMyUnknownImp
{
FILE *file_;
public:
MY_UNKNOWN_IMP
CFileOut() : file_(0) { }
~CFileOut() { this->close(); }
HRESULT open(const char *name)
{
file_ = fopen(name,"wb");
if (file_) return S_OK;
return E_FAIL;
}
void close()
{
if (file_) fclose(file_);
file_ = 0;
}
HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize)
{
if (file_)
{
size_t ret = fwrite(data, 1, size, file_);
*processedSize = ret;
// TBD : if ret == 0, test for feof/ferror
return S_OK;
}
return E_FAIL;
}
};
//////////////////////////////////////////////////////////////////////////
// Main function
static const char *kHelpString =
"Usage: ClientCodec codec.so [c | d | i] [file_in file_out]\n"
"Examples:\n"
" ClientCodec LZMA.so i : info about the codec\n"
" ClientCodec LZMA.so e file_in file_out : encodes file_in to file_out\n"
" ClientCodec LZMA.so d file_in file_out : decodes file_in to file_out\n"
;
typedef UINT32 (WINAPI * CreateObjectFunc)(
const GUID *clsID,
const GUID *interfaceID,
void **outObject);
typedef UINT32 (WINAPI * GetNumberOfMethodsFunc)(UINT32 *numMethods);
typedef UINT32 (WINAPI * GetMethodPropertyFunc)(UINT32 index, PROPID propID, PROPVARIANT *value);
int main(int argc, char* argv[])
{
if ((argc != 3) && (argc != 5))
{
printf(kHelpString);
return 1;
}
if ((argc == 3) && (strcmp(argv[2],"i") != 0))
{
printf(kHelpString);
return 1;
}
NWindows::NDLL::CLibrary library;
if (!library.Load(argv[1]))
{
printf("Can not load library %s\n",argv[1]);
return 1;
}
CreateObjectFunc createObjectFunc = (CreateObjectFunc)library.GetProcAddress("CreateObject");
if (createObjectFunc == 0)
{
printf("Can not get CreateObject\n");
return 1;
}
GetNumberOfMethodsFunc getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)library.GetProcAddress("GetNumberOfMethods");
if (getNumberOfMethodsFunc == 0)
{
printf("Can not get GetNumberOfMethodsFunc\n");
return 1;
}
UINT32 numMethods = 0;
HRESULT res = getNumberOfMethodsFunc(&numMethods);
if (res != S_OK)
{
printf("Error in GetNumberOfMethods\n");
return 1;
}
GetMethodPropertyFunc getMethodPropertyFunc = (GetMethodPropertyFunc)library.GetProcAddress("GetMethodProperty");
if (getMethodPropertyFunc == 0)
{
printf("Can not get GetMethodProperty\n");
return 1;
}
if (argv[2][0] == 'i')
{
printf("%s has %d method(s)\n",argv[1],(int)numMethods);
for(UINT32 m = 0; m < numMethods ; m++)
{
printf("\tMethod %d :\n",(int)m);
NCOM::CPropVariant propVariant;
res = getMethodPropertyFunc(m,NMethodPropID::kName,&propVariant);
if (res == S_OK)
{
if (propVariant.vt == VT_BSTR)
{
printf("\t\tName : %ls\n",propVariant.bstrVal); // Unicode Name
} else {
printf("\t\tName : Error\n");
}
} else {
printf("\t\tName : Unknown\n");
}
res = getMethodPropertyFunc(m,NMethodPropID::kDecoder,&propVariant);
if ((res == S_OK) && (propVariant.vt == VT_BSTR)) printf("\t\tDecoder : YES\n");
else printf("\t\tDecoder : NO\n");
res = getMethodPropertyFunc(m,NMethodPropID::kEncoder,&propVariant);
if ((res == S_OK) && (propVariant.vt == VT_BSTR)) printf("\t\tEncoder : YES\n");
else printf("\t\tEncoder : NO\n");
}
}
int numMethod = 0; // TBD
if (argv[2][0] == 'e')
{
NCOM::CPropVariant propVariant;
res = getMethodPropertyFunc(numMethod,NMethodPropID::kEncoder,&propVariant);
if ((res == S_OK) && (propVariant.vt == VT_BSTR))
{
CMyComPtr<ICompressCoder> outCoder;
if (createObjectFunc((const GUID *)propVariant.bstrVal, &IID_ICompressCoder, (void **)&outCoder) != S_OK)
{
printf("Can not get class object\n");
return 1;
}
printf("Encoding : ...\n");
CMyComPtr<CFileIn> inStream = new CFileIn;
res = inStream->open(argv[3]);
if (res != S_OK)
{
printf("cannot open %s\n",argv[3]);
return 1;
}
CMyComPtr<CFileOut> outStream = new CFileOut;
res = outStream->open(argv[4]);
if (res != S_OK)
{
printf("cannot open %s\n",argv[4]);
return 1;
}
res = outCoder->Code(inStream,outStream,0,0,0);
inStream->close();
outStream->close();
if (res == S_OK)
{
printf("Encoding : Done\n");
} else {
printf("Encoding : Error\n");
return 1;
}
}
else
{
printf("Encoder not available\n");
return 1;
}
}
if (argv[2][0] == 'd')
{
NCOM::CPropVariant propVariant;
res = getMethodPropertyFunc(numMethod,NMethodPropID::kDecoder,&propVariant);
if ((res == S_OK) && (propVariant.vt == VT_BSTR))
{
CMyComPtr<ICompressCoder> outCoder;
if (createObjectFunc((const GUID *)propVariant.bstrVal, &IID_ICompressCoder, (void **)&outCoder) != S_OK)
{
printf("Can not get class object\n");
return 1;
}
printf("Decoding : ...\n");
CMyComPtr<CFileIn> inStream = new CFileIn;
res = inStream->open(argv[3]);
if (res != S_OK)
{
printf("cannot open %s\n",argv[3]);
return 1;
}
CMyComPtr<CFileOut> outStream = new CFileOut;
res = outStream->open(argv[4]);
if (res != S_OK)
{
printf("cannot open %s\n",argv[4]);
return 1;
}
res = outCoder->Code(inStream,outStream,0,0,0);
inStream->close();
outStream->close();
if (res == S_OK)
{
printf("Decoding : Done\n");
} else {
printf("Decoding : Error\n");
return 1;
}
}
else
{
printf("Decoder not available\n");
return 1;
}
}
return 0;
}
- Why does not the LZMA decoder use the same default parameters as the encoder?
I can change default properties. For example, default LZMA dictionary was 2 MB. Now default is 4 MB.
Encoding
--------
1)Try to get ICompressSetCoderProperties and call SetCoderProperties(...);
2) Try to get ICompressWriteCoderProperties
interface and call WriteCoderProperties(propsStream);
Step 1) is optional.
Write to stream:
1) Size of properties
2) Propereties
3) Uncompressed size for LZMA (if you don't use EOS marker).
4) Compressed Data
Decoding
--------
Try to get
ICompressSetDecoderProperties2.
If you can get it, call
SetDecoderProperties2(const Byte *data, UInt32 size);