]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Update unhex() to allow a second argument, specifying a set of characters that are... unhex-function
authordan <Dan Kennedy>
Tue, 24 Jan 2023 17:19:47 +0000 (17:19 +0000)
committerdan <Dan Kennedy>
Tue, 24 Jan 2023 17:19:47 +0000 (17:19 +0000)
FossilOrigin-Name: 66c8562690b19f17972589611810e1dccad3a48777acb05208289c1f77076f71

manifest
manifest.uuid
src/func.c
test/unhex.test

index e67118aea2fd483bc1979863be87942d53a20c64..784839752b4fa0eac4970720170868db83045453 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sexperimental\suser\sfunction\sunhex().
-D 2023-01-23T14:11:34.494
+C Update\sunhex()\sto\sallow\sa\ssecond\sargument,\sspecifying\sa\sset\sof\scharacters\sthat\sare\spermitted\sto\sappear\sbetween\spairs\sof\shexadecimal\sdigits.
+D 2023-01-24T17:19:47.983
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -573,7 +573,7 @@ F src/delete.c 86573edae75e3d3e9a8b590d87db8e47222103029df4f3e11fa56044459b514e
 F src/expr.c 204af6a83c191f5ac19ec4af6ecc546f188cc2dd1c76fc5280982f710ec4b9c4
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c 722f20779f5342a787922deded3628d8c74b5249cab04098cf17ee2f2aaff002
-F src/func.c b17ff98c7665bba857608b0c837103a81a5370362ebc0d69ac6a53123ec7be9b
+F src/func.c 0bf5b82df41ffa1afe2bc67c3d0d361761c56c9e1785c999e24a15ba04c28d2b
 F src/global.c e06ff8e0acd85aec13563c9ecb44fbbf38232ccf73594998fd880b92d619594b
 F src/hash.c c6af5f96a7a76d000f07c5402c48c318c2566beecdee9e78b9d9f60ce7119565
 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
@@ -1758,7 +1758,7 @@ F test/tt3_vacuum.c 71b254cde1fc49d6c8c44efd54f4668f3e57d7b3a8f4601ade069f75a999
 F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
 F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
-F test/unhex.test abf3d0adbf40357bdeeabfb8a0073d7f3a704af3529c63645fcc8bb398c37d4d
+F test/unhex.test 47b547f4b35e4f6525ecac7c7839bd3ae4eb4613d4e8932592eff55da83308f1
 F test/unionall.test eb9afa030897af75fd2f0dd28354ef63c8a5897b6c76aa1f15acae61a12eabcf
 F test/unionall2.test 71e8fa08d5699d50dc9f9dc0c9799c2e7a6bb7931a330d369307a4df7f157fa1
 F test/unionallfault.test 652bfbb630e6c43135965dc1e8f0a9a791da83aec885d626a632fe1909c56f73
@@ -2044,11 +2044,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 5f2dfdcc345453ee0a05311f6826d90b7c1d7b95fdaf77a0a8383923a8fc7213
-R 828038e1afa4103669415a1c409f187d
-T *branch * unhex-function
-T *sym-unhex-function *
-T -sym-trunk *
+P dbe424b5db33ce2c7562dfb44daf2969cf3074234cc891eb9b8d0d907faf6a78
+R 2327d3168a15a3681a167b76648dc26a
 U dan
-Z efd8b9c01e0025c3579168914aaf4748
+Z 1993f291d48ac6d6618af856abe5f1fa
 # Remove this line to create a well-formed Fossil manifest.
