text: /*
  ** 2019-10-23
  **
  ** The author disclaims copyright to this source code.  In place of
  ** a legal notice, here is a blessing:
  **
  **    May you do good and not evil.
  **    May you find forgiveness for yourself and forgive others.
  **    May you share freely, never taking more than you give.
  **
  ******************************************************************************
  **
  ** This SQLite extension implements functions that handling RFC-4122 UUIDs
  ** Three SQL functions are implemented:
  **
  **     uuid()        - generate a version 4 UUID as a string
  **     uuid_str(X)   - convert a UUID X into a well-formed UUID string
  **     uuid_blob(X)  - convert a UUID X into a 16-byte blob
  **
  ** The output from uuid() and uuid_str(X) are always well-formed RFC-4122
  ** UUID strings in this format:
  **
  **        xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
  **
  ** All of the 'x', 'M', and 'N' values are lower-case hexadecimal digits.
  ** The M digit indicates the "version".  For uuid()-generated UUIDs, the
  ** version is always "4" (a random UUID).  The upper three bits of N digit
  ** are the "variant".  This library only supports variant 1 (indicated
  ** by values of N between '8' and 'b') as those are overwhelming the most
  ** common.  Other variants are for legacy compatibility only.
  **
  ** The output of uuid_blob(X) is always a 16-byte blob.  The UUID input
  ** string is converted in network byte order (big-endian) in accordance
  ** with RFC-4122 specifications for variant-1 UUIDs.  Note that network
  ** byte order is *always* used, even if the input self-identifies as a
  ** variant-2 UUID.
  **
  ** The input X to the uuid_str() and uuid_blob() functions can be either
  ** a string or a BLOB.  If it is a BLOB it must be exactly 16 bytes in
  ** length or else a NULL is returned.  If the input is a string it must
  ** consist of 32 hexadecimal digits, upper or lower case, optionally
  ** surrounded by {...} and with optional "-" characters interposed in the
  ** middle.  The flexibility of input is inspired by the PostgreSQL
  ** implementation of UUID functions that accept in all of the following
  ** formats:
  **
  **     A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
  **     {a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
  **     a0eebc999c0b4ef8bb6d6bb9bd380a11
  **     a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
  **     {a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}
  **
  ** If any of the above inputs are passed into uuid_str(), the output will
  ** always be in the canonical RFC-4122 format:
  **
  **     a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
  **
  ** If the X input string has too few or too many digits or contains
  ** stray characters other than {, }, or -, then NULL is returned.
  */
  #include "sqlite3ext.h"
  SQLITE_EXTENSION_INIT1
  #include <assert.h>
  #include <string.h>
  #include <ctype.h>
  
  #if !defined(SQLITE_ASCII) && !defined(SQLITE_EBCDIC)
  # define SQLITE_ASCII 1
  #endif
  
  /*
  ** Translate a single byte of Hex into an integer.
  ** This routine only works if h really is a valid hexadecimal
  ** character:  0..9a..fA..F
  */
  static unsigned char sqlite3UuidHexToInt(int h){
    assert( (h>='0' && h<='9') ||  (h>='a' && h<='f') ||  (h>='A' && h<='F') );
  #ifdef SQLITE_ASCII
    h += 9*(1&(h>>6));
  #endif
  #ifdef SQLITE_EBCDIC
    h += 9*(1&~(h>>4));
  #endif
    return (unsigned char)(h & 0xf);
  }
  
  /*
  ** Convert a 16-byte BLOB into a well-formed RFC-4122 UUID.  The output
  ** buffer zStr should be at least 37 bytes in length.   The output will
  ** be zero-terminated.
  */
  static void sqlite3UuidBlobToStr(
    const unsigned char *aBlob,  /* Input blob */
    unsigned char *zStr          /* Write the answer here */
  ){
    static const char zDigits[] = "0123456789abcdef";
    int i, k;
    unsigned char x;
    k = 0;
    for(i=0, k=0x550; i<16; i++, k=k>>1){
      if( k&1 ){
        zStr[0] = '-';
        zStr++;
      }
      x = aBlob[i];
      zStr[0] = zDigits[x>>4];
      zStr[1] = zDigits[x&0xf];
      zStr += 2;
    }
    *zStr = 0;
  }
  
  /*
  ** Attempt to parse a zero-terminated input string zStr into a binary
  ** UUID.  Return 0 on success, or non-zero if the input string is not
  ** parsable.
  */
  static int sqlite3UuidStrToBlob(
    const unsigned char *zStr,   /* Input string */
    unsigned char *aBlob         /* Write results here */
  ){
    int i;
    if( zStr[0]=='{' ) zStr++;
    for(i=0; i<16; i++){
      if( zStr[0]=='-' ) zStr++;
      if( isxdigit(zStr[0]) && isxdigit(zStr[1]) ){
        aBlob[i] = (sqlite3UuidHexToInt(zStr[0])<<4)
                        + sqlite3UuidHexToInt(zStr[1]);
        zStr += 2;
      }else{
        return 1;
      }
    }
    if( zStr[0]=='}' ) zStr++;
    return zStr[0]!=0;
  }
  
  /*
  ** Render sqlite3_value pIn as a 16-byte UUID blob.  Return a pointer
  ** to the blob, or NULL if the input is not well-formed.
  */
  static const unsigned char *sqlite3UuidInputToBlob(
    sqlite3_value *pIn,     /* Input text */
    unsigned char *pBuf     /* output buffer */
  ){
    switch( sqlite3_value_type(pIn) ){
      case SQLITE_TEXT: {
        const unsigned char *z = sqlite3_value_text(pIn);
        if( sqlite3UuidStrToBlob(z, pBuf) ) return 0;
        return pBuf;
      }
      case SQLITE_BLOB: {
        int n = sqlite3_value_bytes(pIn);
        return n==16 ? sqlite3_value_blob(pIn) : 0;
      }
      default: {
        return 0;
      }
    }
  }
  
  /* Implementation of uuid() */
  static void sqlite3UuidFunc(
    sqlite3_context *context,
    int argc,
    sqlite3_value **argv
  ){
    unsigned char aBlob[16];
    unsigned char zStr[37];
    (void)argc;
    (void)argv;
    sqlite3_randomness(16, aBlob);
    aBlob[6] = (aBlob[6]&0x0f) + 0x40;
    aBlob[8] = (aBlob[8]&0x3f) + 0x80;
    sqlite3UuidBlobToStr(aBlob, zStr);
    sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT);
  }
  
  /* Implementation of uuid_str() */
  static void sqlite3UuidStrFunc(
    sqlite3_context *context,
    int argc,
    sqlite3_value **argv
  ){
    unsigned char aBlob[16];
    unsigned char zStr[37];
    const unsigned char *pBlob;
    (void)argc;
    pBlob = sqlite3UuidInputToBlob(argv[0], aBlob);
    if( pBlob==0 ) return;
    sqlite3UuidBlobToStr(pBlob, zStr);
    sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT);
  }
  
  /* Implementation of uuid_blob() */
  static void sqlite3UuidBlobFunc(
    sqlite3_context *context,
    int argc,
    sqlite3_value **argv
  ){
    unsigned char aBlob[16];
    const unsigned char *pBlob;
    (void)argc;
    pBlob = sqlite3UuidInputToBlob(argv[0], aBlob);
    if( pBlob==0 ) return;
    sqlite3_result_blob(context, pBlob, 16, SQLITE_TRANSIENT);
  }
  
  #ifdef _WIN32
  __declspec(dllexport)
  #endif
  int sqlite3_uuid_init(
    sqlite3 *db,
    char **pzErrMsg,
    const sqlite3_api_routines *pApi
  ){
    int rc = SQLITE_OK;
    SQLITE_EXTENSION_INIT2(pApi);
    (void)pzErrMsg;  /* Unused parameter */
    rc = sqlite3_create_function(db, "uuid", 0, SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
                                 sqlite3UuidFunc, 0, 0);
    if( rc==SQLITE_OK ){
      rc = sqlite3_create_function(db, "uuid_str", 1, 
                         SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
                         0, sqlite3UuidStrFunc, 0, 0);
    }
    if( rc==SQLITE_OK ){
      rc = sqlite3_create_function(db, "uuid_blob", 1,
                         SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
                         0, sqlite3UuidBlobFunc, 0, 0);
    }
    return rc;
  }
  