if (zerr != Z_OK && zerr != Z_STREAM_END) {
        FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
        return 0;
    }
    return dest_len;
}

// ZLib library interface
// Design and implementation by
// - Floris van den Berg (example@nnthink.com)

#include "../ZLib/zlib.h"
#include "FreeImage.h"
#include "Utilities.h"
#include "../ZLib/zutil.h"	/* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */

/**
Compresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 12 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibUncompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = compress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Decompresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = uncompress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
		case Z_DATA_ERROR:	// input data was corrupted
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Compresses a source buffer into a target buffer, using the ZLib library.
On success, the target buffer contains a GZIP compatible layout.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 24 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size - 12;
	DWORD crc = crc32(0L, NULL, 0);

    // set up header (stolen from zlib/gzio.c)
    sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
         Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
    int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
        case Z_OK: {
            // patch header, setup crc and length (stolen from mod_trace_output)
            BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
 	        crc = crc32(crc, source, source_size);
	        memcpy(target + 4 + dest_len, &crc, 4);
	        memcpy(target + 8 + dest_len, &source_size, 4);
            return dest_len + 12;
        }
	}
	return 0;
}

/**
Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibGZip
*/

static int get_byte(z_stream *stream) {
    if (stream->avail_in <= 0) return EOF;
    stream->avail_in--;
    return *(stream->next_in)++;
}

static int checkheader(z_stream *stream) {
    int flags, c;
    DWORD len;

    if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
        return Z_DATA_ERROR;
    if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
        return Z_DATA_ERROR;
    for (len = 0; len < 6; len++) (void)get_byte(stream);

    if ((flags & 0x04) != 0) { /* skip the extra field */
        len  =  (DWORD)get_byte(stream);
        len += ((DWORD)get_byte(stream)) << 8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(stream) != EOF) ;
    }
    if ((flags & 0x08) != 0) { /* skip the original file name */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x10) != 0) {   /* skip the .gz file comment */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x02) != 0) {  /* skip the header crc */
        for (len = 0; len < 2; len++) (void)get_byte(stream);
    }
    return Z_OK;
}

DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
    DWORD src_len  = source_size;
    DWORD dest_len = target_size;
    int   zerr     = Z_DATA_ERROR;

    if (src_len > 0) {
        z_stream stream;
        memset(&stream, 0, sizeof (stream));
        if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
            stream.next_in  = source;
            stream.avail_in = source_size;

            stream.next_out  = target;
            stream.avail_out = target_size;

            if ((zerr = checkheader(&stream)) == Z_OK) {
                zerr = inflate (&stream, Z_NO_FLUSH);
                dest_len = target_size - stream.avail_out;

                if (zerr == Z_OK || zerr == Z_STREAM_END)
                    inflateEnd(&stream);
            }
        }
    }

/**
Update a running crc from source and return the updated crc, using the ZLib library.
If source is NULL, this function returns the required initial value for the crc.

@param crc Running crc value
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the new crc value
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {

    return crc32(crc, source, source_size);
}


// ZLib library interface
// Design and implementation by
// - Floris van den Berg (example@nnthink.com)

#include "../ZLib/zlib.h"
#include "FreeImage.h"
#include "Utilities.h"
#include "../ZLib/zutil.h"	/* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */

/**
Compresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 12 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibUncompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = compress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Decompresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf

	int zerr = uncompress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
		case Z_DATA_ERROR:	// input data was corrupted
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Compresses a source buffer into a target buffer, using the ZLib library.
On success, the target buffer contains a GZIP compatible layout.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 24 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size - 12;
	DWORD crc = crc32(0L, NULL, 0);

    // set up header (stolen from zlib/gzio.c)
    sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
         Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
    int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
        case Z_OK: {
            // patch header, setup crc and length (stolen from mod_trace_output)
            BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
 	        crc = crc32(crc, source, source_size);
	        memcpy(target + 4 + dest_len, &crc, 4);
	        memcpy(target + 8 + dest_len, &source_size, 4);
            return dest_len + 12;
        }
	}
	return 0;
}

/**
Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibGZip
*/

static int get_byte(z_stream *stream) {
    if (stream->avail_in <= 0) return EOF;
    stream->avail_in--;
    return *(stream->next_in)++;
}

static int checkheader(z_stream *stream) {
    int flags, c;
    DWORD len;

    if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
        return Z_DATA_ERROR;
    if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
        return Z_DATA_ERROR;
    for (len = 0; len < 6; len++) (void)get_byte(stream);

    if ((flags & 0x04) != 0) { /* skip the extra field */
        len  =  (DWORD)get_byte(stream);
        len += ((DWORD)get_byte(stream)) << 8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(stream) != EOF) ;
    }
    if ((flags & 0x08) != 0) { /* skip the original file name */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x10) != 0) {   /* skip the .gz file comment */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x02) != 0) {  /* skip the header crc */
        for (len = 0; len < 2; len++) (void)get_byte(stream);
    }
    return Z_OK;
}

DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
    DWORD src_len  = source_size;
    DWORD dest_len = target_size;
    int   zerr     = Z_DATA_ERROR;

    if (src_len > 0) {
        z_stream stream;
        memset(&stream, 0, sizeof (stream));
        if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
            stream.next_in  = source;
            stream.avail_in = source_size;

            stream.next_out  = target;
            stream.avail_out = target_size;

            if ((zerr = checkheader(&stream)) == Z_OK) {
                zerr = inflate (&stream, Z_NO_FLUSH);
                dest_len = target_size - stream.avail_out;

                if (zerr == Z_OK || zerr == Z_STREAM_END)
                    inflateEnd(&stream);
            }
        }
    }
    if (zerr != Z_OK && zerr != Z_STREAM_END) {
        FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
        return 0;
    }
    return dest_len;
}

/**
Update a running crc from source and return the updated crc, using the ZLib library.
If source is NULL, this function returns the required initial value for the crc.

@param crc Running crc value
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the new crc value
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {

    return crc32(crc, source, source_size);
}


DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = compress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

// ZLib library interface
// Design and implementation by
// - Floris van den Berg (example@nnthink.com)

#include "../ZLib/zlib.h"
#include "FreeImage.h"
#include "Utilities.h"
#include "../ZLib/zutil.h"	/* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */

/**
Compresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 12 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibUncompress
*/

/**
Decompresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = uncompress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
		case Z_DATA_ERROR:	// input data was corrupted
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Compresses a source buffer into a target buffer, using the ZLib library.
On success, the target buffer contains a GZIP compatible layout.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 24 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size - 12;
	DWORD crc = crc32(0L, NULL, 0);

    // set up header (stolen from zlib/gzio.c)
    sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
         Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
    int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
        case Z_OK: {
            // patch header, setup crc and length (stolen from mod_trace_output)
            BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
 	        crc = crc32(crc, source, source_size);
	        memcpy(target + 4 + dest_len, &crc, 4);
	        memcpy(target + 8 + dest_len, &source_size, 4);
            return dest_len + 12;
        }
	}
	return 0;
}

/**
Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibGZip
*/

static int get_byte(z_stream *stream) {
    if (stream->avail_in <= 0) return EOF;
    stream->avail_in--;
    return *(stream->next_in)++;
}

static int checkheader(z_stream *stream) {
    int flags, c;
    DWORD len;

    if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
        return Z_DATA_ERROR;
    if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
        return Z_DATA_ERROR;
    for (len = 0; len < 6; len++) (void)get_byte(stream);

    if ((flags & 0x04) != 0) { /* skip the extra field */
        len  =  (DWORD)get_byte(stream);
        len += ((DWORD)get_byte(stream)) << 8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(stream) != EOF) ;
    }
    if ((flags & 0x08) != 0) { /* skip the original file name */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x10) != 0) {   /* skip the .gz file comment */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x02) != 0) {  /* skip the header crc */
        for (len = 0; len < 2; len++) (void)get_byte(stream);
    }
    return Z_OK;
}

DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
    DWORD src_len  = source_size;
    DWORD dest_len = target_size;
    int   zerr     = Z_DATA_ERROR;

    if (src_len > 0) {
        z_stream stream;
        memset(&stream, 0, sizeof (stream));
        if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
            stream.next_in  = source;
            stream.avail_in = source_size;

            stream.next_out  = target;
            stream.avail_out = target_size;

            if ((zerr = checkheader(&stream)) == Z_OK) {
                zerr = inflate (&stream, Z_NO_FLUSH);
                dest_len = target_size - stream.avail_out;

                if (zerr == Z_OK || zerr == Z_STREAM_END)
                    inflateEnd(&stream);
            }
        }
    }
    if (zerr != Z_OK && zerr != Z_STREAM_END) {
        FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
        return 0;
    }
    return dest_len;
}

/**
Update a running crc from source and return the updated crc, using the ZLib library.
If source is NULL, this function returns the required initial value for the crc.

@param crc Running crc value
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the new crc value
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {

    return crc32(crc, source, source_size);
}


// ZLib library interface
// Design and implementation by
// - Floris van den Berg (example@nnthink.com)

#include "../ZLib/zlib.h"
#include "FreeImage.h"
#include "Utilities.h"
#include "../ZLib/zutil.h"	/* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */

/**
Compresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 12 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibUncompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = compress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Decompresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = uncompress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
		case Z_DATA_ERROR:	// input data was corrupted
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Compresses a source buffer into a target buffer, using the ZLib library.
On success, the target buffer contains a GZIP compatible layout.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 24 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size - 12;
	DWORD crc = crc32(0L, NULL, 0);

    // set up header (stolen from zlib/gzio.c)
    sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
         Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
    int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
        case Z_OK: {
            // patch header, setup crc and length (stolen from mod_trace_output)
            BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
 	        crc = crc32(crc, source, source_size);
	        memcpy(target + 4 + dest_len, &crc, 4);
	        memcpy(target + 8 + dest_len, &source_size, 4);
            return dest_len + 12;
        }
	}
	return 0;
}

/**
Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibGZip
*/

static int get_byte(z_stream *stream) {

    stream->avail_in--;
    return *(stream->next_in)++;
}

static int checkheader(z_stream *stream) {
    int flags, c;
    DWORD len;

    if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
        return Z_DATA_ERROR;
    if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
        return Z_DATA_ERROR;
    for (len = 0; len < 6; len++) (void)get_byte(stream);

    if ((flags & 0x04) != 0) { /* skip the extra field */
        len  =  (DWORD)get_byte(stream);
        len += ((DWORD)get_byte(stream)) << 8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(stream) != EOF) ;
    }
    if ((flags & 0x08) != 0) { /* skip the original file name */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x10) != 0) {   /* skip the .gz file comment */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x02) != 0) {  /* skip the header crc */
        for (len = 0; len < 2; len++) (void)get_byte(stream);
    }
    return Z_OK;
}

DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
    DWORD src_len  = source_size;
    DWORD dest_len = target_size;
    int   zerr     = Z_DATA_ERROR;

    if (src_len > 0) {
        z_stream stream;
        memset(&stream, 0, sizeof (stream));
        if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
            stream.next_in  = source;
            stream.avail_in = source_size;

            stream.next_out  = target;
            stream.avail_out = target_size;

            if ((zerr = checkheader(&stream)) == Z_OK) {
                zerr = inflate (&stream, Z_NO_FLUSH);
                dest_len = target_size - stream.avail_out;

                if (zerr == Z_OK || zerr == Z_STREAM_END)
                    inflateEnd(&stream);
            }
        }
    }
    if (zerr != Z_OK && zerr != Z_STREAM_END) {
        FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
        return 0;
    }
    return dest_len;
}

/**
Update a running crc from source and return the updated crc, using the ZLib library.
If source is NULL, this function returns the required initial value for the crc.

@param crc Running crc value
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the new crc value
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {

    return crc32(crc, source, source_size);
}


switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
		case Z_DATA_ERROR:	// input data was corrupted
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

// ZLib library interface
// Design and implementation by
// - Floris van den Berg (example@nnthink.com)

#include "../ZLib/zlib.h"
#include "FreeImage.h"
#include "Utilities.h"
#include "../ZLib/zutil.h"	/* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */

/**
Compresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 12 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibUncompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = compress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Decompresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = uncompress(target, &dest_len, source, source_size);

	return 0;
}

/**
Compresses a source buffer into a target buffer, using the ZLib library.
On success, the target buffer contains a GZIP compatible layout.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 24 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size - 12;
	DWORD crc = crc32(0L, NULL, 0);

    // set up header (stolen from zlib/gzio.c)
    sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
         Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
    int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
        case Z_OK: {
            // patch header, setup crc and length (stolen from mod_trace_output)
            BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
 	        crc = crc32(crc, source, source_size);
	        memcpy(target + 4 + dest_len, &crc, 4);
	        memcpy(target + 8 + dest_len, &source_size, 4);
            return dest_len + 12;
        }
	}
	return 0;
}

/**
Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibGZip
*/

static int get_byte(z_stream *stream) {
    if (stream->avail_in <= 0) return EOF;
    stream->avail_in--;
    return *(stream->next_in)++;
}

static int checkheader(z_stream *stream) {
    int flags, c;
    DWORD len;

    if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
        return Z_DATA_ERROR;
    if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
        return Z_DATA_ERROR;
    for (len = 0; len < 6; len++) (void)get_byte(stream);

    if ((flags & 0x04) != 0) { /* skip the extra field */
        len  =  (DWORD)get_byte(stream);
        len += ((DWORD)get_byte(stream)) << 8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(stream) != EOF) ;
    }
    if ((flags & 0x08) != 0) { /* skip the original file name */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x10) != 0) {   /* skip the .gz file comment */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x02) != 0) {  /* skip the header crc */
        for (len = 0; len < 2; len++) (void)get_byte(stream);
    }
    return Z_OK;
}

DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
    DWORD src_len  = source_size;
    DWORD dest_len = target_size;
    int   zerr     = Z_DATA_ERROR;

    if (src_len > 0) {
        z_stream stream;
        memset(&stream, 0, sizeof (stream));
        if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
            stream.next_in  = source;
            stream.avail_in = source_size;

            stream.next_out  = target;
            stream.avail_out = target_size;

            if ((zerr = checkheader(&stream)) == Z_OK) {
                zerr = inflate (&stream, Z_NO_FLUSH);
                dest_len = target_size - stream.avail_out;

                if (zerr == Z_OK || zerr == Z_STREAM_END)
                    inflateEnd(&stream);
            }
        }
    }
    if (zerr != Z_OK && zerr != Z_STREAM_END) {
        FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
        return 0;
    }
    return dest_len;
}

/**
Update a running crc from source and return the updated crc, using the ZLib library.
If source is NULL, this function returns the required initial value for the crc.

@param crc Running crc value
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the new crc value
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {

    return crc32(crc, source, source_size);
}


for (len = 0; len < 6; len++) (void)get_byte(stream);

// ZLib library interface
// Design and implementation by
// - Floris van den Berg (example@nnthink.com)

#include "../ZLib/zlib.h"
#include "FreeImage.h"
#include "Utilities.h"
#include "../ZLib/zutil.h"	/* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */

/**
Compresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 12 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibUncompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = compress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Decompresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = uncompress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
		case Z_DATA_ERROR:	// input data was corrupted
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Compresses a source buffer into a target buffer, using the ZLib library.
On success, the target buffer contains a GZIP compatible layout.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 24 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size - 12;
	DWORD crc = crc32(0L, NULL, 0);

    // set up header (stolen from zlib/gzio.c)
    sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
         Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
    int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
        case Z_OK: {
            // patch header, setup crc and length (stolen from mod_trace_output)
            BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
 	        crc = crc32(crc, source, source_size);
	        memcpy(target + 4 + dest_len, &crc, 4);
	        memcpy(target + 8 + dest_len, &source_size, 4);
            return dest_len + 12;
        }
	}
	return 0;
}

/**
Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibGZip
*/

