Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/LibJXR/jxrgluelib/JXRMeta.c  view on Meta::CPAN

    U16 cDir;
    U16 i;
    U16 ofsEXIFIFDEntry = 0;
    U16 ofsGPSInfoIFDEntry = 0;
    U16 ofsInteroperabilityIFDEntry = 0;
    U32 ofsEXIFIFD = 0;
    U32 ofsGPSInfoIFD = 0;
    U32 ofsInteroperabilityIFD = 0;
    U32 ofsdstnextdata;
    U32 ofsdst = *pofsdst;
    U32 ofssrcdir;
    U32 ofsdstdir;
    U32 ofsnextifd;

    Call(getbfwe(pbsrc, cbsrc, ofssrc, &cDir, endian));
    Call(setbfw(pbdst, cbdst, ofsdst, cDir));
    ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir;
    ofsdstnextdata = ofsnextifd + sizeof(U32);

    ofssrcdir = ofssrc + sizeof(U16);
    ofsdstdir = ofsdst + sizeof(U16);
    for ( i = 0; i < cDir; i++ )
    {
        U16 tag;
        U16 type;
        U32 count;
        U32 value;
        U32 size;

        Call(getbfwe(pbsrc, cbsrc, ofssrcdir, &tag, endian));
        Call(setbfw(pbdst, cbdst, ofsdstdir, tag));

        Call(getbfwe(pbsrc, cbsrc, ofssrcdir + sizeof(U16), &type, endian));
        Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type));

        Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16), &count, endian));
        Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count));

        Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value, endian));
        Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0));

        FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
        if ( tag == WMP_tagEXIFMetadata )
        {
            ofsEXIFIFDEntry = (U16) ofsdstdir;
            ofsEXIFIFD = value;
        }
        else if ( tag == WMP_tagGPSInfoMetadata )
        {
            ofsGPSInfoIFDEntry = (U16) ofsdstdir;
            ofsGPSInfoIFD = value;
        }
        else if ( tag == WMP_tagInteroperabilityIFD )
        {
            ofsInteroperabilityIFDEntry = (U16) ofsdstdir;
            ofsInteroperabilityIFD = value;
        }
        else
        {
            U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32);
            U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32);
            size = count * IFDEntryTypeSizes[type];
            if ( size > 4 )
            {
                ofssrcdata = value;
                Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata));
                ofsdstdata = ofsdstnextdata;
                ofsdstnextdata += size;
            }
            FailIf(ofssrcdata + size > cbsrc || ofsdstdata + size > cbdst, WMP_errBufferOverflow);
            if ( size == count || endian == WMP_INTEL_ENDIAN )
                // size == count means 8-bit data means endian doesn't matter
                memcpy(&pbdst[ofsdstdata], &pbsrc[ofssrcdata], size);
            else
            {   // big endian source and endian matters
                U32 j;

                switch ( IFDEntryTypeSizes[type] )
                {
                case 2:
                    for ( j = 0; j < count; j++ )
                    {
                        U16 w;
                        getbfwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U16), &w);
                        setbfw(pbdst, cbdst, ofsdstdata + j * sizeof(U16), w);
                    }
                    break;
                case 8:
                    if ( type == WMP_typDOUBLE )
                    {
                        for ( j = 0; j < count; j++ )
                        {
                            U32 dwlo;
                            U32 dwhi;
                            getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8, &dwhi);
                            getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8 + sizeof(U32), &dwlo);
                            setbfdw(pbdst, cbdst, ofsdstdata + j * 8, dwlo);
                            setbfdw(pbdst, cbdst, ofsdstdata + j * 8 + sizeof(U32), dwhi);
                        }
                        break;
                    }
                    count *= 2;
                    // RATIONAL's fall through to be handled as LONG's
                case 4:
                    for ( j = 0; j < count; j++ )
                    {
                        U32 dw;
                        getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U32), &dw);
                        setbfdw(pbdst, cbdst, ofsdstdata + j * sizeof(U32), dw);
                    }
                    break;
                }
            }
        }
        ofssrcdir += SizeofIFDEntry;
        ofsdstdir += SizeofIFDEntry;
    }
    Call(setbfdw(pbdst, cbdst, ofsnextifd, 0));    // no nextIFD

    if ( ofsEXIFIFDEntry != 0 )
    {
        ofsdstnextdata += ( ofsdstnextdata & 1 );
        Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
        Call(BufferCopyIFD(pbsrc, cbsrc, ofsEXIFIFD, endian, pbdst, cbdst, &ofsdstnextdata));
    }
    if ( ofsGPSInfoIFDEntry != 0 )
    {
        ofsdstnextdata += ( ofsdstnextdata & 1 );
        Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
        Call(BufferCopyIFD(pbsrc, cbsrc, ofsGPSInfoIFD, endian, pbdst, cbdst, &ofsdstnextdata));
    }
    if ( ofsInteroperabilityIFDEntry != 0 )
    {
        ofsdstnextdata += ( ofsdstnextdata & 1 );
        Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
        Call(BufferCopyIFD(pbsrc, cbsrc, ofsInteroperabilityIFD, endian, pbdst, cbdst, &ofsdstnextdata));
    }
    *pofsdst = ofsdstnextdata;

