/*-
 ***********************************************************************
 *
 * $Id: string2pool.c,v 1.4 2006/05/25 22:17:28 mavrik Exp $
 *
 ***********************************************************************
 *
 * Copyright 2002-2006 Klayton Monroe, All Rights Reserved.
 *
 ***********************************************************************
 */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/types.h>
#endif

/*-
 ***********************************************************************
 *
 * Defines
 *
 ***********************************************************************
 */
#ifdef WIN32
#define strcasecmp _stricmp
#endif

#define PROGRAM           "string2pool"
#define STRING2POOL_MAX_TRIES       10
#define STRING2POOL_POOL_SIZE   0x8000
#define STRING2POOL_PREFIX_SIZE     32
#define STRING2POOL_SUFFIX_SIZE     32


/*-
 ***********************************************************************
 *
 * Macros
 *
 ***********************************************************************
 */
#define STRING2POOL_NEW_POOL(aucPool, iLength, ulState)\
{\
  int i, j;\
  unsigned long ul = ulState;\
  for (i = 0; i < iLength; i++)\
  {\
    for (j = 0, aucPool[i] = 0; j < 8; j++)\
    {\
      aucPool[i] |= (ul & 1) << j;\
      ul = ((((ul >> 7) ^ (ul >> 6) ^ (ul >> 2) ^ (ul >> 0)) & 1) << 31) | (ul >> 1);\
    }\
  }\
  ulState = ul; /* Return the last register state -- allows the caller to continue the sequence. */\
}


/*-
 ***********************************************************************
 *
 * ConstructIncludeFile
 *
 ***********************************************************************
 */
void
ConstructIncludeFile(FILE *pFile, char *pcPoolType, unsigned long ulFinal, int *piTaps, int iTapsCount)
{
  char                acPrefix[STRING2POOL_PREFIX_SIZE];
  char                acSuffix[STRING2POOL_SUFFIX_SIZE];
  int                 i;

  for (i = 0; i < (int)strlen(pcPoolType); i++)
  {
    acPrefix[i] = tolower((int)pcPoolType[i]);
  }
  acPrefix[i] = 0;

  if (strcasecmp(pcPoolType, "POOL2STRING") == 0)
  {
    acSuffix[0] = 0;
  }
  else
  {
    strcpy(acSuffix, "-pool");
  }

  fprintf(pFile, "/*\n");
  fprintf(pFile, " ***********************************************************************\n");
  fprintf(pFile, " *\n");
  fprintf(pFile, " * $%s: %s%s.h,v custom unknown Exp $\n", "Id", acPrefix, acSuffix);
  fprintf(pFile, " *\n");
  fprintf(pFile, " ***********************************************************************\n");
  fprintf(pFile, " *\n");
  fprintf(pFile, " * Copyright 2003-2006 Klayton Monroe, All Rights Reserved.\n");
  fprintf(pFile, " *\n");
  fprintf(pFile, " ***********************************************************************\n");
  fprintf(pFile, " */\n");
  fprintf(pFile, "\n");
  fprintf(pFile, "/*\n");
  fprintf(pFile, " ***********************************************************************\n");
  fprintf(pFile, " *\n");
  fprintf(pFile, " * Defines\n");
  fprintf(pFile, " *\n");
  fprintf(pFile, " ***********************************************************************\n");
  fprintf(pFile, " */\n");
  fprintf(pFile, "#define %s_POOL_SEED 0x%08lx\n", pcPoolType, ulFinal);
  fprintf(pFile, "#define %s_POOL_SIZE 0x%08x\n", pcPoolType, STRING2POOL_POOL_SIZE);
  fprintf(pFile, "#define %s_POOL_TAPS (%d) + (1)\n", pcPoolType, iTapsCount);
  fprintf(pFile, "\n\n");
  fprintf(pFile, "/*\n");
  fprintf(pFile, " ***********************************************************************\n");
  fprintf(pFile, " *\n");
  fprintf(pFile, " * Macros\n");
  fprintf(pFile, " *\n");
  fprintf(pFile, " ***********************************************************************\n");
  fprintf(pFile, " */\n");
  fprintf(pFile, "#define %s_NEW_POOL(aucPool, iLength, ulState)\\\n", pcPoolType);
  fprintf(pFile, "{\\\n");
  fprintf(pFile, "  int i, j;\\\n");
  fprintf(pFile, "  unsigned long ul = ulState;\\\n");
  fprintf(pFile, "  for (i = 0; i < iLength; i++)\\\n");
  fprintf(pFile, "  {\\\n");
  fprintf(pFile, "    for (j = 0, aucPool[i] = 0; j < 8; j++)\\\n");
  fprintf(pFile, "    {\\\n");
  fprintf(pFile, "      aucPool[i] |= (ul & 1) << j;\\\n");
  fprintf(pFile, "      ul = ((((ul >> 7) ^ (ul >> 6) ^ (ul >> 2) ^ (ul >> 0)) & 1) << 31) | (ul >> 1);\\\n");
  fprintf(pFile, "    }\\\n");
  fprintf(pFile, "  }\\\n");
  fprintf(pFile, "}\n");
  fprintf(pFile, "\n");
  fprintf(pFile, "#define %s_TAP_POOL(aucTaps, aucPool)\\\n", pcPoolType);
  fprintf(pFile, "{\\\n");
  if (iTapsCount > 0)
  {
    fprintf(pFile, "  if (%s_POOL_SEED == 0x%08lx && %s_POOL_SIZE == 0x%08x && %s_POOL_TAPS == %d)\\\n",
            pcPoolType,
            ulFinal,
            pcPoolType,
            STRING2POOL_POOL_SIZE,
            pcPoolType,
            iTapsCount + 1
           );
    fprintf(pFile, "  {\\\n");
    for (i = 0; piTaps && i < iTapsCount; i++)
    {
      fprintf(pFile, "    aucTaps[%d] = aucPool[%d];\\\n", i, piTaps[i]);
      fprintf(pFile, "    aucPool[%d] = 0;\\\n", i);
    }
    fprintf(pFile, "    aucTaps[%d] = 0;\\\n", i);
    fprintf(pFile, "  }\\\n");
    fprintf(pFile, "  else\\\n");
    fprintf(pFile, "  {\\\n");
    fprintf(pFile, "    aucTaps[0] = 0;\\\n");
    fprintf(pFile, "  }\\\n");
  }
  else
  {
    fprintf(pFile, "  aucTaps[0] = 0;\\\n");
  }
  fprintf(pFile, "}\n");
  return;
}