static int get_byte(z_stream *stream) {
    if (stream->avail_in <= 0) return EOF;
    stream->avail_in--;
    return *(stream->next_in)++;
}

static int checkheader(z_stream *stream) {
    int flags, c;
    DWORD len;

    if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
        return Z_DATA_ERROR;
    if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
        return Z_DATA_ERROR;

    if ((flags & 0x04) != 0) { /* skip the extra field */
        len  =  (DWORD)get_byte(stream);
        len += ((DWORD)get_byte(stream)) << 8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(stream) != EOF) ;
    }
    if ((flags & 0x08) != 0) { /* skip the original file name */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x10) != 0) {   /* skip the .gz file comment */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x02) != 0) {  /* skip the header crc */
        for (len = 0; len < 2; len++) (void)get_byte(stream);
    }
    return Z_OK;
}

DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
    DWORD src_len  = source_size;
    DWORD dest_len = target_size;
    int   zerr     = Z_DATA_ERROR;

    if (src_len > 0) {
        z_stream stream;
        memset(&stream, 0, sizeof (stream));
        if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
            stream.next_in  = source;
            stream.avail_in = source_size;

            stream.next_out  = target;
            stream.avail_out = target_size;

            if ((zerr = checkheader(&stream)) == Z_OK) {
                zerr = inflate (&stream, Z_NO_FLUSH);
                dest_len = target_size - stream.avail_out;

                if (zerr == Z_OK || zerr == Z_STREAM_END)
                    inflateEnd(&stream);
            }
        }
    }
    if (zerr != Z_OK && zerr != Z_STREAM_END) {
        FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
        return 0;
    }
    return dest_len;
}

/**
Update a running crc from source and return the updated crc, using the ZLib library.
If source is NULL, this function returns the required initial value for the crc.

@param crc Running crc value
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the new crc value
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {

    return crc32(crc, source, source_size);
}


// ZLib library interface
// Design and implementation by
// - Floris van den Berg (example@nnthink.com)

#include "../ZLib/zlib.h"
#include "FreeImage.h"
#include "Utilities.h"
#include "../ZLib/zutil.h"	/* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */

/**
Compresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 12 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibUncompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = compress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Decompresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = uncompress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
		case Z_DATA_ERROR:	// input data was corrupted
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Compresses a source buffer into a target buffer, using the ZLib library.
On success, the target buffer contains a GZIP compatible layout.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 24 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size - 12;
	DWORD crc = crc32(0L, NULL, 0);

    // set up header (stolen from zlib/gzio.c)
    sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
         Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
    int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
        case Z_OK: {
            // patch header, setup crc and length (stolen from mod_trace_output)
            BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
 	        crc = crc32(crc, source, source_size);
	        memcpy(target + 4 + dest_len, &crc, 4);
	        memcpy(target + 8 + dest_len, &source_size, 4);
            return dest_len + 12;
        }
	}
	return 0;
}

/**
Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibGZip
*/

static int get_byte(z_stream *stream) {
    if (stream->avail_in <= 0) return EOF;
    stream->avail_in--;
    return *(stream->next_in)++;
}

static int checkheader(z_stream *stream) {
    int flags, c;
    DWORD len;

    if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
        return Z_DATA_ERROR;
    if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
        return Z_DATA_ERROR;
    for (len = 0; len < 6; len++) (void)get_byte(stream);

    if ((flags & 0x04) != 0) { /* skip the extra field */
        len  =  (DWORD)get_byte(stream);
        len += ((DWORD)get_byte(stream)) << 8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(stream) != EOF) ;
    }
    if ((flags & 0x08) != 0) { /* skip the original file name */

    }
    if ((flags & 0x10) != 0) {   /* skip the .gz file comment */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x02) != 0) {  /* skip the header crc */
        for (len = 0; len < 2; len++) (void)get_byte(stream);
    }
    return Z_OK;
}

DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
    DWORD src_len  = source_size;
    DWORD dest_len = target_size;
    int   zerr     = Z_DATA_ERROR;

    if (src_len > 0) {
        z_stream stream;
        memset(&stream, 0, sizeof (stream));
        if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
            stream.next_in  = source;
            stream.avail_in = source_size;

            stream.next_out  = target;
            stream.avail_out = target_size;

            if ((zerr = checkheader(&stream)) == Z_OK) {
                zerr = inflate (&stream, Z_NO_FLUSH);
                dest_len = target_size - stream.avail_out;

                if (zerr == Z_OK || zerr == Z_STREAM_END)
                    inflateEnd(&stream);
            }
        }
    }
    if (zerr != Z_OK && zerr != Z_STREAM_END) {
        FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
        return 0;
    }
    return dest_len;
}

/**
Update a running crc from source and return the updated crc, using the ZLib library.
If source is NULL, this function returns the required initial value for the crc.

@param crc Running crc value
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the new crc value
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {

    return crc32(crc, source, source_size);
}


// ZLib library interface
// Design and implementation by
// - Floris van den Berg (example@nnthink.com)

#include "../ZLib/zlib.h"
#include "FreeImage.h"
#include "Utilities.h"
#include "../ZLib/zutil.h"	/* must be the last header because of error C3163 in VS2008 (_vsnprintf defined in stdio.h) */

/**
Compresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 12 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibUncompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = compress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Decompresses a source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size;

	int zerr = uncompress(target, &dest_len, source, source_size);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
		case Z_DATA_ERROR:	// input data was corrupted
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
		case Z_OK:
			return dest_len;
	}

	return 0;
}

/**
Compresses a source buffer into a target buffer, using the ZLib library.
On success, the target buffer contains a GZIP compatible layout.
Upon entry, target_size is the total size of the destination buffer,
which must be at least 0.1% larger than source_size plus 24 bytes.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the compressed buffer, returns 0 if an error occured
@see FreeImage_ZLibCompress
*/
DWORD DLL_CALLCONV
FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
	uLongf dest_len = (uLongf)target_size - 12;
	DWORD crc = crc32(0L, NULL, 0);

    // set up header (stolen from zlib/gzio.c)
    sprintf((char *)target, "%c%c%c%c%c%c%c%c", 0x1f, 0x8b,
         Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/);
    int zerr = compress2(target + 8, &dest_len, source, source_size, Z_BEST_COMPRESSION);
	switch(zerr) {
		case Z_MEM_ERROR:	// not enough memory
		case Z_BUF_ERROR:	// not enough room in the output buffer
			FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
			return 0;
        case Z_OK: {
            // patch header, setup crc and length (stolen from mod_trace_output)
            BYTE *p = target + 8; *p++ = 2; *p = OS_CODE; // xflags, os_code
 	        crc = crc32(crc, source, source_size);
	        memcpy(target + 4 + dest_len, &crc, 4);
	        memcpy(target + 8 + dest_len, &source_size, 4);
            return dest_len + 12;
        }
	}
	return 0;
}

/**
Decompresses a gzipped source buffer into a target buffer, using the ZLib library.
Upon entry, target_size is the total size of the destination buffer,
which must be large enough to hold the entire uncompressed data.
The size of the uncompressed data must have been saved previously by the compressor
and transmitted to the decompressor by some mechanism outside the scope of this
compression library.

@param target Destination buffer
@param target_size Size of the destination buffer, in bytes
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the actual size of the uncompressed buffer, returns 0 if an error occured
@see FreeImage_ZLibGZip
*/

static int get_byte(z_stream *stream) {
    if (stream->avail_in <= 0) return EOF;
    stream->avail_in--;
    return *(stream->next_in)++;
}

