/*
 *                         Vortex OpenSplice
 *
 *   This software and documentation are Copyright 2006 to TO_YEAR ADLINK
 *   Technology Limited, its affiliated companies and licensors. All rights
 *   reserved.
 *
 *   Licensed under the ADLINK Software License Agreement Rev 2.7 2nd October
 *   2014 (the "License"); you may not use this file except in compliance with
 *   the License.
 *   You may obtain a copy of the License at:
 *                      $OSPL_HOME/LICENSE
 *
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
#include <string.h>

#if ! LITE
#include "kernelModule.h"
#endif
#include "q_misc.h"
#include "q_bswap.h"
#include "q_md5.h"

int vendor_is_rti (nn_vendorid_t vendor)
{
  const nn_vendorid_t rti = NN_VENDORID_RTI;
  return vendor.id[0] == rti.id[0] && vendor.id[1] == rti.id[1];
}

int vendor_is_twinoaks (nn_vendorid_t vendor)
{
  const nn_vendorid_t twinoaks = NN_VENDORID_TWINOAKS;
  return vendor.id[0] == twinoaks.id[0] && vendor.id[1] == twinoaks.id[1];
}

int vendor_is_cloud (nn_vendorid_t vendor)
{
  const nn_vendorid_t cloud = NN_VENDORID_PRISMTECH_CLOUD;
  return vendor.id[0] == cloud.id[0] && vendor.id[1] == cloud.id[1];
}

int vendor_is_prismtech (nn_vendorid_t vid)
{
  const nn_vendorid_t pt1 = NN_VENDORID_PRISMTECH_OSPL;
  const nn_vendorid_t pt2 = NN_VENDORID_PRISMTECH_LITE;
  const nn_vendorid_t pt3 = NN_VENDORID_PRISMTECH_GATEWAY;
  const nn_vendorid_t pt4 = NN_VENDORID_PRISMTECH_JAVA;
  const nn_vendorid_t pt5 = NN_VENDORID_PRISMTECH_CLOUD;

  return
    (vid.id[0] == pt1.id[0]) &&
    ((vid.id[1] == pt1.id[1]) || (vid.id[1] == pt2.id[1])
     || (vid.id[1] == pt3.id[1]) || (vid.id[1] == pt4.id[1])
     || (vid.id[1] == pt5.id[1]));
}

int vendor_is_opensplice (nn_vendorid_t vid)
{
  const nn_vendorid_t pt1 = NN_VENDORID_PRISMTECH_OSPL;
  return (vid.id[0] == pt1.id[0] && vid.id[1] == pt1.id[1]);
}

int vendor_is_lite (nn_vendorid_t vid)
{
  const nn_vendorid_t pt1 = NN_VENDORID_PRISMTECH_LITE;
  return (vid.id[0] == pt1.id[0] && vid.id[1] == pt1.id[1]);
}

int is_own_vendor (nn_vendorid_t vendor)
{
  const nn_vendorid_t ownid = MY_VENDOR_ID;
  return vendor.id[0] == ownid.id[0] && vendor.id[1] == ownid.id[1];
}

#if ! LITE
int gid_is_fake (const struct v_gid_s *gid)
{
  /* 0:0:0 is not so much fake as invalid, but here they both mean we
     pretend there is no gid.  For the localId mask, see v_handle.c --
     this is very much an undocumented characteristic of GIDs ... */
  if (gid->systemId == 0 && gid->localId == 0 && gid->serial == 0)
    return 1;
  else if (gid->localId & 0xffc00000)
    return 1;
  else
    return 0;
}
#endif

os_int64 fromSN (const nn_sequence_number_t sn)
{
  return ((os_int64) sn.high << 32) | sn.low;
}

nn_sequence_number_t toSN (os_int64 n)
{
  nn_sequence_number_t x;
  x.high = (int) (n >> 32);
  x.low = (unsigned) n;
  return x;
}

#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
int WildcardOverlap(char * p1, char * p2)
{
  /* both patterns are empty or contain wildcards => overlap */
  if ((p1 == NULL || strcmp(p1,"") == 0 || strcmp(p1,"*") == 0) &&
      (p2 == NULL || strcmp(p2,"") == 0 || strcmp(p2,"*") == 0))
    return 1;

  /* Either pattern is empty (but the other is not empty or wildcard only) => no overlap */
  if (p1 == NULL || strcmp(p1,"") == 0 || p2 == NULL || strcmp(p2,"")==0)
    return 0;

  if ( (p1[0] == '*' || p2[0] == '*') && (WildcardOverlap(p1,p2+1)|| WildcardOverlap(p1+1,p2)))
    return 1;

  if ( (p1[0] == '?' || p2[0] == '?' || p1[0] == p2[0] ) && WildcardOverlap(p1+1,p2+1))
    return 1;

  /* else, no match, return false */
  return 0;
}
#endif

