Fossil SCM

fossil-scm / src / encode.c
Source Blame History 934 lines
dbda8d6… drh 1 /*
c19f34c… drh 2 ** Copyright (c) 2006 D. Richard Hipp
dbda8d6… drh 3 **
dbda8d6… drh 4 ** This program is free software; you can redistribute it and/or
c06edd2… drh 5 ** modify it under the terms of the Simplified BSD License (also
c06edd2… drh 6 ** known as the "2-Clause License" or "FreeBSD License".)
c06edd2… drh 7
dbda8d6… drh 8 ** This program is distributed in the hope that it will be useful,
c06edd2… drh 9 ** but without any warranty; without even the implied warranty of
c06edd2… drh 10 ** merchantability or fitness for a particular purpose.
dbda8d6… drh 11 **
dbda8d6… drh 12 ** Author contact information:
dbda8d6… drh 13 ** [email protected]
dbda8d6… drh 14 ** http://www.hwaci.com/drh/
dbda8d6… drh 15 **
dbda8d6… drh 16 *******************************************************************************
dbda8d6… drh 17 **
dbda8d6… drh 18 ** Routines for encoding and decoding text.
dbda8d6… drh 19 */
dbda8d6… drh 20 #include "config.h"
dbda8d6… drh 21 #include "encode.h"
dbda8d6… drh 22
dbda8d6… drh 23 /*
dbda8d6… drh 24 ** Make the given string safe for HTML by converting every "<" into "&lt;",
dbda8d6… drh 25 ** every ">" into "&gt;" and every "&" into "&amp;". Return a pointer
dbda8d6… drh 26 ** to a new string obtained from malloc().
dbda8d6… drh 27 **
5e17369… andygoth 28 ** We also encode " as &quot; and ' as &#39; so they can appear as an argument
dbda8d6… drh 29 ** to markup.
dbda8d6… drh 30 */
4c1d38f… drh 31 char *htmlize(const char *z, int n){
4c1d38f… drh 32 unsigned char c;
dbda8d6… drh 33 int i = 0;
dbda8d6… drh 34 int count = 0;
4c1d38f… drh 35 unsigned char *zOut;
4c1d38f… drh 36 const unsigned char *zIn = (const unsigned char*)z;
4c1d38f… drh 37
4c1d38f… drh 38 if( n<0 ) n = strlen(z);
4c1d38f… drh 39 while( i<n ){
4c1d38f… drh 40 switch( zIn[i] ){
4c1d38f… drh 41 case '<': count += 3; break;
4c1d38f… drh 42 case '>': count += 3; break;
4c1d38f… drh 43 case '&': count += 4; break;
4c1d38f… drh 44 case '"': count += 5; break;
4c1d38f… drh 45 case '\'': count += 4; break;
4c1d38f… drh 46 case 0: n = i; break;
dbda8d6… drh 47 }
dbda8d6… drh 48 i++;
dbda8d6… drh 49 }
dbda8d6… drh 50 i = 0;
4c1d38f… drh 51 zOut = fossil_malloc( count+n+1 );
4c1d38f… drh 52 if( count==0 ){
4c1d38f… drh 53 memcpy(zOut, zIn, n);
4c1d38f… drh 54 zOut[n] = 0;
4c1d38f… drh 55 return (char*)zOut;
4c1d38f… drh 56 }
4c1d38f… drh 57 while( n-->0 ){
4c1d38f… drh 58 c = *(zIn++);
dbda8d6… drh 59 switch( c ){
20d02ab… jan.nijtmans 60 case '<':
dbda8d6… drh 61 zOut[i++] = '&';
dbda8d6… drh 62 zOut[i++] = 'l';
dbda8d6… drh 63 zOut[i++] = 't';
dbda8d6… drh 64 zOut[i++] = ';';
dbda8d6… drh 65 break;
20d02ab… jan.nijtmans 66 case '>':
dbda8d6… drh 67 zOut[i++] = '&';
dbda8d6… drh 68 zOut[i++] = 'g';
dbda8d6… drh 69 zOut[i++] = 't';
dbda8d6… drh 70 zOut[i++] = ';';
dbda8d6… drh 71 break;
20d02ab… jan.nijtmans 72 case '&':
dbda8d6… drh 73 zOut[i++] = '&';
dbda8d6… drh 74 zOut[i++] = 'a';
dbda8d6… drh 75 zOut[i++] = 'm';
dbda8d6… drh 76 zOut[i++] = 'p';
dbda8d6… drh 77 zOut[i++] = ';';
dbda8d6… drh 78 break;
20d02ab… jan.nijtmans 79 case '"':
dbda8d6… drh 80 zOut[i++] = '&';
dbda8d6… drh 81 zOut[i++] = 'q';
dbda8d6… drh 82 zOut[i++] = 'u';
dbda8d6… drh 83 zOut[i++] = 'o';
dbda8d6… drh 84 zOut[i++] = 't';
dbda8d6… drh 85 zOut[i++] = ';';
dbda8d6… drh 86 break;
5e17369… andygoth 87 case '\'':
5e17369… andygoth 88 zOut[i++] = '&';
5e17369… andygoth 89 zOut[i++] = '#';
5e17369… andygoth 90 zOut[i++] = '3';
5e17369… andygoth 91 zOut[i++] = '9';
5e17369… andygoth 92 zOut[i++] = ';';
5e17369… andygoth 93 break;
4615bc8… drh 94 default:
4615bc8… drh 95 zOut[i++] = c;
4615bc8… drh 96 break;
4615bc8… drh 97 }
4615bc8… drh 98 }
4615bc8… drh 99 zOut[i] = 0;
4c1d38f… drh 100 return (char*)zOut;
4615bc8… drh 101 }
4615bc8… drh 102
4615bc8… drh 103 /*
4615bc8… drh 104 ** Append HTML-escaped text to a Blob.
4615bc8… drh 105 */
4615bc8… drh 106 void htmlize_to_blob(Blob *p, const char *zIn, int n){
4615bc8… drh 107 int c, i, j;
4615bc8… drh 108 if( n<0 ) n = strlen(zIn);
4615bc8… drh 109 for(i=j=0; i<n; i++){
4615bc8… drh 110 c = zIn[i];
4615bc8… drh 111 switch( c ){
4615bc8… drh 112 case '<':
4615bc8… drh 113 if( j<i ) blob_append(p, zIn+j, i-j);
4615bc8… drh 114 blob_append(p, "&lt;", 4);
4615bc8… drh 115 j = i+1;
4615bc8… drh 116 break;
4615bc8… drh 117 case '>':
4615bc8… drh 118 if( j<i ) blob_append(p, zIn+j, i-j);
4615bc8… drh 119 blob_append(p, "&gt;", 4);
4615bc8… drh 120 j = i+1;
4615bc8… drh 121 break;
4615bc8… drh 122 case '&':
4615bc8… drh 123 if( j<i ) blob_append(p, zIn+j, i-j);
4615bc8… drh 124 blob_append(p, "&amp;", 5);
4615bc8… drh 125 j = i+1;
4615bc8… drh 126 break;
4615bc8… drh 127 case '"':
4615bc8… drh 128 if( j<i ) blob_append(p, zIn+j, i-j);
4615bc8… drh 129 blob_append(p, "&quot;", 6);
4615bc8… drh 130 j = i+1;
4615bc8… drh 131 break;
5e17369… andygoth 132 case '\'':
5e17369… andygoth 133 if( j<i ) blob_append(p, zIn+j, i-j);
5e17369… andygoth 134 blob_append(p, "&#39;", 5);
5e17369… andygoth 135 j = i+1;
5e17369… andygoth 136 break;
050ba62… drh 137 case '\r':
050ba62… drh 138 if( j<i ) blob_append(p, zIn+j, i-j);
050ba62… drh 139 blob_append(p, " ", 1);
050ba62… drh 140 j = i+1;
050ba62… drh 141 break;
4615bc8… drh 142 }
4615bc8… drh 143 }
4615bc8… drh 144 if( j<i ) blob_append(p, zIn+j, i-j);
5ea6e15… drh 145 }
5ea6e15… drh 146
5ea6e15… drh 147 /*
5ea6e15… drh 148 ** Make the given string safe for HTML by converting syntax characters
5ea6e15… drh 149 ** into alternatives that do not have the special syntactic meaning.
5ea6e15… drh 150 **
5ea6e15… drh 151 ** < --> U+227a
5ea6e15… drh 152 ** > --> U+227b
5ea6e15… drh 153 ** & --> +
5ea6e15… drh 154 ** " --> U+201d
5ea6e15… drh 155 ** ' --> U+2019
5ea6e15… drh 156 **
5ea6e15… drh 157 ** Return a pointer to a new string obtained from fossil_malloc().
5ea6e15… drh 158 */
5ea6e15… drh 159 char *html_lookalike(const char *z, int n){
5ea6e15… drh 160 unsigned char c;
5ea6e15… drh 161 int i = 0;
5ea6e15… drh 162 int count = 0;
5ea6e15… drh 163 unsigned char *zOut;
5ea6e15… drh 164 const unsigned char *zIn = (const unsigned char*)z;
5ea6e15… drh 165
5ea6e15… drh 166 if( n<0 ) n = strlen(z);
5ea6e15… drh 167 while( i<n ){
5ea6e15… drh 168 switch( zIn[i] ){
5ea6e15… drh 169 case '<': count += 3; break;
5ea6e15… drh 170 case '>': count += 3; break;
5ea6e15… drh 171 case '"': count += 3; break;
5ea6e15… drh 172 case '\'': count += 3; break;
5ea6e15… drh 173 case 0: n = i; break;
5ea6e15… drh 174 }
5ea6e15… drh 175 i++;
5ea6e15… drh 176 }
5ea6e15… drh 177 i = 0;
5ea6e15… drh 178 zOut = fossil_malloc( count+n+1 );
5ea6e15… drh 179 if( count==0 ){
5ea6e15… drh 180 memcpy(zOut, zIn, n);
5ea6e15… drh 181 zOut[n] = 0;
5ea6e15… drh 182 return (char*)zOut;
5ea6e15… drh 183 }
5ea6e15… drh 184 while( n-->0 ){
5ea6e15… drh 185 c = *(zIn++);
5ea6e15… drh 186 switch( c ){
5ea6e15… drh 187 case '<':
5ea6e15… drh 188 zOut[i++] = 0xe2;
5ea6e15… drh 189 zOut[i++] = 0x89;
5ea6e15… drh 190 zOut[i++] = 0xba;
5ea6e15… drh 191 break;
5ea6e15… drh 192 case '>':
5ea6e15… drh 193 zOut[i++] = 0xe2;
5ea6e15… drh 194 zOut[i++] = 0x89;
5ea6e15… drh 195 zOut[i++] = 0xbb;
5ea6e15… drh 196 break;
5ea6e15… drh 197 case '&':
5ea6e15… drh 198 zOut[i++] = '+';
5ea6e15… drh 199 break;
5ea6e15… drh 200 case '"':
5ea6e15… drh 201 zOut[i++] = 0xe2;
5ea6e15… drh 202 zOut[i++] = 0x80;
5ea6e15… drh 203 zOut[i++] = 0x9d;
5ea6e15… drh 204 break;
5ea6e15… drh 205 case '\'':
5ea6e15… drh 206 zOut[i++] = 0xe2;
5ea6e15… drh 207 zOut[i++] = 0x80;
5ea6e15… drh 208 zOut[i++] = 0x99;
5ea6e15… drh 209 break;
5ea6e15… drh 210 default:
5ea6e15… drh 211 zOut[i++] = c;
5ea6e15… drh 212 break;
5ea6e15… drh 213 }
5ea6e15… drh 214 }
5ea6e15… drh 215 zOut[i] = 0;
5ea6e15… drh 216 return (char*)zOut;
f7a18cf… drh 217 }
f7a18cf… drh 218
dbda8d6… drh 219
dbda8d6… drh 220 /*
dbda8d6… drh 221 ** Encode a string for HTTP. This means converting lots of
dbda8d6… drh 222 ** characters into the "%HH" where H is a hex digit. It also
dbda8d6… drh 223 ** means converting spaces to "+".
dbda8d6… drh 224 **
dbda8d6… drh 225 ** This is the opposite of DeHttpizeString below.
dbda8d6… drh 226 */
dbda8d6… drh 227 static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
dbda8d6… drh 228 int c;
dbda8d6… drh 229 int i = 0;
dbda8d6… drh 230 int count = 0;
dbda8d6… drh 231 char *zOut;
dbda8d6… drh 232 # define IsSafeChar(X) \
2fac809… drh 233 (fossil_isalnum(X) || (X)=='.' || (X)=='$' \
afec3f8… drh 234 || (X)=='~' || (X)=='-' || (X)=='_' \
afec3f8… drh 235 || (!encodeSlash && ((X)=='/' || (X)==':')))
dbda8d6… drh 236
dbda8d6… drh 237 if( zIn==0 ) return 0;
dbda8d6… drh 238 if( n<0 ) n = strlen(zIn);
dbda8d6… drh 239 while( i<n && (c = zIn[i])!=0 ){
dbda8d6… drh 240 if( IsSafeChar(c) || c==' ' ){
dbda8d6… drh 241 count++;
dbda8d6… drh 242 }else{
dbda8d6… drh 243 count += 3;
dbda8d6… drh 244 }
dbda8d6… drh 245 i++;
dbda8d6… drh 246 }
dbda8d6… drh 247 i = 0;
8f41b2f… drh 248 zOut = fossil_malloc( count+1 );
dbda8d6… drh 249 while( n-->0 && (c = *zIn)!=0 ){
dbda8d6… drh 250 if( IsSafeChar(c) ){
dbda8d6… drh 251 zOut[i++] = c;
dbda8d6… drh 252 }else if( c==' ' ){
dbda8d6… drh 253 zOut[i++] = '+';
dbda8d6… drh 254 }else{
dbda8d6… drh 255 zOut[i++] = '%';
dbda8d6… drh 256 zOut[i++] = "0123456789ABCDEF"[(c>>4)&0xf];
dbda8d6… drh 257 zOut[i++] = "0123456789ABCDEF"[c&0xf];
dbda8d6… drh 258 }
dbda8d6… drh 259 zIn++;
dbda8d6… drh 260 }
dbda8d6… drh 261 zOut[i] = 0;
a789e85… stephan 262 #undef IsSafeChar
dbda8d6… drh 263 return zOut;
dbda8d6… drh 264 }
dbda8d6… drh 265
dbda8d6… drh 266 /*
dbda8d6… drh 267 ** Convert the input string into a form that is suitable for use as
dbda8d6… drh 268 ** a token in the HTTP protocol. Spaces are encoded as '+' and special
db0c512… drh 269 ** characters are encoded as "%HH" where HH is a two-digit hexadecimal
dbda8d6… drh 270 ** representation of the character. The "/" character is encoded
dbda8d6… drh 271 ** as "%2F".
dbda8d6… drh 272 */
dbda8d6… drh 273 char *httpize(const char *z, int n){
dbda8d6… drh 274 return EncodeHttp(z, n, 1);
dbda8d6… drh 275 }
dbda8d6… drh 276
dbda8d6… drh 277 /*
dbda8d6… drh 278 ** Convert the input string into a form that is suitable for use as
dbda8d6… drh 279 ** a token in the HTTP protocol. Spaces are encoded as '+' and special
dbda8d6… drh 280 ** characters are encoded as "%HH" where HH is a two-digit hexidecimal
dbda8d6… drh 281 ** representation of the character. The "/" character is not encoded
20d02ab… jan.nijtmans 282 ** by this routine.
dbda8d6… drh 283 */
dbda8d6… drh 284 char *urlize(const char *z, int n){
dbda8d6… drh 285 return EncodeHttp(z, n, 0);
dbda8d6… drh 286 }
dbda8d6… drh 287
dbda8d6… drh 288 /*
19e6905… drh 289 ** If input string does not contain quotes (neither ' nor ")
3990518… george 290 ** then return the argument itself. Otherwise return a newly allocated
3990518… george 291 ** copy of input with all quotes %-escaped.
3990518… george 292 */
3990518… george 293 const char* escape_quotes(const char *zIn){
3990518… george 294 char *zRet, *zOut;
3990518… george 295 size_t i, n = 0;
3990518… george 296 for(i=0; zIn[i]; i++){
3990518… george 297 if( zIn[i]== '"' || zIn[i]== '\'' ) n++;
3990518… george 298 }
3990518… george 299 if( !n ) return zIn;
3990518… george 300 zRet = zOut = fossil_malloc( i + 2*n + 1 );
3990518… george 301 for(i=0; zIn[i]; i++){
3990518… george 302 if( zIn[i]=='"' ){
3990518… george 303 *(zOut++) = '%';
3990518… george 304 *(zOut++) = '2';
3990518… george 305 *(zOut++) = '2';
3990518… george 306 }else if( zIn[i]=='\'' ){
3990518… george 307 *(zOut++) = '%';
3990518… george 308 *(zOut++) = '2';
3990518… george 309 *(zOut++) = '7';
3990518… george 310 }else{
3990518… george 311 *(zOut++) = zIn[i];
3990518… george 312 }
3990518… george 313 }
3990518… george 314 *zOut = 0;
3990518… george 315 return zRet;
3990518… george 316 }
3990518… george 317
3990518… george 318 /*
dbda8d6… drh 319 ** Convert a single HEX digit to an integer
dbda8d6… drh 320 */
f7a18cf… drh 321 int fossil_hexvalue(int c){
dbda8d6… drh 322 if( c>='a' && c<='f' ){
dbda8d6… drh 323 c += 10 - 'a';
dbda8d6… drh 324 }else if( c>='A' && c<='F' ){
dbda8d6… drh 325 c += 10 - 'A';
dbda8d6… drh 326 }else if( c>='0' && c<='9' ){
dbda8d6… drh 327 c -= '0';
dbda8d6… drh 328 }else{
dbda8d6… drh 329 c = 0;
dbda8d6… drh 330 }
dbda8d6… drh 331 return c;
dbda8d6… drh 332 }
dbda8d6… drh 333
dbda8d6… drh 334 /*
dbda8d6… drh 335 ** Remove the HTTP encodings from a string. The conversion is done
dbda8d6… drh 336 ** in-place. Return the length of the string after conversion.
dbda8d6… drh 337 */
dbda8d6… drh 338 int dehttpize(char *z){
dbda8d6… drh 339 int i, j;
3a25b68… drh 340
3a25b68… drh 341 /* Treat a null pointer as a zero-length string. */
3a25b68… drh 342 if( !z ) return 0;
3a25b68… drh 343
dbda8d6… drh 344 i = j = 0;
dbda8d6… drh 345 while( z[i] ){
dbda8d6… drh 346 switch( z[i] ){
dbda8d6… drh 347 case '%':
dbda8d6… drh 348 if( z[i+1] && z[i+2] ){
f7a18cf… drh 349 z[j] = fossil_hexvalue(z[i+1]) << 4;
f7a18cf… drh 350 z[j] |= fossil_hexvalue(z[i+2]);
dbda8d6… drh 351 i += 2;
dbda8d6… drh 352 }
dbda8d6… drh 353 break;
dbda8d6… drh 354 case '+':
dbda8d6… drh 355 z[j] = ' ';
dbda8d6… drh 356 break;
dbda8d6… drh 357 default:
dbda8d6… drh 358 z[j] = z[i];
dbda8d6… drh 359 break;
dbda8d6… drh 360 }
dbda8d6… drh 361 i++;
dbda8d6… drh 362 j++;
dbda8d6… drh 363 }
dbda8d6… drh 364 z[j] = 0;
dbda8d6… drh 365 return j;
dbda8d6… drh 366 }
dbda8d6… drh 367
dbda8d6… drh 368 /*
dbda8d6… drh 369 ** The "fossilize" encoding is used in the headers of records
dbda8d6… drh 370 ** (aka "content files") to escape special characters. The
dbda8d6… drh 371 ** fossilize encoding passes most characters through unchanged.
dbda8d6… drh 372 ** The changes are these:
dbda8d6… drh 373 **
dbda8d6… drh 374 ** space -> \s
dbda8d6… drh 375 ** tab -> \t
dbda8d6… drh 376 ** newline -> \n
dbda8d6… drh 377 ** cr -> \r
dbda8d6… drh 378 ** formfeed -> \f
dbda8d6… drh 379 ** vtab -> \v
dbda8d6… drh 380 ** nul -> \0
dbda8d6… drh 381 ** \ -> \\
dbda8d6… drh 382 **
dbda8d6… drh 383 ** The fossilize() routine does an encoding of its input and
dbda8d6… drh 384 ** returns a pointer to the encoding in space obtained from
dbda8d6… drh 385 ** malloc.
dbda8d6… drh 386 */
dbda8d6… drh 387 char *fossilize(const char *zIn, int nIn){
dbda8d6… drh 388 int n, i, j, c;
dbda8d6… drh 389 char *zOut;
dbda8d6… drh 390 if( nIn<0 ) nIn = strlen(zIn);
dbda8d6… drh 391 for(i=n=0; i<nIn; i++){
dbda8d6… drh 392 c = zIn[i];
16e703b… drh 393 if( c==0 || c==' ' || c=='\n' || c=='\t' || c=='\r' || c=='\f' || c=='\v'
16e703b… drh 394 || c=='\\' ) n++;
dbda8d6… drh 395 }
dbda8d6… drh 396 n += nIn;
8f41b2f… drh 397 zOut = fossil_malloc( n+1 );
dbda8d6… drh 398 if( zOut ){
dbda8d6… drh 399 for(i=j=0; i<nIn; i++){
dbda8d6… drh 400 int c = zIn[i];
dbda8d6… drh 401 if( c==0 ){
dbda8d6… drh 402 zOut[j++] = '\\';
dbda8d6… drh 403 zOut[j++] = '0';
dbda8d6… drh 404 }else if( c=='\\' ){
dbda8d6… drh 405 zOut[j++] = '\\';
dbda8d6… drh 406 zOut[j++] = '\\';
2fac809… drh 407 }else if( fossil_isspace(c) ){
dbda8d6… drh 408 zOut[j++] = '\\';
dbda8d6… drh 409 switch( c ){
dbda8d6… drh 410 case '\n': c = 'n'; break;
dbda8d6… drh 411 case ' ': c = 's'; break;
dbda8d6… drh 412 case '\t': c = 't'; break;
dbda8d6… drh 413 case '\r': c = 'r'; break;
dbda8d6… drh 414 case '\v': c = 'v'; break;
dbda8d6… drh 415 case '\f': c = 'f'; break;
dbda8d6… drh 416 }
dbda8d6… drh 417 zOut[j++] = c;
dbda8d6… drh 418 }else{
dbda8d6… drh 419 zOut[j++] = c;
dbda8d6… drh 420 }
dbda8d6… drh 421 }
dbda8d6… drh 422 zOut[j] = 0;
dbda8d6… drh 423 }
dbda8d6… drh 424 return zOut;
dbda8d6… drh 425 }
dbda8d6… drh 426
dbda8d6… drh 427 /*
dbda8d6… drh 428 ** Decode a fossilized string in-place.
dbda8d6… drh 429 */
dbda8d6… drh 430 void defossilize(char *z){
dbda8d6… drh 431 int i, j, c;
0aaefea… drh 432 char *zSlash = strchr(z, '\\');
0aaefea… drh 433 if( zSlash==0 ) return;
0aaefea… drh 434 i = zSlash - z;
d13054c… drh 435 for(j=i; (c=z[i])!=0; i++){
dbda8d6… drh 436 if( c=='\\' && z[i+1] ){
dbda8d6… drh 437 i++;
dbda8d6… drh 438 switch( z[i] ){
dbda8d6… drh 439 case 'n': c = '\n'; break;
dbda8d6… drh 440 case 's': c = ' '; break;
dbda8d6… drh 441 case 't': c = '\t'; break;
dbda8d6… drh 442 case 'r': c = '\r'; break;
dbda8d6… drh 443 case 'v': c = '\v'; break;
dbda8d6… drh 444 case 'f': c = '\f'; break;
dbda8d6… drh 445 case '0': c = 0; break;
dbda8d6… drh 446 case '\\': c = '\\'; break;
dbda8d6… drh 447 default: c = z[i]; break;
dbda8d6… drh 448 }
dbda8d6… drh 449 }
dbda8d6… drh 450 z[j++] = c;
dbda8d6… drh 451 }
31e94c0… drh 452 if( z[j] ) z[j] = 0;
31e94c0… drh 453 }
31e94c0… drh 454
31e94c0… drh 455
31e94c0… drh 456 /*
7d12ba5… drh 457 ** The *pz variable points to a UTF8 string. Read the next character
7d12ba5… drh 458 ** off of that string and return its codepoint value. Advance *pz to the
7d12ba5… drh 459 ** next character
7d12ba5… drh 460 */
7d12ba5… drh 461 u32 fossil_utf8_read(
7d12ba5… drh 462 const unsigned char **pz /* Pointer to string from which to read char */
7d12ba5… drh 463 ){
7d12ba5… drh 464 unsigned int c;
7d12ba5… drh 465
7d12ba5… drh 466 /*
7d12ba5… drh 467 ** This lookup table is used to help decode the first byte of
7d12ba5… drh 468 ** a multi-byte UTF8 character.
7d12ba5… drh 469 */
7d12ba5… drh 470 static const unsigned char utf8Trans1[] = {
7d12ba5… drh 471 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
7d12ba5… drh 472 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
7d12ba5… drh 473 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
7d12ba5… drh 474 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
7d12ba5… drh 475 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
7d12ba5… drh 476 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
7d12ba5… drh 477 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
7d12ba5… drh 478 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
7d12ba5… drh 479 };
9a6256c… jan.nijtmans 480
7d12ba5… drh 481 c = *((*pz)++);
7d12ba5… drh 482 if( c>=0xc0 ){
7d12ba5… drh 483 c = utf8Trans1[c-0xc0];
7d12ba5… drh 484 while( (*(*pz) & 0xc0)==0x80 ){
7d12ba5… drh 485 c = (c<<6) + (0x3f & *((*pz)++));
7d12ba5… drh 486 }
7d12ba5… drh 487 if( c<0x80
7d12ba5… drh 488 || (c&0xFFFFF800)==0xD800
7d12ba5… drh 489 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
7d12ba5… drh 490 }
7d12ba5… drh 491 return c;
7d12ba5… drh 492 }
7d12ba5… drh 493
7d12ba5… drh 494 /*
1243bf3… stephan 495 ** Encode a UTF8 string as a JSON string literal (with or without the
1243bf3… stephan 496 ** surrounding "...", depending on whether the 2nd argument is true or
1243bf3… stephan 497 ** false) and return a pointer to the encoding. Space to hold the
1243bf3… stephan 498 ** encoding is obtained from fossil_malloc() and must be freed by the
1243bf3… stephan 499 ** caller.
1243bf3… stephan 500 **
1243bf3… stephan 501 ** If nOut is not NULL then it is assigned to the length, in bytes, of
1243bf3… stephan 502 ** the returned string (its strlen(), not counting the terminating
1243bf3… stephan 503 ** NUL).
7d12ba5… drh 504 */
1243bf3… stephan 505 char *encode_json_string_literal(const char *zStr, int fAddQuotes,
1243bf3… stephan 506 int * nOut){
7d12ba5… drh 507 const unsigned char *z;
7d12ba5… drh 508 char *zOut;
7d12ba5… drh 509 u32 c;
7d12ba5… drh 510 int n, i, j;
7d12ba5… drh 511 z = (const unsigned char*)zStr;
7d12ba5… drh 512 n = 0;
006b908… drh 513 while( (c = *(z++))!=0 ){
7d12ba5… drh 514 if( c=='\\' || c=='"' ){
7d12ba5… drh 515 n += 2;
006b908… drh 516 }else if( c<' ' ){
7d12ba5… drh 517 if( c=='\n' || c=='\r' ){
7d12ba5… drh 518 n += 2;
7d12ba5… drh 519 }else{
7d12ba5… drh 520 n += 6;
7d12ba5… drh 521 }
7d12ba5… drh 522 }else{
7d12ba5… drh 523 n++;
7d12ba5… drh 524 }
7d12ba5… drh 525 }
1243bf3… stephan 526 if(fAddQuotes){
1243bf3… stephan 527 n += 2;
1243bf3… stephan 528 }
5e9c1d5… drh 529 zOut = fossil_malloc(n+1);
5e9c1d5… drh 530 if( zOut==0 ) return 0;
7d12ba5… drh 531 z = (const unsigned char*)zStr;
5e9c1d5… drh 532 i = 0;
1243bf3… stephan 533 if(fAddQuotes){
1243bf3… stephan 534 zOut[i++] = '"';
1243bf3… stephan 535 }
006b908… drh 536 while( (c = *(z++))!=0 ){
caa51de… stephan 537 if( c=='\\' || c=='"' ){
7d12ba5… drh 538 zOut[i++] = '\\';
7d12ba5… drh 539 zOut[i++] = c;
006b908… drh 540 }else if( c<' ' ){
7d12ba5… drh 541 zOut[i++] = '\\';
7d12ba5… drh 542 if( c=='\n' ){
7d12ba5… drh 543 zOut[i++] = 'n';
7d12ba5… drh 544 }else if( c=='\r' ){
7d12ba5… drh 545 zOut[i++] = 'r';
7d12ba5… drh 546 }else{
7d12ba5… drh 547 zOut[i++] = 'u';
7d12ba5… drh 548 for(j=3; j>=0; j--){
7d12ba5… drh 549 zOut[i+j] = "0123456789abcdef"[c&0xf];
7d12ba5… drh 550 c >>= 4;
7d12ba5… drh 551 }
7d12ba5… drh 552 i += 4;
7d12ba5… drh 553 }
7d12ba5… drh 554 }else{
7d12ba5… drh 555 zOut[i++] = c;
7d12ba5… drh 556 }
7d12ba5… drh 557 }
1243bf3… stephan 558 if(fAddQuotes){
1243bf3… stephan 559 zOut[i++] = '"';
1243bf3… stephan 560 }
7d12ba5… drh 561 zOut[i] = 0;
1243bf3… stephan 562 if(nOut!=0){
1243bf3… stephan 563 *nOut = i;
1243bf3… stephan 564 }
5e9c1d5… drh 565 return zOut;
7d12ba5… drh 566 }
7d12ba5… drh 567
7d12ba5… drh 568 /*
dbda8d6… drh 569 ** The characters used for HTTP base64 encoding.
dbda8d6… drh 570 */
20d02ab… jan.nijtmans 571 static unsigned char zBase[] =
c198613… drh 572 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
dbda8d6… drh 573
dbda8d6… drh 574 /*
5200323… drh 575 ** Translate nData bytes of content from zData into
5200323… drh 576 ** ((nData+2)/3)*4) bytes of base64 encoded content and
5200323… drh 577 ** put the result in z64. Add a zero-terminator at the end.
dbda8d6… drh 578 */
5200323… drh 579 int translateBase64(const char *zData, int nData, char *z64){
dbda8d6… drh 580 int i, n;
dbda8d6… drh 581 for(i=n=0; i+2<nData; i+=3){
dbda8d6… drh 582 z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
dbda8d6… drh 583 z64[n++] = zBase[ ((zData[i]<<4) & 0x30) | ((zData[i+1]>>4) & 0x0f) ];
dbda8d6… drh 584 z64[n++] = zBase[ ((zData[i+1]<<2) & 0x3c) | ((zData[i+2]>>6) & 0x03) ];
dbda8d6… drh 585 z64[n++] = zBase[ zData[i+2] & 0x3f ];
dbda8d6… drh 586 }
dbda8d6… drh 587 if( i+1<nData ){
dbda8d6… drh 588 z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
dbda8d6… drh 589 z64[n++] = zBase[ ((zData[i]<<4) & 0x30) | ((zData[i+1]>>4) & 0x0f) ];
dbda8d6… drh 590 z64[n++] = zBase[ ((zData[i+1]<<2) & 0x3c) ];
c198613… drh 591 z64[n++] = '=';
dbda8d6… drh 592 }else if( i<nData ){
dbda8d6… drh 593 z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
dbda8d6… drh 594 z64[n++] = zBase[ ((zData[i]<<4) & 0x30) ];
c198613… drh 595 z64[n++] = '=';
c198613… drh 596 z64[n++] = '=';
dbda8d6… drh 597 }
dbda8d6… drh 598 z64[n] = 0;
5200323… drh 599 return n;
5200323… drh 600 }
5200323… drh 601
5200323… drh 602 /*
5200323… drh 603 ** Encode a string using a base-64 encoding.
5200323… drh 604 ** The encoding can be reversed using the <b>decode64</b> function.
5200323… drh 605 **
5200323… drh 606 ** Space to hold the result comes from malloc().
5200323… drh 607 */
5200323… drh 608 char *encode64(const char *zData, int nData){
5200323… drh 609 char *z64;
5200323… drh 610 if( nData<=0 ){
5200323… drh 611 nData = strlen(zData);
5200323… drh 612 }
5200323… drh 613 z64 = fossil_malloc( (nData*4)/3 + 8 );
5200323… drh 614 translateBase64(zData, nData, z64);
dbda8d6… drh 615 return z64;
dbda8d6… drh 616 }
c198613… drh 617
c198613… drh 618 /*
20d02ab… jan.nijtmans 619 ** COMMAND: test-encode64
c3b5f1d… jan.nijtmans 620 **
c198613… drh 621 ** Usage: %fossil test-encode64 STRING
c198613… drh 622 */
c198613… drh 623 void test_encode64_cmd(void){
c198613… drh 624 char *z;
c198613… drh 625 int i;
c198613… drh 626 for(i=2; i<g.argc; i++){
c198613… drh 627 z = encode64(g.argv[i], -1);
d8ec765… drh 628 fossil_print("%s\n", z);
c198613… drh 629 free(z);
c198613… drh 630 }
c3b5f1d… jan.nijtmans 631 }
c3b5f1d… jan.nijtmans 632
c3b5f1d… jan.nijtmans 633
d0ae089… drh 634 /* Decode base64 text. Write the output into zData. The caller
d0ae089… drh 635 ** must ensure that zData is large enough. It is ok for z64 and
d0ae089… drh 636 ** zData to be the same buffer. In other words, it is ok to decode
d0ae089… drh 637 ** in-place. A zero terminator is always placed at the end of zData.
d0ae089… drh 638 */
d0ae089… drh 639 void decodeBase64(const char *z64, int *pnByte, char *zData){
d0ae089… drh 640 const unsigned char *zIn = (const unsigned char*)z64;
d0ae089… drh 641 int i, j, k;
d0ae089… drh 642 int x[4];
d0ae089… drh 643 static int isInit = 0;
d0ae089… drh 644 static signed char trans[256];
d0ae089… drh 645
d0ae089… drh 646 if( !isInit ){
d0ae089… drh 647 for(i=0; i<256; i++){ trans[i] = -1; }
d0ae089… drh 648 for(i=0; zBase[i]; i++){ trans[zBase[i] & 0x7f] = i; }
d0ae089… drh 649 isInit = 1;
d0ae089… drh 650 }
d0ae089… drh 651 for(j=k=0; zIn[0]; zIn++){
d0ae089… drh 652 int v = trans[zIn[0]];
d0ae089… drh 653 if( v>=0 ){
d0ae089… drh 654 x[k++] = v;
d0ae089… drh 655 if( k==4 ){
d0ae089… drh 656 zData[j++] = ((x[0]<<2) & 0xfc) | ((x[1]>>4) & 0x03);
d0ae089… drh 657 zData[j++] = ((x[1]<<4) & 0xf0) | ((x[2]>>2) & 0x0f);
d0ae089… drh 658 zData[j++] = ((x[2]<<6) & 0xc0) | (x[3] & 0x3f);
d0ae089… drh 659 k = 0;
d0ae089… drh 660 }
d0ae089… drh 661 }
d0ae089… drh 662 }
d0ae089… drh 663 if( k>=2 ){
d0ae089… drh 664 zData[j++] = ((x[0]<<2) & 0xfc) | ((x[1]>>4) & 0x03);
d0ae089… drh 665 if( k==3 ){
d0ae089… drh 666 zData[j++] = ((x[1]<<4) & 0xf0) | ((x[2]>>2) & 0x0f);
d0ae089… drh 667 }
d0ae089… drh 668 }
d0ae089… drh 669 zData[j] = 0;
d0ae089… drh 670 *pnByte = j;
d0ae089… drh 671 }
d0ae089… drh 672
d0ae089… drh 673
dbda8d6… drh 674 /*
dbda8d6… drh 675 ** This function treats its input as a base-64 string and returns the
dbda8d6… drh 676 ** decoded value of that string. Characters of input that are not
dbda8d6… drh 677 ** valid base-64 characters (such as spaces and newlines) are ignored.
dbda8d6… drh 678 **
dbda8d6… drh 679 ** Space to hold the decoded string is obtained from malloc().
dbda8d6… drh 680 **
dbda8d6… drh 681 ** The number of bytes decoded is returned in *pnByte
dbda8d6… drh 682 */
dbda8d6… drh 683 char *decode64(const char *z64, int *pnByte){
dbda8d6… drh 684 char *zData;
d0ae089… drh 685 int n64 = (int)strlen(z64);
dbda8d6… drh 686 while( n64>0 && z64[n64-1]=='=' ) n64--;
8f41b2f… drh 687 zData = fossil_malloc( (n64*3)/4 + 4 );
d0ae089… drh 688 decodeBase64(z64, pnByte, zData);
dbda8d6… drh 689 return zData;
c198613… drh 690 }
c198613… drh 691
c198613… drh 692 /*
20d02ab… jan.nijtmans 693 ** COMMAND: test-decode64
c3b5f1d… jan.nijtmans 694 **
c198613… drh 695 ** Usage: %fossil test-decode64 STRING
c198613… drh 696 */
c198613… drh 697 void test_decode64_cmd(void){
c198613… drh 698 char *z;
c198613… drh 699 int i, n;
c198613… drh 700 for(i=2; i<g.argc; i++){
c198613… drh 701 z = decode64(g.argv[i], &n);
d8ec765… drh 702 fossil_print("%d: %s\n", n, z);
d0ae089… drh 703 fossil_free(z);
c198613… drh 704 }
dbda8d6… drh 705 }
dbda8d6… drh 706
dbda8d6… drh 707 /*
dbda8d6… drh 708 ** The base-16 encoding using the following characters:
dbda8d6… drh 709 **
dbda8d6… drh 710 ** 0123456789abcdef
dbda8d6… drh 711 **
dbda8d6… drh 712 */
dbda8d6… drh 713
dbda8d6… drh 714 /*
dbda8d6… drh 715 ** The array used for encoding
dbda8d6… drh 716 */ /* 123456789 12345 */
20d02ab… jan.nijtmans 717 static const char zEncode[] = "0123456789abcdef";
dbda8d6… drh 718
dbda8d6… drh 719 /*
dbda8d6… drh 720 ** Encode a N-digit base-256 in base-16. Return zero on success
dbda8d6… drh 721 ** and non-zero if there is an error.
dbda8d6… drh 722 */
dbda8d6… drh 723 int encode16(const unsigned char *pIn, unsigned char *zOut, int N){
dbda8d6… drh 724 int i;
dbda8d6… drh 725 for(i=0; i<N; i++){
d0305b3… aku 726 *(zOut++) = zEncode[pIn[i]>>4];
d0305b3… aku 727 *(zOut++) = zEncode[pIn[i]&0xf];
dbda8d6… drh 728 }
dbda8d6… drh 729 *zOut = 0;
dbda8d6… drh 730 return 0;
dbda8d6… drh 731 }
dbda8d6… drh 732
dbda8d6… drh 733 /*
dbda8d6… drh 734 ** An array for translating single base-16 characters into a value.
dbda8d6… drh 735 ** Disallowed input characters have a value of 64. Upper and lower
20d02ab… jan.nijtmans 736 ** case is the same.
dbda8d6… drh 737 */
dbda8d6… drh 738 static const char zDecode[] = {
20d02ab… jan.nijtmans 739 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 740 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 741 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 742 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 64, 64, 64, 64, 64, 64,
c320b85… drh 743 64, 10, 11, 12, 13, 14, 15, 64, 64, 64, 64, 64, 64, 64, 64, 64,
c320b85… drh 744 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
c320b85… drh 745 64, 10, 11, 12, 13, 14, 15, 64, 64, 64, 64, 64, 64, 64, 64, 64,
c320b85… drh 746 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 747 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 748 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 749 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 750 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 751 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 752 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 753 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
20d02ab… jan.nijtmans 754 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
dbda8d6… drh 755 };
dbda8d6… drh 756
dbda8d6… drh 757 /*
20d02ab… jan.nijtmans 758 ** Decode a N-character base-16 number into base-256. N must be a
dbda8d6… drh 759 ** multiple of 2. The output buffer must be at least N/2 characters
dbda8d6… drh 760 ** in length
dbda8d6… drh 761 */
dbda8d6… drh 762 int decode16(const unsigned char *zIn, unsigned char *pOut, int N){
dbda8d6… drh 763 int i, j;
dbda8d6… drh 764 if( (N&1)!=0 ) return 1;
dbda8d6… drh 765 for(i=j=0; i<N; i += 2, j++){
dbda8d6… drh 766 int v1, v2, a;
dbda8d6… drh 767 a = zIn[i];
dbda8d6… drh 768 if( (a & 0x80)!=0 || (v1 = zDecode[a])==64 ) return 1;
dbda8d6… drh 769 a = zIn[i+1];
dbda8d6… drh 770 if( (a & 0x80)!=0 || (v2 = zDecode[a])==64 ) return 1;
dbda8d6… drh 771 pOut[j] = (v1<<4) + v2;
dbda8d6… drh 772 }
dbda8d6… drh 773 return 0;
dbda8d6… drh 774 }
dbda8d6… drh 775
dbda8d6… drh 776
dbda8d6… drh 777 /*
dbda8d6… drh 778 ** Return true if the input string contains only valid base-16 digits.
dbda8d6… drh 779 ** If any invalid characters appear in the string, return false.
dbda8d6… drh 780 */
dbda8d6… drh 781 int validate16(const char *zIn, int nIn){
4c37130… drh 782 int i;
b77f1aa… drh 783 if( nIn<0 ) nIn = (int)strlen(zIn);
c550d6e… drh 784 if( zIn[nIn]==0 ){
53db40e… drh 785 return (int)strspn(zIn,"0123456789abcdefABCDEF")==nIn;
c550d6e… drh 786 }
4c37130… drh 787 for(i=0; i<nIn; i++, zIn++){
4c37130… drh 788 if( zDecode[zIn[0]&0xff]>63 ){
4c37130… drh 789 return zIn[0]==0;
4c37130… drh 790 }
dbda8d6… drh 791 }
dbda8d6… drh 792 return 1;
dbda8d6… drh 793 }
dbda8d6… drh 794
dbda8d6… drh 795 /*
dbda8d6… drh 796 ** The input string is a base16 value. Convert it into its canonical
dbda8d6… drh 797 ** form. This means that digits are all lower case and that conversions
dbda8d6… drh 798 ** like "l"->"1" and "O"->"0" occur.
dbda8d6… drh 799 */
dbda8d6… drh 800 void canonical16(char *z, int n){
dbda8d6… drh 801 while( *z && n-- ){
dbda8d6… drh 802 *z = zEncode[zDecode[(*z)&0x7f]&0x1f];
dbda8d6… drh 803 z++;
cfbbad3… drh 804 }
d0ae089… drh 805 }
593ceca… drh 806
593ceca… drh 807 /*
593ceca… drh 808 ** Decode hexadecimal into a string and return the new string. Space to
593ceca… drh 809 ** hold the string is obtained from fossil_malloc() and should be released
593ceca… drh 810 ** by the caller.
593ceca… drh 811 **
593ceca… drh 812 ** If the input is not hex, return NULL.
593ceca… drh 813 */
593ceca… drh 814 char *decode16_dup(const char *zIn){
593ceca… drh 815 int nIn = (int)strlen(zIn);
593ceca… drh 816 char *zOut;
593ceca… drh 817 if( !validate16(zIn, nIn) ) return 0;
593ceca… drh 818 zOut = fossil_malloc(nIn/2+1);
593ceca… drh 819 decode16((const u8*)zIn, (u8*)zOut, nIn);
593ceca… drh 820 zOut[nIn/2] = 0;
593ceca… drh 821 return zOut;
593ceca… drh 822 }
593ceca… drh 823
d0ae089… drh 824
d0ae089… drh 825 /*
d0ae089… drh 826 ** Decode a string encoded using "quoted-printable".
d0ae089… drh 827 **
d0ae089… drh 828 ** (1) "=" followed by two hex digits becomes a single
d0ae089… drh 829 ** byte specified by the two digits
d0ae089… drh 830 **
d0ae089… drh 831 ** The decoding is done in-place.
d0ae089… drh 832 */
d0ae089… drh 833 void decodeQuotedPrintable(char *z, int *pnByte){
d0ae089… drh 834 int i, j, c;
d0ae089… drh 835 for(i=j=0; (c = z[i])!=0; i++){
d0ae089… drh 836 if( c=='=' ){
d0ae089… drh 837 if( z[i+1]!='\r' ){
d0ae089… drh 838 decode16((unsigned char*)&z[i+1], (unsigned char*)&z[j], 2);
d0ae089… drh 839 j++;
d0ae089… drh 840 }
d0ae089… drh 841 i += 2;
d0ae089… drh 842 }else{
d0ae089… drh 843 z[j++] = c;
d0ae089… drh 844 }
d0ae089… drh 845 }
d0ae089… drh 846 if( pnByte ) *pnByte = j;
d0ae089… drh 847 z[j] = 0;
20d02ab… jan.nijtmans 848 }
20d02ab… jan.nijtmans 849
cfbbad3… drh 850 /* Randomness used for XOR-ing by the obscure() and unobscure() routines */
cfbbad3… drh 851 static const unsigned char aObscurer[16] = {
cfbbad3… drh 852 0xa7, 0x21, 0x31, 0xe3, 0x2a, 0x50, 0x2c, 0x86,
cfbbad3… drh 853 0x4c, 0xa4, 0x52, 0x25, 0xff, 0x49, 0x35, 0x85
cfbbad3… drh 854 };
20d02ab… jan.nijtmans 855
cfbbad3… drh 856
cfbbad3… drh 857 /*
cfbbad3… drh 858 ** Obscure plain text so that it is not easily readable.
cfbbad3… drh 859 **
cfbbad3… drh 860 ** This is used for storing sensitive information (such as passwords) in a
cfbbad3… drh 861 ** way that prevents their exposure through idle browsing. This is not
cfbbad3… drh 862 ** encryption. Anybody who really wants the password can still get it.
cfbbad3… drh 863 **
cfbbad3… drh 864 ** The text is XOR-ed with a repeating pattern then converted to hex.
cfbbad3… drh 865 ** Space to hold the returned string is obtained from malloc and should
cfbbad3… drh 866 ** be freed by the caller.
cfbbad3… drh 867 */
cfbbad3… drh 868 char *obscure(const char *zIn){
cfbbad3… drh 869 int n, i;
cfbbad3… drh 870 unsigned char salt;
cfbbad3… drh 871 char *zOut;
20d02ab… jan.nijtmans 872
26c262c… drh 873 if( zIn==0 ) return 0;
cfbbad3… drh 874 n = strlen(zIn);
8f41b2f… drh 875 zOut = fossil_malloc( n*2+3 );
cfbbad3… drh 876 sqlite3_randomness(1, &salt);
cfbbad3… drh 877 zOut[n+1] = (char)salt;
cfbbad3… drh 878 for(i=0; i<n; i++) zOut[i+n+2] = zIn[i]^aObscurer[i&0x0f]^salt;
cfbbad3… drh 879 encode16((unsigned char*)&zOut[n+1], (unsigned char*)zOut, n+1);
cfbbad3… drh 880 return zOut;
cfbbad3… drh 881 }
cfbbad3… drh 882
cfbbad3… drh 883 /*
cfbbad3… drh 884 ** Undo the obscuring of text performed by obscure(). Or, if the input is
cfbbad3… drh 885 ** not hexadecimal (meaning the input is not the output of obscure()) then
cfbbad3… drh 886 ** do the equivalent of strdup().
cfbbad3… drh 887 **
20d02ab… jan.nijtmans 888 ** The result is memory obtained from malloc that should be freed by the caller.
cfbbad3… drh 889 */
cfbbad3… drh 890 char *unobscure(const char *zIn){
cfbbad3… drh 891 int n, i;
cfbbad3… drh 892 unsigned char salt;
cfbbad3… drh 893 char *zOut;
20d02ab… jan.nijtmans 894
26c262c… drh 895 if( zIn==0 ) return 0;
cfbbad3… drh 896 n = strlen(zIn);
8f41b2f… drh 897 zOut = fossil_malloc( n + 1 );
cfbbad3… drh 898 if( n<2
cfbbad3… drh 899 || decode16((unsigned char*)zIn, &salt, 2)
cfbbad3… drh 900 || decode16((unsigned char*)&zIn[2], (unsigned char*)zOut, n-2)
cfbbad3… drh 901 ){
cfbbad3… drh 902 memcpy(zOut, zIn, n+1);
cfbbad3… drh 903 }else{
cfbbad3… drh 904 n = n/2 - 1;
cfbbad3… drh 905 for(i=0; i<n; i++) zOut[i] = zOut[i]^aObscurer[i&0x0f]^salt;
cfbbad3… drh 906 zOut[n] = 0;
cfbbad3… drh 907 }
cfbbad3… drh 908 return zOut;
cfbbad3… drh 909 }
cfbbad3… drh 910
cfbbad3… drh 911 /*
cfbbad3… drh 912 ** Command to test obscure() and unobscure(). These commands are also useful
cfbbad3… drh 913 ** utilities for decoding passwords found in the database.
cfbbad3… drh 914 **
cfbbad3… drh 915 ** COMMAND: test-obscure
7ab0328… drh 916 **
7ab0328… drh 917 ** For each command-line argument X, run both obscure(X) and
7ab0328… drh 918 ** unobscure(obscure(X)) and print the results. This is used for testing
7ab0328… drh 919 ** and debugging of the obscure() and unobscure() functions.
cfbbad3… drh 920 */
cfbbad3… drh 921 void test_obscure_cmd(void){
cfbbad3… drh 922 int i;
cfbbad3… drh 923 char *z, *z2;
cfbbad3… drh 924 for(i=2; i<g.argc; i++){
cfbbad3… drh 925 z = obscure(g.argv[i]);
cfbbad3… drh 926 z2 = unobscure(z);
d8ec765… drh 927 fossil_print("OBSCURE: %s -> %s (%s)\n", g.argv[i], z, z2);
cfbbad3… drh 928 free(z);
cfbbad3… drh 929 free(z2);
cfbbad3… drh 930 z = unobscure(g.argv[i]);
d8ec765… drh 931 fossil_print("UNOBSCURE: %s -> %s\n", g.argv[i], z);
cfbbad3… drh 932 free(z);
007d1ce… drh 933 }
dbda8d6… drh 934 }

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button