static int checkheader(z_stream *stream) {
    int flags, c;
    DWORD len;

    if (get_byte(stream) != 0x1f || get_byte(stream) != 0x8b)
        return Z_DATA_ERROR;
    if (get_byte(stream) != Z_DEFLATED || ((flags = get_byte(stream)) & 0xE0) != 0)
        return Z_DATA_ERROR;
    for (len = 0; len < 6; len++) (void)get_byte(stream);

    if ((flags & 0x04) != 0) { /* skip the extra field */
        len  =  (DWORD)get_byte(stream);
        len += ((DWORD)get_byte(stream)) << 8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(stream) != EOF) ;
    }
    if ((flags & 0x08) != 0) { /* skip the original file name */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x10) != 0) {

/* skip the .gz file comment */
        while ((c = get_byte(stream)) != 0 && c != EOF) ;
    }
    if ((flags & 0x02) != 0) {  /* skip the header crc */
        for (len = 0; len < 2; len++) (void)get_byte(stream);
    }
    return Z_OK;
}

DWORD DLL_CALLCONV
FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) {
    DWORD src_len  = source_size;
    DWORD dest_len = target_size;
    int   zerr     = Z_DATA_ERROR;

    if (src_len > 0) {
        z_stream stream;
        memset(&stream, 0, sizeof (stream));
        if ((zerr = inflateInit2(&stream, -MAX_WBITS)) == Z_OK) {
            stream.next_in  = source;
            stream.avail_in = source_size;

            stream.next_out  = target;
            stream.avail_out = target_size;

            if ((zerr = checkheader(&stream)) == Z_OK) {
                zerr = inflate (&stream, Z_NO_FLUSH);
                dest_len = target_size - stream.avail_out;

                if (zerr == Z_OK || zerr == Z_STREAM_END)
                    inflateEnd(&stream);
            }
        }
    }
    if (zerr != Z_OK && zerr != Z_STREAM_END) {
        FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr));
        return 0;
    }
    return dest_len;
}

/**
Update a running crc from source and return the updated crc, using the ZLib library.
If source is NULL, this function returns the required initial value for the crc.

@param crc Running crc value
@param source Source buffer
@param source_size Size of the source buffer, in bytes
@return Returns the new crc value
*/
DWORD DLL_CALLCONV
FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size) {

    return crc32(crc, source, source_size);
}


/**
 */

#include <aws/directconnect/model/DescribeDirectConnectGatewayAssociationProposalsRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::DirectConnect::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DescribeDirectConnectGatewayAssociationProposalsRequest::DescribeDirectConnectGatewayAssociationProposalsRequest() :
    m_directConnectGatewayIdHasBeenSet(false),
    m_proposalIdHasBeenSet(false),
    m_associatedGatewayIdHasBeenSet(false),
    m_maxResults(0),
    m_maxResultsHasBeenSet(false),
    m_nextTokenHasBeenSet(false)
{
}

Aws::String DescribeDirectConnectGatewayAssociationProposalsRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_directConnectGatewayIdHasBeenSet)
  {
   payload.WithString("directConnectGatewayId", m_directConnectGatewayId);

  }

  if(m_proposalIdHasBeenSet)
  {
   payload.WithString("proposalId", m_proposalId);

  }

  if(m_associatedGatewayIdHasBeenSet)
  {
   payload.WithString("associatedGatewayId", m_associatedGatewayId);

  }

  if(m_maxResultsHasBeenSet)
  {
   payload.WithInteger("maxResults", m_maxResults);

  }

  if(m_nextTokenHasBeenSet)
  {
   payload.WithString("nextToken", m_nextToken);

  }

  return payload.View().WriteReadable();
}

{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "OvertureService.DescribeDirectConnectGatewayAssociationProposals"));
  return headers;

}


{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "OvertureService.DescribeDirectConnectGatewayAssociationProposals"));
  return headers;

}

/**
 */

#include <aws/directconnect/model/DescribeDirectConnectGatewayAssociationProposalsRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::DirectConnect::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DescribeDirectConnectGatewayAssociationProposalsRequest::DescribeDirectConnectGatewayAssociationProposalsRequest() :
    m_directConnectGatewayIdHasBeenSet(false),
    m_proposalIdHasBeenSet(false),
    m_associatedGatewayIdHasBeenSet(false),
    m_maxResults(0),
    m_maxResultsHasBeenSet(false),
    m_nextTokenHasBeenSet(false)
{
}

Aws::String DescribeDirectConnectGatewayAssociationProposalsRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_directConnectGatewayIdHasBeenSet)
  {
   payload.WithString("directConnectGatewayId", m_directConnectGatewayId);

  }

  if(m_proposalIdHasBeenSet)
  {
   payload.WithString("proposalId", m_proposalId);

  }

  if(m_associatedGatewayIdHasBeenSet)
  {
   payload.WithString("associatedGatewayId", m_associatedGatewayId);

  }

  if(m_maxResultsHasBeenSet)
  {
   payload.WithInteger("maxResults", m_maxResults);

  }

  if(m_nextTokenHasBeenSet)
  {
   payload.WithString("nextToken", m_nextToken);

  }

  return payload.View().WriteReadable();
}

Aws::Http::HeaderValueCollection DescribeDirectConnectGatewayAssociationProposalsRequest::GetRequestSpecificHeaders() const


{
  JsonValue payload;

  if(m_directConnectGatewayIdHasBeenSet)
  {
   payload.WithString("directConnectGatewayId", m_directConnectGatewayId);

  }

/**
 */

#include <aws/directconnect/model/DescribeDirectConnectGatewayAssociationProposalsRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::DirectConnect::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DescribeDirectConnectGatewayAssociationProposalsRequest::DescribeDirectConnectGatewayAssociationProposalsRequest() :
    m_directConnectGatewayIdHasBeenSet(false),
    m_proposalIdHasBeenSet(false),
    m_associatedGatewayIdHasBeenSet(false),
    m_maxResults(0),
    m_maxResultsHasBeenSet(false),
    m_nextTokenHasBeenSet(false)
{
}

Aws::String DescribeDirectConnectGatewayAssociationProposalsRequest::SerializePayload() const

  if(m_proposalIdHasBeenSet)
  {
   payload.WithString("proposalId", m_proposalId);

  }

  if(m_associatedGatewayIdHasBeenSet)
  {
   payload.WithString("associatedGatewayId", m_associatedGatewayId);

  }

  if(m_maxResultsHasBeenSet)
  {
   payload.WithInteger("maxResults", m_maxResults);

  }

  if(m_nextTokenHasBeenSet)
  {
   payload.WithString("nextToken", m_nextToken);

  }

  return payload.View().WriteReadable();
}

Aws::Http::HeaderValueCollection DescribeDirectConnectGatewayAssociationProposalsRequest::GetRequestSpecificHeaders() const
{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "OvertureService.DescribeDirectConnectGatewayAssociationProposals"));
  return headers;

}


if(m_proposalIdHasBeenSet)
  {
   payload.WithString("proposalId", m_proposalId);

  }

  if(m_associatedGatewayIdHasBeenSet)
  {
   payload.WithString("associatedGatewayId", m_associatedGatewayId);

  }

  if(m_maxResultsHasBeenSet)
  {
   payload.WithInteger("maxResults", m_maxResults);

  }

/**
 */

#include <aws/directconnect/model/DescribeDirectConnectGatewayAssociationProposalsRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::DirectConnect::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DescribeDirectConnectGatewayAssociationProposalsRequest::DescribeDirectConnectGatewayAssociationProposalsRequest() :
    m_directConnectGatewayIdHasBeenSet(false),
    m_proposalIdHasBeenSet(false),
    m_associatedGatewayIdHasBeenSet(false),
    m_maxResults(0),
    m_maxResultsHasBeenSet(false),
    m_nextTokenHasBeenSet(false)
{
}

Aws::String DescribeDirectConnectGatewayAssociationProposalsRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_directConnectGatewayIdHasBeenSet)
  {
   payload.WithString("directConnectGatewayId", m_directConnectGatewayId);

  }

  if(m_nextTokenHasBeenSet)
  {
   payload.WithString("nextToken", m_nextToken);

  }

  return payload.View().WriteReadable();
}