#if ! LITE
int ddsi2_patmatch (const char *pat, const char *str)
{
  c_value p, n, r;
  p.kind = n.kind = V_STRING;
  p.is.String = (char *) pat;
  n.is.String = (char *) str;
  r = c_valueStringMatch (p, n);
  return r.is.Boolean;
}
#else
int ddsi2_patmatch (const char *pat, const char *str)
{
  while (*pat)
  {
    if (*pat == '?')
    {
      /* any character will do */
      if (*str++ == 0)
      {
        return 0;
      }
      pat++;
    }
    else if (*pat == '*')
    {
      /* collapse a sequence of wildcards, requiring as many
       characters in str as there are ?s in the sequence */
      while (*pat == '*' || *pat == '?')
      {
        if (*pat == '?' && *str++ == 0)
        {
          return 0;
        }
        pat++;
      }
      /* try matching on all positions where str matches pat */
      while (*str)
      {
        if (*str == *pat && ddsi2_patmatch (pat+1, str+1))
        {
          return 1;
        }
        str++;
      }
      return *pat == 0;
    }
    else
    {
      /* only an exact match */
      if (*str++ != *pat++)
      {
        return 0;
      }
    }
  }
  return *str == 0;
}
#endif

#if ! LITE
void nn_guid_to_ospl_gid (v_gid *gid, const nn_guid_t *guid, int guid_has_systemid)
{
  /* Try hard to fake a writer id for OpenSplice based on a GUID. All
   systems I know of have something resembling a host/system id in
   the first 32 bits, so copy that as the system id and copy half of
   an MD5 hash into the remaining 64 bits. Now if only OpenSplice
   would use all 96 bits as a key, we'd be doing reasonably well ... */
  const nn_guid_t nguid = nn_hton_guid (*guid);
  union { os_uint32 u[4]; unsigned char md5[16]; } hp, hg;
  md5_state_t md5st;

  if (guid_has_systemid)
  {
    /* for old OpenSplice versions: modern durability relies on the systemId for
       liveliness of its fellows, so we must not modify it */
    gid->systemId = guid->prefix.u[0];
  }
  else
  {
    md5_init (&md5st);
    md5_append (&md5st, (unsigned char *) &nguid.prefix, sizeof (nguid.prefix));
    md5_finish (&md5st, hp.md5);
    gid->systemId = fromBE4u (hp.u[0]);
  }

  md5_init (&md5st);
  md5_append (&md5st, (unsigned char *) &nguid, sizeof (nguid));
  md5_finish (&md5st, hg.md5);

  /* See also gid_is_fake for the masking of bits in localId */
  gid->localId = fromBE4u (hg.u[0]) & 0x3fffff;
  gid->serial = guid->entityid.u;
}

int version_info_is_6_4_1 (const char *internals)
{
  /* node/version/...; unfortunately, the version is quoted on some platforms */
  const char *p;
  if (internals == NULL || (p = strchr (internals, '/')) == NULL)
    return 0;
  return (strncmp (p + 1, "V6.4.1/", 7) == 0 || strncmp (p + 1, "\"V6.4.1\"/", 9) == 0);
}
#endif

#if LITE
static const os_uint32 crc32_table[] = {
  0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
  0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
  0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
  0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
  0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
  0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
  0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
  0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
  0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
  0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
  0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
  0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
  0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
  0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
  0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
  0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
  0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
  0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
  0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
  0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
  0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
  0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
  0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
  0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
  0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
  0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
  0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
  0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
  0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
  0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
  0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
  0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
  0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
  0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
  0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
  0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
  0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
  0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
  0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
  0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
  0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
  0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
  0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};

os_uint32 crc32_calc (const void *buf, os_uint32 length)
{
  const uint8_t *vptr = buf;
  os_uint32 i, reg = 0;
  uint8_t top;
  for (i = 0; i < length; i++)
  {
    top = (uint8_t) (reg >> 24);
    top ^= *vptr;
    reg = (reg << 8) ^ crc32_table[top];
    vptr++;
  }
  return reg;
}
#endif
