/*
 * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
 *
 * Permission to use, copy, modify, distribute, and sell this software and 
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names of
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
 * publicity relating to the software without the specific, prior written
 * permission of Sam Leffler and Silicon Graphics.
 * 
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 * 
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
 * OF THIS SOFTWARE.
 */

/*
 * TIFF Library
 *
 * Module to test _TIFFRewriteField().
 */

#include "tif_config.h"

#include <stdio.h>
#include <stdlib.h>

#ifdef HAVE_UNISTD_H 
# include <unistd.h> 
#endif 

#include "tiffio.h"
#include "tiffiop.h"

const uint32_t	length = 40;
const uint32_t	rows_per_strip = 1;

int test_packbits()

{
    TIFF	    *tif;
    int             i;
    unsigned char   buf[10] = {0,0,0,0,0,0,0,0,0,0};

    uint32_t width = 10;
    int  length = 20;
    const char *filename = "test_packbits.tif";

    /* Test whether we can write tags. */
    tif = TIFFOpen(filename, "w");

    if (!tif) {
        fprintf (stderr, "Can't create test TIFF file %s.\n", filename);
        return 1;
    }

    if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS)) {
        fprintf (stderr, "Can't set Compression tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width)) {
        fprintf (stderr, "Can't set ImageWidth tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length)) {
        fprintf (stderr, "Can't set ImageLength tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8)) {
        fprintf (stderr, "Can't set BitsPerSample tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1)) {
        fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip)) {
        fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
        fprintf (stderr, "Can't set PlanarConfiguration tag.\n");
        goto failure;
    }

    for (i = 0; i < length; i++ )
    {
        if( !TIFFWriteEncodedStrip( tif, i, buf, 10 ) )
        {
            fprintf (stderr, "Can't write image data.\n");
            goto failure;
        }
    }

    TIFFClose(tif);

    /* Test whether we can write tags. */

    tif = TIFFOpen(filename, "r+");

    if (!tif) {
        fprintf (stderr, "Can't create test TIFF file %s.\n", filename);
        return 1;
    }

    buf[3] = 17;
    buf[6] = 12;

    if( !TIFFWriteEncodedStrip( tif, 6, buf, 10 ) )
    {
        fprintf (stderr, "Can't write image data.\n");
        goto failure;
    }

    TIFFClose(tif);

    unlink(filename);

    return 0;

  failure:
    /* Something goes wrong; close file and return unsuccessful status. */
    TIFFClose(tif);
    /*  unlink(filename); */

    return 1;
    
}

/************************************************************************/
/*                            rewrite_test()                            */
/************************************************************************/
int rewrite_test(const char *filename, uint32_t width, int length, int bigtiff,
                 uint64_t base_value )

{
    TIFF		*tif;
    int			i;
    unsigned char	*buf;
    uint64_t		*rowoffset, *rowbytes;
    uint64_t		*upd_rowoffset = NULL;
    uint64_t		*upd_bytecount = NULL;

    buf = calloc(1, width);
    assert(buf);

    /* Test whether we can write tags. */
    if( bigtiff )
        tif = TIFFOpen(filename, "w8");
    else
        tif = TIFFOpen(filename, "w4");

    if (!tif) {
        fprintf (stderr, "Can't create test TIFF file %s.\n", filename);
        free(buf);
        return 1;
    }

    if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS)) {
        fprintf (stderr, "Can't set Compression tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width)) {
        fprintf (stderr, "Can't set ImageWidth tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length)) {
        fprintf (stderr, "Can't set ImageLength tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8)) {
        fprintf (stderr, "Can't set BitsPerSample tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1)) {
        fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip)) {
        fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
        goto failure;
    }
    if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
        fprintf (stderr, "Can't set PlanarConfiguration tag.\n");
        goto failure;
    }

    for (i = 0; i < length; i++ )
    {
        if( TIFFWriteScanline( tif, buf, i, 0 ) == -1 )
        {
            fprintf (stderr, "Can't write image data.\n");
            goto failure;
        }
    }

    TIFFClose(tif);
	
    /* Ok, now test whether we can read written values. */
    tif = TIFFOpen(filename, "r+");
    if (!tif) {
        fprintf (stderr, "Can't open test TIFF file %s.\n", filename);
        free(buf);
        return 1;
    }
        
    if( !TIFFGetField( tif, TIFFTAG_STRIPOFFSETS, &rowoffset ) )
    {
        fprintf (stderr, "Can't fetch STRIPOFFSETS.\n");
        goto failure;
    }
        
    if( !TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &rowbytes ) )
    {
        fprintf (stderr, "Can't fetch STRIPBYTECOUNTS.\n");
        goto failure;
    }

    upd_rowoffset = (uint64_t *) _TIFFmalloc(sizeof(uint64_t) * length);
    for( i = 0; i < length; i++ )
        upd_rowoffset[i] = base_value + i*width;

    if( !_TIFFRewriteField( tif, TIFFTAG_STRIPOFFSETS, TIFF_LONG8, 
                            length, upd_rowoffset ) )
    {
        fprintf (stderr, "Can't rewrite STRIPOFFSETS.\n");
        goto failure;
    }

    _TIFFfree( upd_rowoffset );
    upd_rowoffset = NULL;

    upd_bytecount = (uint64_t *) _TIFFmalloc(sizeof(uint64_t) * length);
    for( i = 0; i < length; i++ )
        upd_bytecount[i] = 100 + i*width;

    if( !_TIFFRewriteField( tif, TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG8, 
                            length, upd_bytecount ) )
    {
        fprintf (stderr, "Can't rewrite STRIPBYTECOUNTS.\n");
        goto failure;
    }

    _TIFFfree( upd_bytecount );
    upd_bytecount = NULL;

    TIFFClose(tif);

    /* Reopen file and read back to verify contents */

    tif = TIFFOpen(filename, "r");
    if (!tif) {
        fprintf (stderr, "Can't open test TIFF file %s.\n", filename);
        free(buf);
        return 1;
    }
        
    if( !TIFFGetField( tif, TIFFTAG_STRIPOFFSETS, &rowoffset ) )
    {
        fprintf (stderr, "Can't fetch STRIPOFFSETS.\n");
        goto failure;
    }
        
    for( i = 0; i < length; i++ )
    {
        uint64_t expect = base_value + i * width;

        if( rowoffset[i] != expect )
        {
            fprintf( stderr, 
                     "%s:STRIPOFFSETS[%d]: Got %X:%08X instead of %X:%08X.\n",
                     filename, i, 
                     (int) (rowoffset[i] >> 32), 
                     (int) (rowoffset[i]&0xFFFFFFFF), 
                     (int) (expect >> 32), 
                     (int) (expect & 0xFFFFFFFF) );
            goto failure;
        }
    }

    if( !TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &rowbytes ) )
    {
        fprintf (stderr, "Can't fetch STRIPBYTECOUNTS.\n");
        goto failure;
    }
        
    for( i = 0; i < length; i++ )
    {
        uint64_t expect = 100 + i * width;

        if( rowbytes[i] != expect )
        {
            fprintf( stderr, 
                     "%s:STRIPBYTECOUNTS[%d]: Got %X:%08X instead of %X:%08X.\n",
                     filename, i, 
                     (int) (rowbytes[i] >> 32), 
                     (int) (rowbytes[i] & 0xFFFFFFFF), 
                     (int) (expect >> 32), 
                     (int) (expect & 0xFFFFFFFF) );
            goto failure;
        }
    }

    TIFFClose( tif );
    free(buf);

    /* All tests passed; delete file and exit with success status. */
    unlink(filename);
    return 0;

  failure:
    /* Something goes wrong; close file and return unsuccessful status. */
    TIFFClose(tif);
    free(buf);
    if( upd_rowoffset != NULL )
    {
        _TIFFfree( upd_rowoffset );
    }
    if ( upd_bytecount != NULL )
    {
        _TIFFfree( upd_bytecount );
    }
    /*  unlink(filename); */

    return 1;
    
}

/************************************************************************/
/*                                main()                                */
/************************************************************************/
int
main(void)
{
    int failure = 0;

    failure |= test_packbits();

    /* test fairly normal use */
    failure |= rewrite_test( "rewrite1.tif", 10, 10, 0, 100 );
    failure |= rewrite_test( "rewrite2.tif", 10, 10, 1, 100 );

    /* test case of fitting all in directory entry */
    failure |= rewrite_test( "rewrite3.tif", 10, 1, 0, 100 );
    failure |= rewrite_test( "rewrite4.tif", 10, 1, 1, 100 );

    /* test with very large values that don't fit in 4bytes (bigtiff only) */
    failure |= rewrite_test( "rewrite5.tif", 10, 1000, 1, 0x6000000000ULL );
    failure |= rewrite_test( "rewrite6.tif", 10, 1, 1, 0x6000000000ULL );

    /* StripByteCounts on LONG */
    failure |= rewrite_test( "rewrite7.tif", 65536, 1, 0, 100 );
    failure |= rewrite_test( "rewrite8.tif", 65536, 2, 0, 100 );

    return failure;
}

/* vim: set ts=8 sts=8 sw=8 noet: */