Aws::Http::HeaderValueCollection DescribeDirectConnectGatewayAssociationProposalsRequest::GetRequestSpecificHeaders() const
{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "OvertureService.DescribeDirectConnectGatewayAssociationProposals"));
  return headers;

}


if(m_nextTokenHasBeenSet)
  {
   payload.WithString("nextToken", m_nextToken);

  }

  return payload.View().WriteReadable();
}

/**
 */

#include <aws/directconnect/model/DescribeDirectConnectGatewayAssociationProposalsRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::DirectConnect::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DescribeDirectConnectGatewayAssociationProposalsRequest::DescribeDirectConnectGatewayAssociationProposalsRequest() :
    m_directConnectGatewayIdHasBeenSet(false),
    m_proposalIdHasBeenSet(false),
    m_associatedGatewayIdHasBeenSet(false),
    m_maxResults(0),
    m_maxResultsHasBeenSet(false),
    m_nextTokenHasBeenSet(false)
{
}

Aws::String DescribeDirectConnectGatewayAssociationProposalsRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_directConnectGatewayIdHasBeenSet)
  {
   payload.WithString("directConnectGatewayId", m_directConnectGatewayId);

  }

  if(m_proposalIdHasBeenSet)
  {
   payload.WithString("proposalId", m_proposalId);

  }

  if(m_associatedGatewayIdHasBeenSet)
  {
   payload.WithString("associatedGatewayId", m_associatedGatewayId);

  }

  if(m_maxResultsHasBeenSet)
  {
   payload.WithInteger("maxResults", m_maxResults);

  }

Aws::Http::HeaderValueCollection DescribeDirectConnectGatewayAssociationProposalsRequest::GetRequestSpecificHeaders() const
{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "OvertureService.DescribeDirectConnectGatewayAssociationProposals"));
  return headers;

}


/**
 */

#include <aws/directconnect/model/DescribeDirectConnectGatewayAssociationProposalsRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::DirectConnect::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DescribeDirectConnectGatewayAssociationProposalsRequest::DescribeDirectConnectGatewayAssociationProposalsRequest() :
    m_directConnectGatewayIdHasBeenSet(false),
    m_proposalIdHasBeenSet(false),
    m_associatedGatewayIdHasBeenSet(false),
    m_maxResults(0),
    m_maxResultsHasBeenSet(false),
    m_nextTokenHasBeenSet(false)
{
}

Aws::String DescribeDirectConnectGatewayAssociationProposalsRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_directConnectGatewayIdHasBeenSet)
  {
   payload.WithString("directConnectGatewayId", m_directConnectGatewayId);

  }

  if(m_proposalIdHasBeenSet)
  {
   payload.WithString("proposalId", m_proposalId);

  }

  if(m_associatedGatewayIdHasBeenSet)
  {
   payload.WithString("associatedGatewayId", m_associatedGatewayId);

  }

  if(m_maxResultsHasBeenSet)
  {
   payload.WithInteger("maxResults", m_maxResults);

  }

  if(m_nextTokenHasBeenSet)
  {
   payload.WithString("nextToken", m_nextToken);

  }

  ret

}

Aws::Http::HeaderValueCollection DescribeDirectConnectGatewayAssociationProposalsRequest::GetRequestSpecificHeaders() const
{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "OvertureService.DescribeDirectConnectGatewayAssociationProposals"));
  return headers;

}


if(m_maxResultsHasBeenSet)
  {
   payload.WithInteger("maxResults", m_maxResults);

  }

/**
 */

#include <aws/directconnect/model/DescribeDirectConnectGatewayAssociationProposalsRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::DirectConnect::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DescribeDirectConnectGatewayAssociationProposalsRequest::DescribeDirectConnectGatewayAssociationProposalsRequest() :
    m_directConnectGatewayIdHasBeenSet(false),
    m_proposalIdHasBeenSet(false),
    m_associatedGatewayIdHasBeenSet(false),
    m_maxResults(0),
    m_maxResultsHasBeenSet(false),
    m_nextTokenHasBeenSet(false)
{
}

Aws::String DescribeDirectConnectGatewayAssociationProposalsRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_directConnectGatewayIdHasBeenSet)
  {
   payload.WithString("directConnectGatewayId", m_directConnectGatewayId);

  }

  if(m_proposalIdHasBeenSet)
  {
   payload.WithString("proposalId", m_proposalId);

  }

  if(m_associatedGatewayIdHasBeenSet)
  {
   payload.WithString("associatedGatewayId", m_associatedGatewayId);

  }


/**
 */

#include <aws/directconnect/model/DescribeDirectConnectGatewayAssociationProposalsRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::DirectConnect::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

DescribeDirectConnectGatewayAssociationProposalsRequest::DescribeDirec

tConnectGatewayAssociationProposalsRequest() :
    m_directConnectGatewayIdHasBeenSet(false),
    m_proposalIdHasBeenSet(false),
    m_associatedGatewayIdHasBeenSet(false),
    m_maxResults(0),
    m_maxResultsHasBeenSet(false),
    m_nextTokenHasBeenSet(false)
{
}

Aws::String DescribeDirectConnectGatewayAssociationProposalsRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_directConnectGatewayIdHasBeenSet)
  {
   payload.WithString("directConnectGatewayId", m_directConnectGatewayId);

  }

  if(m_proposalIdHasBeenSet)
  {
   payload.WithString("proposalId", m_proposalId);

  }

  if(m_associatedGatewayIdHasBeenSet)
  {
   payload.WithString("associatedGatewayId", m_associatedGatewayId);

  }

  if(m_maxResultsHasBeenSet)
  {
   payload.WithInteger("maxResults", m_maxResults);

  }

  if(m_nextTokenHasBeenSet)
  {
   payload.WithString("nextToken", m_nextToken);

  }

  return payload.View().WriteReadable();
}

Aws::Http::HeaderValueCollection DescribeDirectConnectGatewayAssociationProposalsRequest::GetRequestSpecificHeaders() const
{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "OvertureService.DescribeDirectConnectGatewayAssociationProposals"));
  return headers;

}


bool save_file(const std::vector<patch_byte> &pvec, std::string fname)

/*
http://example.com

A thread-safe logging console with a line editor for windows.

Based on linenoise win32 port,
All rights reserved.
The original linenoise can be found at: http://example.com

*/

#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include <stdint.h>

#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <vector>

#include <memory>

#include <md5wrapper.h>

using std::cout;
using std::cerr;
using std::endl;

typedef unsigned char patch_byte;

struct BinaryPatch {
    struct Byte {
        unsigned offset;
        patch_byte old_val, new_val;
    };
    enum State {
        Conflict = 0,
        Unapplied = 1,
        Applied = 2,
        Partial = 3
    };

    std::vector<Byte> entries;

    bool loadDIF(std::string name);
    State checkState(const patch_byte *ptr, size_t len);

    void apply(patch_byte *ptr, size_t len, bool newv);
};

inline bool is_hex(char c)
{
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}

bool BinaryPatch::loadDIF(std::string name)
{
    entries.clear();

    std::ifstream infile(name);
    if(infile.bad())
    {
        cerr << "Cannot open file: " << name << endl;
        return false;
    }

    std::string s;
    while(std::getline(infile, s))
    {
        // Parse lines that begin with "[0-9a-f]+:"
        size_t idx = s.find(':');
        if (idx == std::string::npos || idx == 0 || idx > 8)
            continue;

        bool ok = true;
        for (size_t i = 0; i < idx; i++)
            if (!is_hex(s[i]))
                ok = false;
        if (!ok)
            continue;

        unsigned off, oval, nval;
        int nchar = 0;
        int cnt = sscanf(s.c_str(), "%x: %x %x%n", &off, &oval, &nval, &nchar);

        if (cnt < 3)
        {
            cerr << "Could not parse: " << s << endl;
            return false;
        }

        for (size_t i = nchar; i < s.size(); i++)
        {
            if (!isspace(s[i]))
            {
                cerr << "Garbage at end of line: " << s << endl;
                return false;
            }
        }

        if (oval >= 256 || nval >= 256)
        {
            cerr << "Invalid byte values: " << s << endl;
            return false;
        }

        Byte bv = { off, patch_byte(oval), patch_byte(nval) };
        entries.push_back(bv);
    }

    if (entries.empty())
    {
        cerr << "No lines recognized." << endl;
        return false;
    }

    return true;
}