/*-
 ***********************************************************************
 *
 * Usage
 *
 ***********************************************************************
 */
void
Usage()
{
  fprintf(stderr, "\n");
  fprintf(stderr, "Usage: %s --default prefix\n", PROGRAM);
  fprintf(stderr, "       %s --defined prefix seed string\n", PROGRAM);
  fprintf(stderr, "\n");
  exit(1);
}


/*-
 ***********************************************************************
 *
 * Main
 *
 ***********************************************************************
 */
int
main(int iArgumentCount, char *ppcArgumentVector[])
{
  const char          acRoutine[] = "Main()";
  char                acPrefix[STRING2POOL_PREFIX_SIZE];
  char               *pcEnd;
  char               *pcString;
  int                 i;
  int                 iDone;
  int                 iStringLength;
  int                 iStringOffset;
  int                 iTries;
  int                *piTaps;
  unsigned char       aucPool[STRING2POOL_POOL_SIZE];
  unsigned long       ulSeed;
  unsigned long       ulFinal;
  unsigned long       ulState;

  /*-
   *********************************************************************
   *
   * Seed the random number generator.
   *
   *********************************************************************
   */
#ifdef WIN32
  ulSeed = (unsigned long) GetTickCount() ^ (unsigned long) time(NULL);
  srand(ulSeed);
#else
  ulSeed = (((unsigned long) getpid()) << 16) ^ (unsigned long) time(NULL);
  srandom(ulSeed);
#endif

  /*-
   *********************************************************************
   *
   * Process arguments.
   *
   *********************************************************************
   */
  if (iArgumentCount == 3)
  {
    if (strcasecmp(ppcArgumentVector[1], "--default") == 0)
    {
      if (strcasecmp(ppcArgumentVector[2], "HTTP") == 0)
      {
        strcpy(acPrefix, "HTTP");
      }
      else if (strcasecmp(ppcArgumentVector[2], "POOL") == 0)
      {
        strcpy(acPrefix, "POOL2STRING");
      }
      else if (strcasecmp(ppcArgumentVector[2], "SSL") == 0)
      {
        strcpy(acPrefix, "SSL");
      }
      else
      {
        fprintf(stderr, "%s: Prefix='%s': Prefix must be one of 'HTTP', 'POOL', or 'SSL'.\n", acRoutine, ppcArgumentVector[2]);
        return 2;
      }
      ConstructIncludeFile(stdout, acPrefix, 0, NULL, 0);
      return 0;
    }
    else
    {
      Usage();
    }
  }
  else if (iArgumentCount == 5)
  {
    if (strcasecmp(ppcArgumentVector[1], "--defined") == 0)
    {
      if (strcasecmp(ppcArgumentVector[2], "HTTP") == 0)
      {
        strcpy(acPrefix, "HTTP");
      }
      else if (strcasecmp(ppcArgumentVector[2], "POOL") == 0)
      {
        strcpy(acPrefix, "POOL2STRING");
      }
      else if (strcasecmp(ppcArgumentVector[2], "SSL") == 0)
      {
        strcpy(acPrefix, "SSL");
      }
      else
      {
        fprintf(stderr, "%s: Prefix='%s': Prefix must be one of 'HTTP', 'POOL', or 'SSL'.\n", acRoutine, ppcArgumentVector[2]);
        return 2;
      }
      if (ppcArgumentVector[3][0] != 0)
      {
        ulState = strtoul(ppcArgumentVector[3], &pcEnd, 16);
        if (*pcEnd != 0 || errno == ERANGE)
        {
          fprintf(stderr, "%s: Seed='%s': Value could not be converted to a 32 bit hex number.\n", acRoutine, ppcArgumentVector[3]);
          return 3;
        }
        if (ulState == 0)
        {
#ifdef WIN32
          ulState = (unsigned long) ((GetTickCount() << 16) ^ rand());
#else
          ulState = (unsigned long) random();
#endif
        }
      }
      else
      {
        fprintf(stderr, "%s: Seed='%s': Value must not be null.\n", acRoutine, ppcArgumentVector[3]);
        return 4;
      }
      pcString = ppcArgumentVector[4];
      iStringLength = strlen(pcString);
      if (iStringLength > (STRING2POOL_POOL_SIZE / 1024))
      {
        fprintf(stderr, "%s: PoolSize='%d' String='%s' Length='%d': Required Pool size is (Length * 1024).\n", acRoutine, STRING2POOL_POOL_SIZE, ppcArgumentVector[4], iStringLength);
        return 5;
      }
      piTaps = malloc(iStringLength * sizeof(int));
      if (piTaps == NULL)
      {
        fprintf(stderr, "%s: malloc(): %s\n", acRoutine, strerror(errno));
        return 6;
      }
    }
    else
    {
      Usage();
    }
  }
  else
  {
    Usage();
  }

  /*-
   *********************************************************************
   *
   * Locate a pool that contains the specified string.
   *
   *********************************************************************
   */
  for (iDone = iTries = iStringOffset = 0; !iDone && iTries < STRING2POOL_MAX_TRIES; iTries++, iStringOffset = 0)
  {
    ulFinal = ulState;
    STRING2POOL_NEW_POOL(aucPool, STRING2POOL_POOL_SIZE, ulState);
    for (i = 0; i < STRING2POOL_POOL_SIZE && iStringOffset < iStringLength; i++)
    {
      if (aucPool[i] == pcString[iStringOffset])
      {
        piTaps[iStringOffset++] = i;
      }
    }
    iDone = (iStringOffset == iStringLength) ? 1 : 0;
  }
  if (iTries >= STRING2POOL_MAX_TRIES)
  {
    fprintf(stderr, "%s: Tries='%d': Failed to locate a suitable pool within the given number of tries.\n", acRoutine, iTries);
    return 7;
  }

  /*-
   *********************************************************************
   *
   * Construct an include file and write it out.
   *
   *********************************************************************
   */
  ConstructIncludeFile(stdout, acPrefix, ulFinal, piTaps, iStringLength);

  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1