/**************************************************************************/
/*                                                                        */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com)          */
/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de>  */
/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de>                 */
/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de>                */
/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com)           */
/*                                                                        */
/* NXCOMPEXT, NX protocol compression and NX extensions to this software  */
/* are copyright of the aforementioned persons and companies.             */
/*                                                                        */
/* Redistribution and use of the present software is allowed according    */
/* to terms specified in the file LICENSE which comes in the source       */
/* distribution.                                                          */
/*                                                                        */
/* All rights reserved.                                                   */
/*                                                                        */
/* NOTE: This software has received contributions from various other      */
/* contributors, only the core maintainers and supporters are listed as   */
/* copyright holders. Please contact us, if you feel you should be listed */
/* as copyright holder, as well.                                          */
/*                                                                        */
/**************************************************************************/

#include <stdio.h>
#include <signal.h>

#include "os.h"

#include "Compext.h"

#include "Clean.h"

#define PANIC
#define WARNING
#undef  TEST
#undef  DEBUG

int CleanXYImage(XImage *image)
{
  int i, j, k, plane;

  int bitsToClean = (image -> bytes_per_line << 3) - image -> width - image -> xoffset;

  unsigned int bytesToClean = bitsToClean >> 3;

  bitsToClean &= 7;

  for (k = 0; k < image -> depth; k++)
  {
    plane = k * (image -> bytes_per_line * image -> height);

    for (i = 1; i <= image -> height; i++)
    {
      if (image -> byte_order == image -> bitmap_bit_order)
      {
        for (j = 1; j <= bytesToClean; j++)
        {
          image -> data[plane + i * (image -> bytes_per_line) - j] = 0x00;
        }
      }
      else
      {
        for (j = bytesToClean; j >= 1; j--)
        {
          image -> data[plane + i * (image -> bytes_per_line) - j] = 0x00;
        }
      }

      if (image -> bitmap_bit_order == MSBFirst)
      {
        image -> data[plane + i * (image -> bytes_per_line) - j] &= 0xff << bitsToClean;
      }
      else
      {
        image -> data[plane + i * (image -> bytes_per_line) - j] &= 0xff >> bitsToClean;
      }
    }
  }

  return 1;
}

int CleanZImage(XImage *image)
{
  unsigned int bytesToClean;
  unsigned int imageLength;

  #ifdef TEST
  fprintf(stderr, "*****CleanZImage: Going to clean image of [%d] bits per pixel.\n",
              image -> bits_per_pixel);
  #endif

  switch (image -> bits_per_pixel)
  {
    case 32:
    {
      /*
       * The caller should pay attention at extracting
       * the alpha channel prior to cleaning the image.
       * Cleaning an image which is carrying the alpha
       * channel will result in the image being treated
       * as fully transparent.
       */

      bytesToClean = image -> bytes_per_line * image -> height;

      #ifdef DEBUG
      fprintf(stderr, "*****CleanZImage: Cleaning [%d] bytes with bits per pixel [%d] "
                  "width [%d] bytes per line [%d] height [%d].\n", bytesToClean,
                      image -> bits_per_pixel, image -> width, image ->
                          bytes_per_line, image -> height);
      #endif

      if (image -> byte_order == LSBFirst)
      {
        for (int i = 3; i < bytesToClean; i += 4)
        {
          ((unsigned char *) image -> data)[i] = 0x00;
        }
      }
      else
      {
        for (int i = 0; i < bytesToClean; i += 4)
        {
          ((unsigned char *) image -> data)[i] = 0x00;
        }
      }

      break;
    }
    case 24:
    case 15:
    case 16:
    case 8:
    {
      bytesToClean = image -> bytes_per_line -
                           ((image -> width * image -> bits_per_pixel) >> 3);

      for (int i = 1; i <= image -> height; i++)
      {
        for (int j = bytesToClean; j > 0; j--)
        {
          ((unsigned char *) image -> data)[(i * image -> bytes_per_line) - j] = 0x00;
        }
      }

      break;
    }
    default:
    {
      #ifdef PANIC
      fprintf(stderr, "*****CleanZImage: PANIC! Cannot clean image with [%d] bits per pixel.\n",
                  image -> bits_per_pixel);
      #endif
    }
  }

  /* 
   * Clean the padding bytes at the real
   * end of the buffer.
   */

  imageLength = image -> bytes_per_line * image -> height;

  bytesToClean = imageLength % 4;

  for (int j = 0; j < bytesToClean; j++)
  {
    ((unsigned char *)image -> data)[(imageLength + j)] = 0x00;
  }

  return 1;
}