BinaryPatch::State BinaryPatch::checkState(const patch_byte *ptr, size_t len)
{
    int state = 0;

    for (size_t i = 0; i < entries.size(); i++)
    {
        Byte &bv = entries[i];

        if (bv.offset >= len)
        {
            cerr << "Offset out of range: 0x" << std::hex << bv.offset << std::dec << endl;
            return Conflict;
        }

        patch_byte cv = ptr[bv.offset];
        if (bv.old_val == cv)
            state |= Unapplied;
        else if (bv.new_val == cv)
            state |= Applied;
        else
        {
            cerr << std::hex << bv.offset << ": "
                 << unsigned(bv.old_val) << " " << unsigned(bv.new_val)
                 << ", but currently " << unsigned(cv) << std::dec << endl;
            return Conflict;
        }
    }

    return State(state);
}

void BinaryPatch::apply(patch_byte *ptr, size_t len, bool newv)
{
    for (size_t i = 0; i < entries.size(); i++)
    {
        Byte &bv = entries[i];
        assert (bv.offset < len);

        ptr[bv.offset] = (newv ? bv.new_val : bv.old_val);
    }
}

bool load_file(std::vector<patch_byte> *pvec, std::string fname)
{
    FILE *f = fopen(fname.c_str(), "rb");
    if (!f)
    {
        cerr << "Cannot open file: " << fname << endl;
        return false;
    }

    fseek(f, 0, SEEK_END);
    pvec->resize(ftell(f));
    fseek(f, 0, SEEK_SET);
    size_t cnt = fread(pvec->data(), 1, pvec->size(), f);
    fclose(f);

    return cnt == pvec->size();
}

{
    FILE *f = fopen(fname.c_str(), "wb");
    if (!f)
    {
        cerr << "Cannot open file: " << fname << endl;
        return false;
    }

    size_t cnt = fwrite(pvec.data(), 1, pvec.size(), f);
    fclose(f);

    return cnt == pvec.size();
}

std::string compute_hash(const std::vector<patch_byte> &pvec)
{
    md5wrapper md5;
    return md5.getHashFromBytes(pvec.data(), pvec.size());
}

int main (int argc, char *argv[])
{
    if (argc <= 3)
    {
        cerr << "Usage: binpatch check|apply|remove <exe> <patch>" << endl;
        return 2;
    }

    std::string cmd = argv[1];

    if (cmd != "check" && cmd != "apply" && cmd != "remove")
    {
        cerr << "Invalid command: " << cmd << endl;
        return 2;
    }

    std::string exe_file = argv[2];
    std::vector<patch_byte> bindata;
    if (!load_file(&bindata, exe_file))
        return 2;

    BinaryPatch patch;
    if (!patch.loadDIF(argv[3]))
        return 2;

    BinaryPatch::State state = patch.checkState(bindata.data(), bindata.size());
    if (state == BinaryPatch::Conflict)
        return 1;

    if (cmd == "check")
    {
        switch (state)
        {
        case BinaryPatch::Unapplied:
            cout << "Currently not applied." << endl;
            break;
        case BinaryPatch::Applied:
            cout << "Currently applied." << endl;
            break;
        case BinaryPatch::Partial:
            cout << "Currently partially applied." << endl;
            break;
        default:
            break;
        }

        return 0;
    }
    else if (cmd == "apply")
    {
        if (state == BinaryPatch::Applied)
        {
            cout << "Already applied." << endl;
            return 0;
        }

        patch.apply(bindata.data(), bindata.size(), true);
    }
    else if (cmd == "remove")
    {
        if (state == BinaryPatch::Unapplied)
        {
            cout << "Already removed." << endl;
            return 0;
        }

        patch.apply(bindata.data(), bindata.size(), false);
    }

    if (!save_file(bindata, exe_file + ".bak"))
    {
        cerr << "Could not create backup." << endl;
        return 1;
    }

    if (!save_file(bindata, exe_file))
        return 1;

    cout << "Patched " << patch.entries.size()
         << " bytes, new hash: " << compute_hash(bindata) << endl;
    return 0;
}


{
    md5wrapper md5;
    return md5.getHashFromBytes(pvec.data(), pvec.size());
}

/*
http://example.com

A thread-safe logging console with a line editor for windows.

Based on linenoise win32 port,
All rights reserved.
The original linenoise can be found at: http://example.com

*/

#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include <stdint.h>

#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <vector>

#include <memory>

#include <md5wrapper.h>

using std::cout;
using std::cerr;
using std::endl;

typedef unsigned char patch_byte;

struct BinaryPatch {
    struct Byte {
        unsigned offset;
        patch_byte old_val, new_val;
    };
    enum State {
        Conflict = 0,
        Unapplied = 1,
        Applied = 2,
        Partial = 3
    };

    std::vector<Byte> entries;

    bool loadDIF(std::string name);
    State checkState(const patch_byte *ptr, size_t len);

    void apply(patch_byte *ptr, size_t len, bool newv);
};

inline bool is_hex(char c)
{
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}

bool BinaryPatch::loadDIF(std::string name)
{
    entries.clear();

    std::ifstream infile(name);
    if(infile.bad())
    {
        cerr << "Cannot open file: " << name << endl;
        return false;
    }

    std::string s;
    while(std::getline(infile, s))
    {
        // Parse lines that begin with "[0-9a-f]+:"
        size_t idx = s.find(':');
        if (idx == std::string::npos || idx == 0 || idx > 8)
            continue;

        bool ok = true;
        for (size_t i = 0; i < idx; i++)
            if (!is_hex(s[i]))
                ok = false;
        if (!ok)
            continue;

        unsigned off, oval, nval;
        int nchar = 0;
        int cnt = sscanf(s.c_str(), "%x: %x %x%n", &off, &oval, &nval, &nchar);

        if (cnt < 3)
        {
            cerr << "Could not parse: " << s << endl;
            return false;
        }

        for (size_t i = nchar; i < s.size(); i++)
        {
            if (!isspace(s[i]))
            {
                cerr << "Garbage at end of line: " << s << endl;
                return false;
            }
        }

        if (oval >= 256 || nval >= 256)
        {
            cerr << "Invalid byte values: " << s << endl;
            return false;
        }

        Byte bv = { off, patch_byte(oval), patch_byte(nval) };
        entries.push_back(bv);
    }

    if (entries.empty())
    {
        cerr << "No lines recognized." << endl;
        return false;
    }

    return true;
}

BinaryPatch::State BinaryPatch::checkState(const patch_byte *ptr, size_t len)
{
    int state = 0;

    for (size_t i = 0; i < entries.size(); i++)
    {
        Byte &bv = entries[i];

        if (bv.offset >= len)
        {
            cerr << "Offset out of range: 0x" << std::hex << bv.offset << std::dec << endl;
            return Conflict;
        }

        patch_byte cv = ptr[bv.offset];
        if (bv.old_val == cv)
            state |= Unapplied;
        else if (bv.new_val == cv)
            state |= Applied;
        else
        {
            cerr << std::hex << bv.offset << ": "
                 << unsigned(bv.old_val) << " " << unsigned(bv.new_val)
                 << ", but currently " << unsigned(cv) << std::dec << endl;
            return Conflict;
        }
    }

    return State(state);
}