Cleanup:
    return err;
}



// src IFD copied to dst IFD with any nested IFD's
// src IFD is little endian, arbitrary data arrangement
// dst IFD is little endian, data arranged in tag order
// dst IFD tags are ordered the same as src IFD so src IFD tags must be in order
ERR StreamCopyIFD(struct WMPStream* pWS, U32 ofssrc, U8* pbdst, U32 cbdst, U32* pofsdst)
{
    ERR err = WMP_errSuccess;
    size_t offCurPos = 0;
    Bool GetPosOK = FALSE;
    U16 cDir;
    U16 i;
    U16 ofsEXIFIFDEntry = 0;
    U16 ofsGPSInfoIFDEntry = 0;
    U16 ofsInteroperabilityIFDEntry = 0;
    U32 ofsEXIFIFD = 0;
    U32 ofsGPSInfoIFD = 0;
    U32 ofsInteroperabilityIFD = 0;
    U32 ofsdstnextdata;
    U32 ofsdst = *pofsdst;
    U32 ofssrcdir;
    U32 ofsdstdir;
    U32 ofsnextifd;

    Call(pWS->GetPos(pWS, &offCurPos));
    GetPosOK = TRUE;

    Call(GetUShort(pWS, ofssrc, &cDir));
    Call(setbfw(pbdst, cbdst, ofsdst, cDir));

    ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir;
    ofsdstnextdata = ofsnextifd + sizeof(U32);

    ofssrcdir = ofssrc + sizeof(U16);
    ofsdstdir = ofsdst + sizeof(U16);
    for ( i = 0; i < cDir; i++ )
    {
        U16 tag;
        U16 type;
        U32 count;
        U32 value;
        U32 size;

        Call(GetUShort(pWS, ofssrcdir, &tag));
        Call(setbfw(pbdst, cbdst, ofsdstdir, tag));

        Call(GetUShort(pWS, ofssrcdir + sizeof(U16), &type));
        Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type));

        Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16), &count));
        Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count));

        Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value));
        Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0));

        FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
        if ( tag == WMP_tagEXIFMetadata )
        {
            ofsEXIFIFDEntry = (U16) ofsdstdir;
            ofsEXIFIFD = value;
        }
        else if ( tag == WMP_tagGPSInfoMetadata )
        {
            ofsGPSInfoIFDEntry = (U16) ofsdstdir;
            ofsGPSInfoIFD = value;
        }
        else if ( tag == WMP_tagInteroperabilityIFD )
        {
            ofsInteroperabilityIFDEntry = (U16) ofsdstdir;
            ofsInteroperabilityIFD = value;
        }
        else
        {
            U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32);
            U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32);
            size = count * IFDEntryTypeSizes[type];
            if ( size > 4 )
            {
                ofssrcdata = value;
                Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata));
                ofsdstdata = ofsdstnextdata;
                ofsdstnextdata += size;
            }
            FailIf(ofsdstdata + size > cbdst, WMP_errBufferOverflow);
            Call(pWS->SetPos(pWS, ofssrcdata));
            Call(pWS->Read(pWS, &pbdst[ofsdstdata], size));
        }
        ofssrcdir += SizeofIFDEntry;
        ofsdstdir += SizeofIFDEntry;
    }
    Call(setbfdw(pbdst, cbdst, ofsnextifd, 0));    // no nextIFD

    if ( ofsEXIFIFDEntry != 0 )
    {
        ofsdstnextdata += ( ofsdstnextdata & 1 );
        Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
        Call(StreamCopyIFD(pWS, ofsEXIFIFD, pbdst, cbdst, &ofsdstnextdata));
    }
    if ( ofsGPSInfoIFDEntry != 0 )
    {
        ofsdstnextdata += ( ofsdstnextdata & 1 );
        Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
        Call(StreamCopyIFD(pWS, ofsGPSInfoIFD, pbdst, cbdst, &ofsdstnextdata));
    }
    if ( ofsInteroperabilityIFDEntry != 0 )
    {
        ofsdstnextdata += ( ofsdstnextdata & 1 );
        Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
        Call(StreamCopyIFD(pWS, ofsInteroperabilityIFD, pbdst, cbdst, &ofsdstnextdata));
    }
    *pofsdst = ofsdstnextdata;

Cleanup:
    if ( GetPosOK )
        Call(pWS->SetPos(pWS, offCurPos));
    return err;
}



//================================================================
ERR GetUShort(
    __in_ecount(1) struct WMPStream* pWS,
    size_t offPos,
    __out_ecount(1) U16* puValue)
{
    ERR err = WMP_errSuccess;
    U8  cVal;

    Call(pWS->SetPos(pWS, offPos));
    Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
    puValue[0] = (U16) cVal;
    Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
    puValue[0] += ((U16) cVal) << 8;

Cleanup:
    return err;
}

ERR PutUShort(
    __in_ecount(1) struct WMPStream* pWS,
    size_t offPos,
    U16 uValue)
{
    ERR err = WMP_errSuccess;



( run in 0.838 second using v1.01-cache-2.11-cpan-754626df90b )