/*
** Test of sqlite_encode_binary() and sqlite_decode_binary().
*/
#include "sqlite.h"
#include <assert.h>
#include <malloc.h>
#include <stdlib.h>
#include <memory.h>

int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out);
int sqlite_decode_binary(const unsigned char *in, unsigned char *out);

/***********************************************************************/

/*
** Compute the maximum size required by sqlite_encode_binary().
** This doesn't include the NUL byte which terminates the string.
*/
int sqaux_encode_maxsize(int datasize)
{
  int nEncMax = (256*datasize + 1262)/253;
  return nEncMax;
}

/*
** Empty callback function needed to call sqlite_exec(),
**   which won't accept NULL for the callback argument.
** Return zero on success, non-zero on failure.
*/
int callback_dummy(void *pArg, int nArg, char **azArg, char **azCol)
{
  return 0;
}

/***********************************************************************/

#define DATASIZE 1024
char decdata1[DATASIZE];

/*
** Test behavior of the sqlite_encode_binary() functions.
*/
int main()
{
  int i;
  int encsize1, decsize1, maxsize1;
  int encsize2, decsize2;
  char *encdata1 = 0, *encdata2 = 0;
  char *decdata2 = 0;
  sqlite *db = 0;
  int rc = -1, nRow, nCol;
  char **result = 0;

  /* Open a test database. */
  db = sqlite_open("enctest.db", 0, 0);
  if (db == 0)
    goto error;
  rc = sqlite_exec(db, "CREATE TABLE encoded (encsize INTEGER, encdata STRING);", callback_dummy, 0, 0);
  if (rc != SQLITE_OK)
    goto error;

  /***************************************/

  /* Fill the data array with a linear permutation of bytes 0-255.
  ** This will contain all bytes, including '\0' and apostrophe.
  */
  decsize1 = DATASIZE;
  for(i=0; i<decsize1; i++)
    decdata1[i] = (5 + i*37) & 255; /* (37 and 256 are coprime) */

  maxsize1 = sqaux_encode_maxsize(decsize1);
  encdata1 = malloc(maxsize1+1);
  if( malloc == 0)
    goto error;

  encsize1 = sqlite_encode_binary(decdata1, decsize1, encdata1);
  assert(encsize1 <= maxsize1);

  /***************************************/

  /* Insert the encoded data into the database. */
  rc = sqlite_exec_printf(db, "INSERT INTO encoded VALUES('%d', '%s');", callback_dummy, 0, 0, encsize1, encdata1);
  if (rc != SQLITE_OK)
    goto error;

  /***************************************/

  /* Retrieve the encoded data from the database. */
  rc = sqlite_get_table(db, "SELECT encsize, encdata FROM encoded;", &result, &nRow, &nCol, 0);
  if (rc != SQLITE_OK || nRow < 1 || nCol != 2)
    goto error;

  encsize2 = atol(result[2]);
  encdata2 = result[3];
  assert(encsize2 == encsize1);

  /* Verify that the encoded data is unchanged. */
  assert(memcmp(encdata1, encdata2, encsize2) == 0);
  
  /***************************************/

  /* Decode the encoded data. */

  decdata2 = malloc(encsize2);
  decsize2 = sqlite_decode_binary(encdata2, decdata2);

  /* Reallocate down to original size. */
  decdata2 = realloc(decdata2, decsize2);

  /* Verify that the decoded data is unchanged. */
  assert(memcmp(decdata1, decdata2, decsize2) == 0);

  /***************************************/

error:
  /* Free the encoded data. */
  free(encdata1);
  /* encdata2 is freed by sqlite_free_table(). */
  /* decdata1 is statically allocated. */
  free(decdata2);

  sqlite_free_table(result);
  sqlite_close(db);

  return rc; /* okay */
}