/*
 * Copy a clean version of src_image into dst_image.
 * This code is not taking care of the image format.
 * The agent doesn't use it and you have to consider
 * it unsupported.
 */

int CopyAndCleanImage(XImage *src_image, XImage *dst_image)
{
  register long data_size;

  data_size = (src_image -> bytes_per_line * src_image -> height) >> 2;

  #ifdef WARNING
  fprintf(stderr, "******CleanImage: WARNING! Function called with image of [%d] bits per pixel.\n",
              src_image -> bits_per_pixel);
  #endif

  switch (src_image -> bits_per_pixel)
  {
    case 32:
    {
      unsigned int mask;

      if (src_image -> byte_order == MSBFirst)
      {
        mask = 0xffffff00;
      }
      else
      {
        mask = 0x00ffffff;
      }
      for (int i = 0; i < data_size; i++)
      {
        ((unsigned int *)dst_image -> data)[i] = ((unsigned int *)src_image -> data)[i] & mask;
      }

      break;
    }

    case 24:
    {
      unsigned int bytes_to_clean;

      for (int i = 0; i < data_size; i++)
      {
        ((unsigned int *)dst_image -> data)[i] = ((unsigned int *)src_image -> data)[i];
      }

      bytes_to_clean = dst_image -> bytes_per_line - ((dst_image -> width *
                           dst_image -> bits_per_pixel) >> 3);

      if (bytes_to_clean)
      {
        register unsigned int mask = 0xffffffff;
        register int line_size;

        line_size = dst_image -> bytes_per_line >> 2;

        if (dst_image -> byte_order == MSBFirst)
        {
          mask = mask << (bytes_to_clean << 3);
        }
        else
        {
          mask = mask >> (bytes_to_clean << 3);
        }

        for (int i = 0; i < dst_image -> height;)
        {
          ((unsigned char *)dst_image -> data)[(++i * line_size) -1] &= mask;
        }
      }

      break;
    }

    case 15:
    case 16:
    {
      for (int i = 0; i < data_size; i++)
      {
        ((unsigned int *) dst_image -> data)[i] = ((unsigned int *) src_image -> data)[i];
      }

      if (src_image -> width & 0x00000001)
      {
        int card32_per_line = dst_image -> bytes_per_line >> 2;

        for (int i = 0; i < dst_image -> height;)
        {
          ((unsigned int *) dst_image -> data)[(++i * card32_per_line) -1] &= 0x0000ffff;
        }
      }

      break;
    }

    case 8:
    {
      unsigned int mask = 0x00000000;

      switch (dst_image -> width % 4)
      {
        case 3:
        {
          mask = 0x00ffffff;

          break;
        }
        case 2:
        {
          mask = 0x0000ffff;

          break;
        }
        case 1:
        {
          mask = 0x000000ff;

          break;
        }
        default:
        {
          /*
           * Nothing to clean.
           */

          break;
        }
      }

      for (int i = 0; i < data_size; i++)
      {
        ((unsigned int *) dst_image -> data)[i] = ((unsigned int *) src_image -> data)[i];
      }

      if (mask)
      {
        int card32_per_line;

        card32_per_line = dst_image -> bytes_per_line >> 2;

        for (int i = 0; i < dst_image -> height; i++)
        {
          ((unsigned int *) dst_image -> data)[(++i * card32_per_line) -1] &= mask;
        }
      }

      break;
    }

    default:
    {
      #ifdef PANIC
      fprintf(stderr, "******CleanImage: PANIC! Cannot clean image of [%d] bits per pixel.\n",
                  src_image -> bits_per_pixel);
      #endif

      return 0;
    }
  }

  return 1;
}
