/*
 * This file was generated automatically by ExtUtils::ParseXS version 2.18_02 from the
 * contents of XSAdler32.xs. Do not edit this file, edit XSAdler32.xs instead.
 *
 *	ANY CHANGES MADE HERE WILL BE LOST! 
 *
 */

#line 1 "XSAdler32.xs"
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#define BASE 65521
#define BLOCK_SIZE 10240
#ifdef __cplusplus
}
#endif


#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#line 28 "XSAdler32.c"

XS(XS_Digest__XSAdler32_update_adler32); /* prototype to pass -Wmissing-prototypes */
XS(XS_Digest__XSAdler32_update_adler32)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 3)
       Perl_croak(aTHX_ "Usage: %s(%s)", "Digest::XSAdler32::update_adler32", "fp, offset, size");
    PERL_UNUSED_VAR(cv); /* -W */
    {
	FILE *	fp = PerlIO_findFILE(IoIFP(sv_2io(ST(0))));
	unsigned long	offset = (unsigned long)SvUV(ST(1));
	unsigned long	size = (unsigned long)SvUV(ST(2));
	unsigned long	RETVAL;
	dXSTARG;
#line 22 "XSAdler32.xs"
        unsigned long m_s1, m_s2;
        m_s1 = 1; m_s2 = 0;
        unsigned int fd = fileno(fp);
        off_t seekpos = lseek(fd, offset, SEEK_SET);
        if(seekpos < 0) 
        {
            RETVAL = -1;
            exit(-1);
        }

        char *buf = (char*) malloc(sizeof(char) * BLOCK_SIZE);
        void* orig_pos = buf;

        memset(buf, '\0', BLOCK_SIZE);
        unsigned long readAmt = 0;
        while(readAmt < size) 
        {
            buf = orig_pos;

            unsigned long toRead;
            if ( (readAmt + BLOCK_SIZE) > size ) 
            {
                toRead = (size - readAmt);
            }
            else 
            {
                toRead = BLOCK_SIZE;
            }


            int length = read(fd, buf, toRead);
            if(length < 1) {
                break;
            }
            readAmt = readAmt + length;

            unsigned long s1 = m_s1;
            unsigned long s2 = m_s2;

            unsigned char* buf1 = (unsigned char*) buf;

            if (length % 8 != 0)
            {
                    do
                    {
                            s1 += *buf1++;
                            s2 += s1;
                            length--;
                    } while (length % 8 != 0);

                    if (s1 >= BASE)
                            s1 -= BASE;
                    s2 %= BASE;
            }

            while (length > 0)
            {
                    s1 += buf1[0]; s2 += s1;
                    s1 += buf1[1]; s2 += s1;
                    s1 += buf1[2]; s2 += s1;
                    s1 += buf1[3]; s2 += s1;
                    s1 += buf1[4]; s2 += s1;
                    s1 += buf1[5]; s2 += s1;
                    s1 += buf1[6]; s2 += s1;
                    s1 += buf1[7]; s2 += s1;

                    length -= 8;
                    buf1 += 8;

                    if (s1 >= BASE)
                            s1 -= BASE;
                    if (length % 0x8000 == 0)
                            s2 %= BASE;
            }

            m_s1 = s1;
            m_s2 = s2;
        }
        buf = orig_pos;
        free(buf);
        unsigned long final_cksum = (m_s2 << 16 ) | m_s1 ;
        RETVAL = final_cksum;
#line 130 "XSAdler32.c"
	XSprePUSH; PUSHu((UV)RETVAL);
    }
    XSRETURN(1);
}

#ifdef __cplusplus
extern "C"
#endif
XS(boot_Digest__XSAdler32); /* prototype to pass -Wmissing-prototypes */
XS(boot_Digest__XSAdler32)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    char* file = __FILE__;

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    XS_VERSION_BOOTCHECK ;

        newXS("Digest::XSAdler32::update_adler32", XS_Digest__XSAdler32_update_adler32, file);
    if (PL_unitcheckav)
         call_list(PL_scopestack_ix, PL_unitcheckav);
    XSRETURN_YES;
}