void BinaryPatch::apply(patch_byte *ptr, size_t len, bool newv)
{
    for (size_t i = 0; i < entries.size(); i++)
    {
        Byte &bv = entries[i];
        assert (bv.offset < len);

        ptr[bv.offset] = (newv ? bv.new_val : bv.old_val);
    }
}

bool load_file(std::vector<patch_byte> *pvec, std::string fname)
{
    FILE *f = fopen(fname.c_str(), "rb");
    if (!f)
    {
        cerr << "Cannot open file: " << fname << endl;
        return false;
    }

    fseek(f, 0, SEEK_END);
    pvec->resize(ftell(f));
    fseek(f, 0, SEEK_SET);
    size_t cnt = fread(pvec->data(), 1, pvec->size(), f);
    fclose(f);

    return cnt == pvec->size();
}

bool save_file(const std::vector<patch_byte> &pvec, std::string fname)
{
    FILE *f = fopen(fname.c_str(), "wb");
    if (!f)
    {
        cerr << "Cannot open file: " << fname << endl;
        return false;
    }

    size_t cnt = fwrite(pvec.data(), 1, pvec.size(), f);
    fclose(f);

    return cnt == pvec.size();
}

std::string compute_hash(const std::vector<patch_byte> &pvec)

int main (int argc, char *argv[])
{
    if (argc <= 3)
    {
        cerr << "Usage: binpatch check|apply|remove <exe> <patch>" << endl;
        return 2;
    }

    std::string cmd = argv[1];

    if (cmd != "check" && cmd != "apply" && cmd != "remove")
    {
        cerr << "Invalid command: " << cmd << endl;
        return 2;
    }

    std::string exe_file = argv[2];
    std::vector<patch_byte> bindata;
    if (!load_file(&bindata, exe_file))
        return 2;

    BinaryPatch patch;
    if (!patch.loadDIF(argv[3]))
        return 2;

    BinaryPatch::State state = patch.checkState(bindata.data(), bindata.size());
    if (state == BinaryPatch::Conflict)
        return 1;

    if (cmd == "check")
    {
        switch (state)
        {
        case BinaryPatch::Unapplied:
            cout << "Currently not applied." << endl;
            break;
        case BinaryPatch::Applied:
            cout << "Currently applied." << endl;
            break;
        case BinaryPatch::Partial:
            cout << "Currently partially applied." << endl;
            break;
        default:
            break;
        }

        return 0;
    }
    else if (cmd == "apply")
    {
        if (state == BinaryPatch::Applied)
        {
            cout << "Already applied." << endl;
            return 0;
        }

        patch.apply(bindata.data(), bindata.size(), true);
    }
    else if (cmd == "remove")
    {
        if (state == BinaryPatch::Unapplied)
        {
            cout << "Already removed." << endl;
            return 0;
        }

        patch.apply(bindata.data(), bindata.size(), false);
    }

    if (!save_file(bindata, exe_file + ".bak"))
    {
        cerr << "Could not create backup." << endl;
        return 1;
    }

    if (!save_file(bindata, exe_file))
        return 1;

    cout << "Patched " << patch.entries.size()
         << " bytes, new hash: " << compute_hash(bindata) << endl;
    return 0;
}


{
    FILE *f = fopen(fname.c_str(), "wb");
    if (!f)
    {
        cerr << "Cannot open file: " << fname << endl;
        return false;
    }

/*
http://example.com

A thread-safe logging console with a line editor for windows.

Based on linenoise win32 port,
All rights reserved.
The original linenoise can be found at: http://example.com

*/

#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include <stdint.h>

#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <vector>

#include <memory>

#include <md5wrapper.h>

using std::cout;
using std::cerr;
using std::endl;

typedef unsigned char patch_byte;

struct BinaryPatch {
    struct Byte {
        unsigned offset;
        patch_byte old_val, new_val;
    };
    enum State {
        Conflict = 0,
        Unapplied = 1,
        Applied = 2,
        Partial = 3
    };

    std::vector<Byte> entries;

    bool loadDIF(std::string name);
    State checkState(const patch_byte *ptr, size_t len);

    void apply(patch_byte *ptr, size_t len, bool newv);
};

inline bool is_hex(char c)
{
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}

bool BinaryPatch::loadDIF(std::string name)
{
    entries.clear();

    std::ifstream infile(name);
    if(infile.bad())
    {
        cerr << "Cannot open file: " << name << endl;
        return false;
    }

    std::string s;
    while(std::getline(infile, s))
    {
        // Parse lines that begin with "[0-9a-f]+:"
        size_t idx = s.find(':');
        if (idx == std::string::npos || idx == 0 || idx > 8)
            continue;

        bool ok = true;
        for (size_t i = 0; i < idx; i++)
            if (!is_hex(s[i]))
                ok = false;
        if (!ok)
            continue;

        unsigned off, oval, nval;
        int nchar = 0;
        int cnt = sscanf(s.c_str(), "%x: %x %x%n", &off, &oval, &nval, &nchar);

        if (cnt < 3)
        {
            cerr << "Could not parse: " << s << endl;
            return false;
        }

        for (size_t i = nchar; i < s.size(); i++)
        {
            if (!isspace(s[i]))
            {
                cerr << "Garbage at end of line: " << s << endl;
                return false;
            }
        }

        if (oval >= 256 || nval >= 256)
        {
            cerr << "Invalid byte values: " << s << endl;
            return false;
        }

        Byte bv = { off, patch_byte(oval), patch_byte(nval) };
        entries.push_back(bv);
    }

    if (entries.empty())
    {
        cerr << "No lines recognized." << endl;
        return false;
    }

    return true;
}

BinaryPatch::State BinaryPatch::checkState(const patch_byte *ptr, size_t len)
{
    int state = 0;

    for (size_t i = 0; i < entries.size(); i++)
    {
        Byte &bv = entries[i];

        if (bv.offset >= len)
        {
            cerr << "Offset out of range: 0x" << std::hex << bv.offset << std::dec << endl;
            return Conflict;
        }

        patch_byte cv = ptr[bv.offset];
        if (bv.old_val == cv)
            state |= Unapplied;
        else if (bv.new_val == cv)
            state |= Applied;
        else
        {
            cerr << std::hex << bv.offset << ": "
                 << unsigned(bv.old_val) << " " << unsigned(bv.new_val)
                 << ", but currently " << unsigned(cv) << std::dec << endl;
            return Conflict;
        }
    }

    return State(state);
}

void BinaryPatch::apply(patch_byte *ptr, size_t len, bool newv)
{
    for (size_t i = 0; i < entries.size(); i++)
    {
        Byte &bv = entries[i];
        assert (bv.offset < len);

        ptr[bv.offset] = (newv ? bv.new_val : bv.old_val);
    }
}

bool load_file(std::vector<patch_byte> *pvec, std::string fname)
{
    FILE *f = fopen(fname.c_str(), "rb");
    if (!f)
    {
        cerr << "Cannot open file: " << fname << endl;
        return false;
    }

    fseek(f, 0, SEEK_END);
    pvec->resize(ftell(f));
    fseek(f, 0, SEEK_SET);
    size_t cnt = fread(pvec->data(), 1, pvec->size(), f);
    fclose(f);

    return cnt == pvec->size();
}

bool save_file(const std::vector<patch_byte> &pvec, std::string fname)

    size_t cnt = fwrite(pvec.data(), 1, pvec.size(), f);
    fclose(f);

    return cnt == pvec.size();
}

std::string compute_hash(const std::vector<patch_byte> &pvec)
{
    md5wrapper md5;
    return md5.getHashFromBytes(pvec.data(), pvec.size());
}