index 491c8fc32f3f83df612ed502e89b761c04da8237..82e63a96a20e1a9b9f51cd5815b50c49c7c1e751 100644 (file)
@@ -1 +1 @@
-dbe424b5db33ce2c7562dfb44daf2969cf3074234cc891eb9b8d0d907faf6a78
\ No newline at end of file
+66c8562690b19f17972589611810e1dccad3a48777acb05208289c1f77076f71
\ No newline at end of file
index 619c8143025ca81e5af5b8e9824abaeeb686fc96..6a279a9d71c73d33a0fdecf47db12999772324ab 100644 (file)
@@ -1224,35 +1224,92 @@ static void hexFunc(
 }
 
 /*
-** The unhex() function. Interpret the argument as text. If it consists
-** of an even number of hexadecimal digits, return the equivalent blob.
-** Otherwise, return NULL.
+** Buffer zStr contains nStr bytes of utf-8 encoded text. Return 1 if zStr
+** contains character ch, or 0 if it does not.
+*/
+static int strContainsChar(const u8 *zStr, int nStr, u32 ch){
+  const u8 *zEnd = &zStr[nStr];
+  const u8 *z = zStr;
+  while( z<zEnd ){
+    u32 tst = Utf8Read(z);
+    if( tst==ch ) return 1;
+  }
+  return 0;
+}
+
+/*
+** The unhex() function. This function may be invoked with either one or
+** two arguments. In both cases the first argument is interpreted as text
+** a text value containing a set of pairs of hexadecimal digits which are
+** decoded and returned as a blob.
+**
+** If there is only a single argument, then it must consist only of an
+** even number of hexadeximal digits. Otherwise, return NULL.
+**
+** Or, if there is a second argument, then any character that appears in
+** the second argument is also allowed to appear between pairs of hexadecimal
+** digits in the first argument. If any other character appears in the
+** first argument, or if one of the allowed characters appears between 
+** two hexadecimal digits that make up a single byte, NULL is returned.
+**
+** The following expressions are all true:
+**
+**     unhex('ABCD')       IS x'ABCD'
+**     unhex('AB CD')      IS NULL
+**     unhex('AB CD', ' ') IS x'ABCD'
+**     unhex('A BCD', ' ') IS NULL
 */
 static void unhexFunc(
   sqlite3_context *pCtx,
   int argc,
   sqlite3_value **argv
 ){
+  const u8 *zPass = (const u8*)"";
+  int nPass = 0;
   const u8 *zHex = sqlite3_value_text(argv[0]);
   int nHex = sqlite3_value_bytes(argv[0]);
-  if( zHex && (nHex%2)==0 ){
-    u8 *pBlob = contextMalloc(pCtx, (nHex/2)+1);
-    if( pBlob ){
-      const u8 *zEnd = &zHex[nHex];
-      u8 *p = pBlob;
-      while( zHex<zEnd ){
-        unsigned char c = *(zHex++);
-        unsigned char d = *(zHex++);
-        if( !sqlite3Isxdigit(c) || !sqlite3Isxdigit(d) ){
-          sqlite3_free(pBlob);
-          return;
-        }else{
-          *(p++) = (sqlite3HexToInt(c)<<4) | sqlite3HexToInt(d);
-        }
+#ifdef SQLITE_DEBUG
+  const u8 *zEnd = &zHex[nHex];
+#endif
+  u8 *pBlob = 0;
+  u8 *p = 0;
+
+  assert( argc==1 || argc==2 );
+  if( argc==2 ){
+    zPass = sqlite3_value_text(argv[1]);
+    nPass = sqlite3_value_bytes(argv[1]);
+  }
+  if( !zHex || !zPass ) return;
+
+  p = pBlob = contextMalloc(pCtx, (nHex/2)+1);
+  if( pBlob ){
+    u8 c;                         /* Most significant digit of next byte */
+    u8 d;                         /* Least significant digit of next byte */
+
+    while( (c = *zHex)!=0x00 ){
+      while( !sqlite3Isxdigit(c) ){
+        u32 ch = Utf8Read(zHex);
+        assert( zHex<=zEnd );
+        if( !strContainsChar(zPass, nPass, ch) ) goto unhex_null;
+        c = *zHex;
+        if( c==0x00 ) goto unhex_done;
       }
-      sqlite3_result_blob(pCtx, pBlob, (p - pBlob), sqlite3_free);
+      zHex++;
+      assert( *zEnd==0x00 );
+      assert( zHex<=zEnd );
+      d = *(zHex++);
+      if( !sqlite3Isxdigit(d) ) goto unhex_null;
+      *(p++) = (sqlite3HexToInt(c)<<4) | sqlite3HexToInt(d);
     }
   }
+
+ unhex_done:
+  sqlite3_result_blob(pCtx, pBlob, (p - pBlob), sqlite3_free);
+  return;
+
+ unhex_null:
+  sqlite3_free(pBlob);
+  return;
 }
 
 
@@ -2321,6 +2378,7 @@ void sqlite3RegisterBuiltinFunctions(void){
     FUNCTION(lower,              1, 0, 0, lowerFunc        ),
     FUNCTION(hex,                1, 0, 0, hexFunc          ),
     FUNCTION(unhex,              1, 0, 0, unhexFunc        ),
+    FUNCTION(unhex,              2, 0, 0, unhexFunc        ),
     INLINE_FUNC(ifnull,          2, INLINEFUNC_coalesce, 0 ),
     VFUNCTION(random,            0, 0, 0, randomFunc       ),
     VFUNCTION(randomblob,        1, 0, 0, randomBlob       ),
index 0bd2dfd6b5524064e1bfd2937b173da34dbaf182..f41e906a8fc206a0e8c418b7752124d0ae4acb26 100644 (file)
@@ -49,9 +49,54 @@ do_catchsql_test 3.0 {
   SELECT unhex();
 } {1 {wrong number of arguments to function unhex()}}
 do_catchsql_test 3.1 {
-  SELECT unhex('ABCD', '1234');
+  SELECT unhex('ABCD', '1234', '');
 } {1 {wrong number of arguments to function unhex()}}
 
+#--------------------------------------------------------------------------
+# Test the 2-argument version.
+#
+foreach {tn hex} {
+  1 "FFFF  ABCD"
+  2 "FFFF ABCD"
+  3 "FFFFABCD "
+  4 " FFFFABCD"
+  5 "--FFFF AB- -CD- "
+  6 "--"
+  7 " --"
+} {
+  set out ""
+  foreach x [split $hex ""] {
+    if {[string is xdigit $x]} { append out $x }
+  }
+
+  do_execsql_test 5.$tn.1 {
+    SELECT hex( unhex($hex, ' -') );
+  } [list $out]
+}
+
+do_execsql_test 6.0 {
+  SELECT typeof( unhex(' ', ' -') ), length( unhex('-', ' -') );
+} {blob 0}
+
+
+do_execsql_test 6.1 "
+  SELECT hex( unhex('\u0E01ABCD\u0E02', '\uE01\uE02') )
+" {ABCD}
+do_execsql_test 6.2 "
+  SELECT typeof( unhex('\u0E01ABCD\u0E02', '\uE03\uE02') )
+" {null}
+do_execsql_test 6.3 "
+  SELECT hex( unhex('\u0E01AB CD\uE02\uE01', '\uE01 \uE02') )
+" {ABCD}
+
+#--------------------------------------------------------------------------
+# Test that if either argument is NULL, the returned value is also NULL.
+#
+do_execsql_test 6.4.1 { SELECT typeof(unhex(NULL)) } {null}
+do_execsql_test 6.4.2 { SELECT typeof(unhex(NULL, ' ')) } {null}
+do_execsql_test 6.4.3 { SELECT typeof(unhex('1234', NULL)) } {null}
+
+
 finish_test