Menu

DEV - generic "ClientCoder"

Help
my space
2006-10-01
2012-12-07
  • my space

    my space - 2006-10-01

      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;
    }

     
    • Igor Pavlov

      Igor Pavlov - 2006-10-02

      - 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);

       

Log in to post a comment.