int main (int argc, char *argv[])
{
    if (argc <= 3)
    {
        cerr << "Usage: binpatch check|apply|remove <exe> <patch>" << endl;
        return 2;
    }

    std::string cmd = argv[1];

    if (cmd != "check" && cmd != "apply" && cmd != "remove")
    {
        cerr << "Invalid command: " << cmd << endl;
        return 2;
    }

    std::string exe_file = argv[2];
    std::vector<patch_byte> bindata;
    if (!load_file(&bindata, exe_file))
        return 2;

    BinaryPatch patch;
    if (!patch.loadDIF(argv[3]))
        return 2;

    BinaryPatch::State state = patch.checkState(bindata.data(), bindata.size());
    if (state == BinaryPatch::Conflict)
        return 1;

    if (cmd == "check")
    {
        switch (state)
        {
        case BinaryPatch::Unapplied:
            cout << "Currently not applied." << endl;
            break;
        case BinaryPatch::Applied:
            cout << "Currently applied." << endl;
            break;
        case BinaryPatch::Partial:
            cout << "Currently partially applied." << endl;
            break;
        default:
            break;
        }

        return 0;
    }
    else if (cmd == "apply")
    {
        if (state == BinaryPatch::Applied)
        {
            cout << "Already applied." << endl;
            return 0;
        }

        patch.apply(bindata.data(), bindata.size(), true);
    }
    else if (cmd == "remove")
    {
        if (state == BinaryPatch::Unapplied)
        {
            cout << "Already removed." << endl;
            return 0;
        }

        patch.apply(bindata.data(), bindata.size(), false);
    }

    if (!save_file(bindata, exe_file + ".bak"))
    {
        cerr << "Could not create backup." << endl;
        return 1;
    }

    if (!save_file(bindata, exe_file))
        return 1;

    cout << "Patched " << patch.entries.size()
         << " bytes, new hash: " << compute_hash(bindata) << endl;
    return 0;
}


size_t cnt = fwrite(pvec.data(), 1, pvec.size(), f);
    fclose(f);

/*
http://example.com

A thread-safe logging console with a line editor for windows.

Based on linenoise win32 port,
All rights reserved.
The original linenoise can be found at: http://example.com

*/

#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include <stdint.h>

#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <vector>

#include <memory>

#include <md5wrapper.h>

using std::cout;
using std::cerr;
using std::endl;

typedef unsigned char patch_byte;

struct BinaryPatch {
    struct Byte {
        unsigned offset;
        patch_byte old_val, new_val;
    };
    enum State {
        Conflict = 0,
        Unapplied = 1,
        Applied = 2,
        Partial = 3
    };

    std::vector<Byte> entries;

    bool loadDIF(std::string name);
    State checkState(const patch_byte *ptr, size_t len);

    void apply(patch_byte *ptr, size_t len, bool newv);
};

inline bool is_hex(char c)
{
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}

bool BinaryPatch::loadDIF(std::string name)
{
    entries.clear();

    std::ifstream infile(name);
    if(infile.bad())
    {
        cerr << "Cannot open file: " << name << endl;
        return false;
    }

    std::string s;
    while(std::getline(infile, s))
    {
        // Parse lines that begin with "[0-9a-f]+:"
        size_t idx = s.find(':');
        if (idx == std::string::npos || idx == 0 || idx > 8)
            continue;

        bool ok = true;
        for (size_t i = 0; i < idx; i++)
            if (!is_hex(s[i]))
                ok = false;
        if (!ok)
            continue;

        unsigned off, oval, nval;
        int nchar = 0;
        int cnt = sscanf(s.c_str(), "%x: %x %x%n", &off, &oval, &nval, &nchar);

        if (cnt < 3)
        {
            cerr << "Could not parse: " << s << endl;
            return false;
        }

        for (size_t i = nchar; i < s.size(); i++)
        {
            if (!isspace(s[i]))
            {
                cerr << "Garbage at end of line: " << s << endl;
                return false;
            }
        }

        if (oval >= 256 || nval >= 256)
        {
            cerr << "Invalid byte values: " << s << endl;
            return false;
        }

        Byte bv = { off, patch_byte(oval), patch_byte(nval) };
        entries.push_back(bv);
    }

    if (entries.empty())
    {
        cerr << "No lines recognized." << endl;
        return false;
    }

    return true;
}

BinaryPatch::State BinaryPatch::checkState(const patch_byte *ptr, size_t len)
{
    int state = 0;

    for (size_t i = 0; i < entries.size(); i++)
    {
        Byte &bv = entries[i];

        if (bv.offset >= len)
        {
            cerr << "Offset out of range: 0x" << std::hex << bv.offset << std::dec << endl;
            return Conflict;
        }

        patch_byte cv = ptr[bv.offset];
        if (bv.old_val == cv)
            state |= Unapplied;
        else if (bv.new_val == cv)
            state |= Applied;
        else
        {
            cerr << std::hex << bv.offset << ": "
                 << unsigned(bv.old_val) << " " << unsigned(bv.new_val)
                 << ", but currently " << unsigned(cv) << std::dec << endl;
            return Conflict;
        }
    }

    return State(state);
}

void BinaryPatch::apply(patch_byte *ptr, size_t len, bool newv)
{
    for (size_t i = 0; i < entries.size(); i++)
    {
        Byte &bv = entries[i];
        assert (bv.offset < len);

        ptr[bv.offset] = (newv ? bv.new_val : bv.old_val);
    }
}

bool load_file(std::vector<patch_byte> *pvec, std::string fname)
{
    FILE *f = fopen(fname.c_str(), "rb");
    if (!f)
    {
        cerr << "Cannot open file: " << fname << endl;
        return false;
    }

    fseek(f, 0, SEEK_END);
    pvec->resize(ftell(f));
    fseek(f, 0, SEEK_SET);
    size_t cnt = fread(pvec->data(), 1, pvec->size(), f);
    fclose(f);

    return cnt == pvec->size();
}

bool save_file(const std::vector<patch_byte> &pvec, std::string fname)
{
    FILE *f = fopen(fname.c_str(), "wb");
    if (!f)
    {
        cerr << "Cannot open file: " << fname << endl;
        return false;
    }

    return cnt == pvec.size();
}

std::string compute_hash(const std::vector<patch_byte> &pvec)
{
    md5wrapper md5;
    return md5.getHashFromBytes(pvec.data(), pvec.size());
}

int main (int argc, char *argv[])
{
    if (argc <= 3)
    {
        cerr << "Usage: binpatch check|apply|remove <exe> <patch>" << endl;
        return 2;
    }

    std::string cmd = argv[1];

    if (cmd != "check" && cmd != "apply" && cmd != "remove")
    {
        cerr << "Invalid command: " << cmd << endl;
        return 2;
    }

    std::string exe_file = argv[2];
    std::vector<patch_byte> bindata;
    if (!load_file(&bindata, exe_file))
        return 2;

    BinaryPatch patch;
    if (!patch.loadDIF(argv[3]))
        return 2;

    BinaryPatch::State state = patch.checkState(bindata.data(), bindata.size());
    if (state == BinaryPatch::Conflict)
        return 1;

    if (cmd == "check")
    {
        switch (state)
        {
        case BinaryPatch::Unapplied:
            cout << "Currently not applied." << endl;
            break;
        case BinaryPatch::Applied:
            cout << "Currently applied." << endl;
            break;
        case BinaryPatch::Partial:
            cout << "Currently partially applied." << endl;
            break;
        default:
            break;
        }

        return 0;
    }
    else if (cmd == "apply")
    {
        if (state == BinaryPatch::Applied)
        {
            cout << "Already applied." << endl;
            return 0;
        }

        patch.apply(bindata.data(), bindata.size(), true);
    }
    else if (cmd == "remove")
    {
        if (state == BinaryPatch::Unapplied)
        {
            cout << "Already removed." << endl;
            return 0;
        }

        patch.apply(bindata.data(), bindata.size(), false);
    }

    if (!save_file(bindata, exe_file + ".bak"))
    {
        cerr << "Could not create backup." << endl;
        return 1;
    }

    if (!save_file(bindata, exe_file))
        return 1;

    cout << "Patched " << patch.entries.size()
         << " bytes, new hash: " << compute_hash(bindata) << endl;
    return 0;
}