1 /*** Extension-formats
2 *
3 * This file adds the following file format support to SQLite.
4 *
5 * Plist - An XML like encoding
6 * Base64 - Standard binary to text conversion
7 *
8 * Compile using:
9 *
10 * gcc -g -fPIC -shared extension-formats.c -o libsqlite-formats.so
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <stdint.h>
18 #include <time.h>
19 #include <assert.h>
20
21 #define COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE 1
22 #include "sqlite3ext.h"
23 SQLITE_EXTENSION_INIT1
24
25 #define INDENT_INCREMENT 4
26
27 #define ERROR_NONE 0
28 #define ERROR_INSUFFICIENT_MEMORY 1
29 #define ERROR_INVALID_HEADER 2
30 #define ERROR_INVALID_TRAILER 3
31 #define ERROR_INVALID_OFFSET 4
32 #define ERROR_INVALID_OBJECT_LENGTH 5
33 #define ERROR_INVALID_REFERENCE 6
34 #define ERROR_INVALID_CHARACTER 7
35
36 typedef struct KEY {
37 struct OBJECT *key;
38 struct OBJECT *value;
39 } KEY;
40
41 typedef struct OBJECT {
42 int type;
43 int length;
44 union {
45 time_t date;
46 double real;
47 long integer;
48 unsigned long uid;
49 unsigned char binary[1];
50 char text[1];
51 short int utf16[1];
52 int refs[1];
53 KEY keys[1];
54 struct OBJECT *objects[1];
55 } data;
56 } OBJECT;
57
58 typedef struct CONFIG {
59 int bytesPerOffset;
60 int bytesPerReference;
61 int objectCount;
62 int rootObjectReference;
63 int offsetTableOffset;
64 size_t bufferLength;
65 size_t outputBufferLength;
66 size_t outputBufferIn;
67 long *offsetTable;
68 unsigned char *buffer;
69 unsigned char *outputBuffer;
70 } CONFIG;
71
72 int createObject(int type, int length, int extra, OBJECT **ptr2);
73 int readObject(CONFIG *cfg, long offset, OBJECT **ptr2);
74
75 static int indent = 2;
76
outputText(CONFIG * cfg,const char * text)77 int outputText(CONFIG *cfg, const char *text)
78 {
79 size_t textLength = strlen(text);
80 size_t availableSpace = cfg->outputBufferLength - cfg->outputBufferIn;
81 while (textLength >= availableSpace) {
82 unsigned char *tmp = cfg->outputBuffer;
83 cfg->outputBufferLength += textLength + 1024;
84 cfg->outputBuffer = (unsigned char *)realloc(cfg->outputBuffer, cfg->outputBufferLength);
85 if (cfg->outputBuffer == NULL) {
86 if (tmp != NULL)
87 free(tmp);
88 return ERROR_INSUFFICIENT_MEMORY;
89 }
90 availableSpace = cfg->outputBufferLength - cfg->outputBufferIn;
91 }
92 strcpy((char *)(cfg->outputBuffer+cfg->outputBufferIn), text);
93 cfg->outputBufferIn += textLength;
94 return ERROR_NONE;
95 }
96
printWithIndent(CONFIG * cfg,const char * text,int newline)97 int printWithIndent(CONFIG *cfg, const char *text, int newline)
98 {
99 int err = ERROR_NONE;
100 char spaces[9] = " ";
101 int n = indent;
102 while ((n > 8) && (err == ERROR_NONE)) {
103 err = outputText(cfg, spaces);
104 n -= 8;
105 }
106 if ((n > 0) && (err == ERROR_NONE))
107 err = outputText(cfg, spaces + 8 - n);
108 if (err == ERROR_NONE)
109 err = outputText(cfg, text);
110 if (newline && (err == ERROR_NONE))
111 err = outputText(cfg, "\n");
112 return err;
113 }
114
readHeader(CONFIG * cfg)115 int readHeader(CONFIG *cfg)
116 {
117 if ((cfg->bufferLength < 40) ||
118 (strncmp((const char *)(cfg->buffer), "bplist0", 7) != 0) ||
119 ((cfg->buffer[7] != '0') && (cfg->buffer[7] != '1')))
120 return ERROR_INVALID_HEADER;
121 return ERROR_NONE;
122 }
123
readTrailer(CONFIG * cfg)124 int readTrailer(CONFIG *cfg)
125 {
126 int i, j;
127 int objectCount = 0;
128 int rootObjectReference = 0;
129 int offsetTableOffset = 0;
130 unsigned char *ptr;
131 unsigned char *buffer = cfg->buffer + cfg->bufferLength - 32;
132
133 // Extract the relevant fields
134 for (i=12; i < 16; i++)
135 objectCount = (objectCount << 8) + buffer[i];
136 for (i=20; i < 24; i++)
137 rootObjectReference = (rootObjectReference << 8) + buffer[i];
138 for (i=28; i < 32; i++)
139 offsetTableOffset = (offsetTableOffset << 8) + buffer[i];
140
141 // Populate the configurartion structure
142 cfg->bytesPerOffset = buffer[6];
143 cfg->bytesPerReference = buffer[7];
144 cfg->objectCount = objectCount;
145 cfg->rootObjectReference = rootObjectReference;
146 cfg->offsetTableOffset = offsetTableOffset;
147 cfg->offsetTable = (long *)malloc((size_t)objectCount * sizeof(long));
148 if (cfg->offsetTable == NULL)
149 return ERROR_INSUFFICIENT_MEMORY;
150 ptr = cfg->buffer + offsetTableOffset;
151 for (i=0; i < objectCount; i++) {
152 long n = 0;
153 for (j=0; j < cfg->bytesPerOffset; j++)
154 n = (n << 8) | *(ptr++);
155 cfg->offsetTable[i] = n;
156 }
157 return ERROR_NONE;
158 }
159
createObject(int type,int length,int extra,OBJECT ** ptr2)160 int createObject(int type, int length, int extra, OBJECT **ptr2)
161 {
162 *ptr2 = NULL;
163 OBJECT *ptr = (OBJECT *)malloc(sizeof(OBJECT) + (size_t)extra);
164 if (ptr == NULL)
165 return ERROR_INSUFFICIENT_MEMORY;
166 ptr->type = type;
167 ptr->length = length;
168 *ptr2 = ptr;
169 return ERROR_NONE;
170 }
171
readInteger(unsigned char * ptr,int desc)172 long readInteger(unsigned char *ptr, int desc)
173 {
174 long value = 0L;
175 int n = 1 << (desc & 0x03);
176 while (n--)
177 value = (value << 8) | (long)(*(ptr++));
178 return value;
179 }
180
readUid(unsigned char * ptr,int desc)181 unsigned long readUid(unsigned char *ptr, int desc)
182 {
183 unsigned long value = 0L;
184 int n = 1 << (desc & 0x03);
185 while (n--)
186 value = (value << 8) | (unsigned long)(*(ptr++));
187 return value;
188 }
189
readDouble(unsigned char * ptr,int desc)190 double readDouble(unsigned char *ptr, int desc)
191 {
192 union {
193 double v;
194 float f[2];
195 unsigned char b[8];
196 } value;
197 int n = 1 << (desc & 0x03);
198 for (int i=0; i < n; i++)
199 value.b[7-i] = *(ptr++);
200 if (n == 4)
201 value.v = (double)(value.f[1]);
202 return value.v;
203 }
204
readArray(CONFIG * cfg,unsigned char * ptr,int type,int length,OBJECT ** array2)205 int readArray(CONFIG *cfg, unsigned char *ptr, int type, int length, OBJECT **array2)
206 {
207 int i;
208 long offset;
209 OBJECT *array;
210 int err = createObject(type, length, ((length-1) * (int)sizeof(OBJECT)), &array);
211 *array2 = NULL;
212 for (i=0; (i < length) && (err == ERROR_NONE); i++) {
213 offset = 0L;
214 for (int j=0; j < cfg->bytesPerReference; j++)
215 offset = (offset << 8) | (long)(*(ptr++));
216 if (offset >= cfg->objectCount)
217 return ERROR_INVALID_REFERENCE;
218 offset = cfg->offsetTable[offset];
219 err = readObject(cfg, offset, &(array->data.objects[i]));
220 }
221 if (err == ERROR_NONE)
222 *array2 = array;
223 return err;
224 }
225
readDictionary(CONFIG * cfg,unsigned char * ptr,int type,int length,OBJECT ** dict2)226 int readDictionary(CONFIG *cfg, unsigned char *ptr, int type, int length, OBJECT **dict2)
227 {
228 int i;
229 long offset;
230 OBJECT *dict;
231 int err = createObject(type, length, ((length-1) * (int)sizeof(KEY)), &dict);
232 *dict2 = NULL;
233 if (err != ERROR_NONE)
234 return err;
235 for (i=0; (i < length) && (err == ERROR_NONE); i++) {
236 offset = 0L;
237 for (int j=0; j < cfg->bytesPerReference; j++)
238 offset = (offset << 8) | (long)(*(ptr++));
239 if (offset >= cfg->objectCount)
240 return ERROR_INVALID_REFERENCE;
241 offset = cfg->offsetTable[offset];
242 err = readObject(cfg, offset, &(dict->data.keys[i].key));
243 }
244 for (i=0; (i < length) && (err == ERROR_NONE); i++) {
245 offset = 0L;
246 for (int j=0; j < cfg->bytesPerReference; j++)
247 offset = (offset << 8) | (long)(*(ptr++));
248 if (offset >= cfg->objectCount)
249 return ERROR_INVALID_REFERENCE;
250 offset = cfg->offsetTable[offset];
251 err = readObject(cfg, offset, &(dict->data.keys[i].value));
252 }
253 if (err == ERROR_NONE)
254 *dict2 = dict;
255 return err;
256 }
257
readObject(CONFIG * cfg,long offset,OBJECT ** ptr2)258 int readObject(CONFIG *cfg, long offset, OBJECT **ptr2)
259 {
260 int i;
261 int length;
262 int type;
263 int err = ERROR_NONE;
264 OBJECT *obj;
265 unsigned char *ptr;
266
267 *ptr2 = NULL;
268 if ((size_t)offset >= cfg->bufferLength)
269 return ERROR_INVALID_OFFSET;
270 ptr = cfg->buffer + offset;
271 type = *(ptr++);
272 length = (type & 0x0F);
273 type >>= 4;
274 if ((type != 0) && (length == 0x0F)) {
275 length = *(ptr++);
276 if ((length >> 4) != 0x01)
277 return ERROR_INVALID_OBJECT_LENGTH;
278 i = (int)readInteger(ptr, length);
279 ptr += (1 << (length & 0x03));
280 length = i;
281 }
282 switch (type) {
283 case 0x00: // Singleton
284 err = createObject(type, length, 5, &obj);
285 if (err != ERROR_NONE)
286 return err;
287 switch(length) {
288 case 0: // NULL
289 strcpy(obj->data.text, "<Null/>");
290 break;
291 case 8: // False
292 strcpy(obj->data.text, "<False/>");
293 break;
294 case 9: // True
295 strcpy(obj->data.text, "<True/>");
296 break;
297 case 15: // Fill
298 strcpy(obj->data.text, "<Fill/>");
299 break;
300 default: // Illegal
301 strcpy(obj->data.text, "***Error***");
302 break;
303 }
304 break;
305 case 0x01: // Integer
306 err = createObject(type, length, 0, &obj);
307 if (err != ERROR_NONE)
308 return err;
309 obj->data.integer = readInteger(ptr, length);
310 break;
311 case 0x02: // Float
312 err = createObject(type, length, 0, &obj);
313 if (err != ERROR_NONE)
314 return err;
315 obj->data.real = readDouble(ptr, length);
316 break;
317 case 0x03: // Date in Elapsed seconds
318 err = createObject(type, length, 0, &obj);
319 if (err != ERROR_NONE)
320 return err;
321 obj->data.date = (time_t)readDouble(ptr, length);
322 break;
323 case 0x04: // binary data
324 err = createObject(type, length, length, &obj);
325 if (err != ERROR_NONE)
326 return err;
327 for (i=0; i < length; i++)
328 obj->data.binary[i] = *(ptr++);
329 break;
330 case 0x05: // ASCII string
331 err = createObject(type, length, length, &obj);
332 if (err != ERROR_NONE)
333 return err;
334 for (i=0; i < length; i++)
335 obj->data.text[i] = (char)*(ptr++);
336 obj->data.text[length] = '\0';
337 break;
338 case 0x06: // UTF16 string
339 err = createObject(type, length, 2 * length, &obj);
340 if (err != ERROR_NONE)
341 return err;
342 for (i=0; i < length; i++) {
343 short int d = *(ptr++);
344 obj->data.utf16[i] = (short int)((d << 8) | *(ptr++));
345 }
346 obj->data.utf16[length] = '\0';
347 break;
348 case 0x08: // UID
349 err = createObject(type, length, 0, &obj);
350 if (err != ERROR_NONE)
351 return err;
352 obj->data.uid = readUid(ptr, length);
353 break;
354 case 0x0A: // Array
355 err = readArray(cfg, ptr, type, length, &obj);
356 break;
357 case 0x0D: // Dictionary
358 err = readDictionary(cfg, ptr, type, length, &obj);
359 break;
360 default:
361 fprintf(stderr, "Unknown object type: %d\n", type);
362 err = createObject(type, length, 0, &obj);
363 break;
364 }
365 if (err == ERROR_NONE)
366 *ptr2 = obj;
367 return err;
368 }
369
displayHex(CONFIG * cfg,int data)370 void displayHex(CONFIG *cfg, int data)
371 {
372 static int in = 0;
373 static char buffer[76];
374 static long offset = 0L;
375 static char hex[] = "0123456789ABCDEF";
376 char *tmp;
377
378 // If -ve then flush buffer
379 if (data < 0) {
380 if (in > 0) {
381 tmp = buffer + in * 3 + 8 + 2 * (in / 8);
382 while (tmp < buffer+59)
383 *(tmp++) = ' ';
384 buffer[in+59] = '\0';
385 printWithIndent(cfg, buffer, 1);
386 }
387 offset = 0L;
388 in = 0;
389 return;
390 }
391
392 // If start of line add offset
393 if (in == 0) {
394 sprintf((char *)buffer, "%06lX ", offset);
395 offset += 16;
396 buffer[8] = '\0';
397 }
398
399 // Add Byte in hex
400 tmp = buffer + in * 3 + 8 + 2 * (in / 8);
401 *(tmp++) = hex[(data >> 4) & 0x0F];
402 *(tmp++) = hex[data & 0x0F];
403 *(tmp++) = ' ';
404
405 // Add to character buffer
406 buffer[in+59] = (char)data;
407
408 // Check if midpoint of buffer
409 if (++in == 8) {
410 *(tmp++) = '-';
411 *(tmp++) = ' ';
412 }
413
414 // Check if buffer full
415 if (in == 16) {
416 buffer[75] = '\0';
417 printWithIndent(cfg, buffer, 1);
418 in = 0;
419 }
420 return;
421 }
422
displayObject(CONFIG * cfg,OBJECT * obj,int raw)423 int displayObject(CONFIG *cfg, OBJECT *obj, int raw)
424 {
425 char text[32];
426 switch (obj->type) {
427 case 0x00: // Singleton
428 printWithIndent(cfg, obj->data.text, 1);
429 break;
430 case 0x01: // Integer
431 if (raw == 0)
432 printWithIndent(cfg, "<number>", 0);
433 sprintf(text, "%ld", obj->data.integer);
434 outputText(cfg, text);
435 if (raw == 0)
436 outputText(cfg, "</number>\n");
437 break;
438 case 0x02: // Float
439 if (raw == 0)
440 printWithIndent(cfg, "<float>", 0);
441 sprintf(text, "%f", obj->data.real);
442 outputText(cfg, text);
443 if (raw == 0)
444 outputText(cfg, "</float>\n");
445 break;
446 case 0x03: // Date
447 if (raw == 0)
448 printWithIndent(cfg, "<date>", 0);
449 outputText(cfg, ctime(&(obj->data.date)));
450 if (raw == 0)
451 outputText(cfg, "</date>\n");
452 break;
453 case 0x04: // Binary data
454 if (raw == 0)
455 printWithIndent(cfg, "<data>", 1);
456 indent += INDENT_INCREMENT;
457 for (int i=0; i < obj->length; i++)
458 displayHex(cfg, obj->data.binary[i]);
459 displayHex(cfg, -1);
460 indent -= INDENT_INCREMENT;
461 if (raw == 0)
462 printWithIndent(cfg, "</data>", 1);
463 break;
464 case 0x05: // String
465 if (raw == 0)
466 printWithIndent(cfg, "<string>", 0);
467 outputText(cfg, (obj->data.text));
468 if (raw == 0)
469 outputText(cfg, "</string>\n");
470 break;
471 case 0x06: // UTF16 string
472 if (raw == 0)
473 printWithIndent(cfg, "<utf16>", 1);
474 indent += INDENT_INCREMENT;
475 for (int i=0; i < obj->length; i++)
476 displayHex(cfg, obj->data.binary[i]);
477 displayHex(cfg, -1);
478 indent -= INDENT_INCREMENT;
479 if (raw == 0)
480 printWithIndent(cfg, "</utf16>", 1);
481 break;
482 case 0x08: // UID
483 if (raw == 0)
484 printWithIndent(cfg, "<uid>", 0);
485 sprintf(text, "%lu", obj->data.uid);
486 outputText(cfg, text);
487 if (raw == 0)
488 outputText(cfg, "</uid>\n");
489 break;
490 case 0x0A: // Array
491 printWithIndent(cfg, "<array>", 1);
492 indent += INDENT_INCREMENT;
493 for (int i=0; i < obj->length; i++)
494 displayObject(cfg, obj->data.objects[i], 0);
495 indent -= INDENT_INCREMENT;
496 printWithIndent(cfg, "</array>", 1);
497 break;
498 case 0x0D: // Dictionary
499 printWithIndent(cfg, "<dict>", 1);
500 indent += INDENT_INCREMENT;
501 for (int i=0; i < obj->length; i++) {
502 printWithIndent(cfg, "<key>", 0);
503 displayObject(cfg, obj->data.keys[i].key, 1);
504 outputText(cfg, "</key>\n");
505 displayObject(cfg, obj->data.keys[i].value, 0);
506 }
507 indent -= INDENT_INCREMENT;
508 printWithIndent(cfg, "</dict>", 1);
509 break;
510 default:
511 sprintf(text, "Cannot display type: %d\n", obj->type);
512 outputText(cfg, text);
513 break;
514 }
515 return ERROR_NONE;
516 }
517
releaseObject(OBJECT * obj)518 int releaseObject(OBJECT *obj)
519 {
520 int i;
521 switch (obj->type) {
522 case 0x00: // Singleton
523 case 0x01: // Int
524 case 0x02: // Float
525 case 0x03: // Date
526 case 0x04: // Binary
527 case 0x05: // ASCII
528 case 0x06: // UTF16
529 case 0x08: // UID
530 break;
531 case 0x0A: // Array
532 for (i=0; i < obj->length; i++)
533 releaseObject(obj->data.objects[i]);
534 break;
535 case 0x0D: // Dictionary
536 for (i=0; i < obj->length; i++) {
537 releaseObject(obj->data.keys[i].key);
538 releaseObject(obj->data.keys[i].value);
539 }
540 break;
541 }
542 free(obj);
543 return ERROR_NONE;
544 }
545
parsePlist(char ** result,const char * data,int dataLength)546 int parsePlist(char **result, const char *data, int dataLength)
547 {
548 CONFIG cfg;
549 char *ptr;
550 OBJECT *obj;
551 int err = ERROR_NONE;
552 int version;
553 long offset;
554 long length;
555 char text[32];
556
557 // Determine the file size and save
558 cfg.buffer = (unsigned char *)data;
559 cfg.bufferLength = dataLength;
560
561 // Preset the output buffer
562 cfg.outputBufferLength = 0;
563 cfg.outputBufferIn = 0;
564 cfg.outputBuffer = NULL;
565
566 // Read the header
567 err = readHeader(&cfg);
568 if (err != ERROR_NONE)
569 return err;
570 version = (int)(cfg.buffer[7] - '0');
571
572 // Read the trailer
573 err = readTrailer(&cfg);
574 if (err != ERROR_NONE)
575 return err; // ERROR_INVALID_TRAILER;
576
577 // Locate and read the root object
578 offset = cfg.offsetTable[cfg.rootObjectReference];
579 err = readObject(&cfg, offset, &obj);
580
581 // If no error display the root object and hence the whole object tree
582 if (err != ERROR_NONE)
583 return err;
584
585 sprintf(text, "<plist version = \"1.%d\">\n", version);
586 outputText(&cfg, text);
587 displayObject(&cfg, obj, 0);
588 outputText(&cfg, "</plist>\n");
589
590 // Create return data
591 length = strlen((const char *)(cfg.outputBuffer));
592 ptr = malloc(length + 1);
593 *result = ptr;
594 if (ptr != NULL) {
595 for (int i=0; i < length; i++)
596 *(ptr++) = cfg.outputBuffer[i];
597 *ptr = '\0';
598 }
599 else
600 err = ERROR_INSUFFICIENT_MEMORY;
601
602 // Release assigned memory
603 releaseObject(obj);
604 free(cfg.offsetTable);
605 free(cfg.outputBuffer);
606 return err;
607 }
608
609 static char map[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
610
611 /** Encode Base64
612 *
613 */
614
encodeBase64(char ** result,const unsigned char * data,int dataLength)615 int encodeBase64(char **result, const unsigned char *data, int dataLength)
616 {
617 unsigned char d;
618 int b;
619 int bitsLeft = 0;
620 int in = 0;
621 int out = 0;
622 int encodedLength = dataLength * 4 / 3 + 4;
623 char *encoded = malloc(encodedLength);
624 *result = encoded;
625 if (encoded == NULL)
626 return ERROR_INSUFFICIENT_MEMORY;
627
628 while (out < dataLength) {
629 d = data[out++];
630 switch (bitsLeft) {
631 case 0:
632 encoded[in++] = map[d >> 2];
633 b = d & 0x03;
634 bitsLeft = 2;
635 break;
636 case 2:
637 b = (b << 8) | d;
638 encoded[in++] = map[b >> 4];
639 b &= 0x0F;
640 bitsLeft = 4;
641 break;
642 case 4:
643 b = (b << 8) | d;
644 encoded[in++] = map[b >> 6];
645 encoded[in++] = map[b & 0x03F];
646 bitsLeft = 0;
647 break;
648 }
649 }
650
651 /* Flush remaining bits */
652 switch (bitsLeft) {
653 case 2:
654 encoded[in++] = map[b << 4];
655 encoded[in++] = '=';
656 encoded[in++] = '=';
657 break;
658 case 4:
659 encoded[in++] = map[b << 2];
660 encoded[in++] = '=';
661 break;
662 default:
663 break;
664 }
665
666 /* Terminate as string */
667 encoded[in] = '\0';
668 return ERROR_NONE;
669 }
670
671 static unsigned char unmap[256] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 00 - 07
672 0x81, 0x80, 0x81, 0x80, 0x80, 0x81, 0x80, 0x80, // 08 - 0F
673 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 10 - 17
674 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 18 - 1F
675 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 20 - 27
676 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, // 28 - 2F
677 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 30 - 37
678 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80, // 38 - 3F
679 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 40 - 47
680 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 48 - 4F
681 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 50 - 57
682 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80, // 58 - 5F
683 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 60 - 67
684 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 68 - 6F
685 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 70 - 77
686 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 78 - 7F
687 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 80 - 87
688 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 88 - 8F
689 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 90 - 97
690 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 98 - 9F
691 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // A0 - A7
692 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // A8 - AF
693 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // B0 - B7
694 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // B8 - BF
695 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // C0 - C7
696 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // C8 - CF
697 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // D0 - D7
698 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // D8 - DF
699 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // E0 - E7
700 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // E8 - EF
701 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // F0 - F7
702 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // F8 - FF
703 };
704
705 /*** decodeBase64
706 *
707 * Returns decoded data and length.
708 */
709
decodeBase64(unsigned char ** result,int * resultLength,const char * data,int dataLength)710 int decodeBase64(unsigned char **result, int *resultLength, const char *data, int dataLength)
711 {
712 int bitsLeft = 8;
713 int in = 0;
714 unsigned char b;
715 unsigned char d;
716 unsigned char *decoded = malloc(dataLength * 3 / 4 + 3);
717 *result = decoded;
718 *resultLength = 0;
719 if (decoded == NULL)
720 return ERROR_INSUFFICIENT_MEMORY;
721
722 while (*data != '\0') {
723 // Get character and check valid
724 d = unmap[*(data++)];
725 if (d > 0x3F) {
726 if (d == 0x80) {
727 free(decoded);
728 return ERROR_INVALID_CHARACTER;
729 }
730 break; // padding space
731 }
732
733 switch (bitsLeft) {
734 case 8:
735 decoded[in] = d;
736 bitsLeft = 2;
737 break;
738 case 2:
739 decoded[in] = (decoded[in] << 2) | (d >> 4);
740 decoded[++in] = d & 0x0F;
741 bitsLeft = 4;
742 break;
743 case 4:
744 decoded[in] = (decoded[in] << 4) | (d >> 2);
745 decoded[++in] = d & 0x03;
746 bitsLeft = 6;
747 break;
748 case 6:
749 decoded[in] = (decoded[in] << 6) | d;
750 in++;
751 bitsLeft = 8;
752 break;
753 }
754 }
755 *resultLength = in;
756 return ERROR_NONE;
757 }
758
759 /** Wrapper functions
760 *
761 */
762
freeResult(void * ptr)763 void freeResult(void *ptr)
764 {
765 if (ptr != NULL)
766 free(ptr);
767 return;
768 }
769
plistFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)770 static void plistFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
771 int resultLength;
772 int errorCode = 0;
773 char *result = NULL;
774 assert( argc==1 );
775 switch( sqlite3_value_type(argv[0]) ){
776 case SQLITE_TEXT:
777 case SQLITE_BLOB: {
778 const char *data = sqlite3_value_text(argv[0]);
779 const int dataLength = sqlite3_value_bytes(argv[0]);
780 errorCode = parsePlist(&result, data, dataLength);
781 if (errorCode == ERROR_NONE) {
782 resultLength = strlen(result);
783 sqlite3_result_text(context, result, resultLength, &freeResult);
784 } else {
785 if (sqlite3_value_type(argv[0]) == SQLITE_TEXT)
786 sqlite3_result_text(context, data, dataLength, NULL);
787 else
788 sqlite3_result_blob(context, data, dataLength, NULL);
789 }
790 break;
791 }
792 default: {
793 sqlite3_result_null(context);
794 break;
795 }
796 }
797 }
798
encodeBase64Func(sqlite3_context * context,int argc,sqlite3_value ** argv)799 static void encodeBase64Func(sqlite3_context *context, int argc, sqlite3_value **argv){
800 int resultLength;
801 int errorCode = 0;
802 int dataLength;
803 const unsigned char *data;
804 char *result = NULL;
805 assert( argc==1 );
806 switch( sqlite3_value_type(argv[0]) ){
807 case SQLITE_BLOB:
808 data = sqlite3_value_blob(argv[0]);
809 dataLength = sqlite3_value_bytes(argv[0]);
810 errorCode = encodeBase64(&result, data, dataLength);
811 if (errorCode == ERROR_NONE) {
812 resultLength = strlen(result);
813 sqlite3_result_text(context, result, resultLength, &freeResult);
814 } else {
815 sqlite3_result_blob(context, data, dataLength, NULL);
816 }
817 break;
818 case SQLITE_TEXT: {
819 data = sqlite3_value_text(argv[0]);
820 dataLength = sqlite3_value_bytes(argv[0]);
821 sqlite3_result_text(context, data, dataLength, NULL);
822 errorCode = encodeBase64(&result, data, dataLength);
823 if (errorCode == ERROR_NONE) {
824 resultLength = strlen(result);
825 sqlite3_result_text(context, result, resultLength, &freeResult);
826 } else {
827 sqlite3_result_text(context, data, dataLength, NULL);
828 }
829 break;
830 }
831 default: {
832 sqlite3_result_null(context);
833 break;
834 }
835 }
836 }
837
838
839 /*** isText
840 *
841 * Returns zero if supplied data is entirely
842 * ASCII printable characters or white space.
843 */
844
isText(unsigned char * data,int dataLength)845 int isText(unsigned char *data, int dataLength)
846 {
847 static unsigned char map[256] = {
848 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1,
849 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
850 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
851 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
852 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
853 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
854 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
855 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
856 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
857 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
858 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
859 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
860 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
861 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
862 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
863 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
864 };
865 int result = 0;
866 for (int i=0; i < dataLength; i++)
867 result |= map[*(data++)];
868 return result;
869 }
870
871 /** isUTF8
872 *
873 * Returns one if the characters conform to UTF8 format in so
874 * far as all the byte lengths are consistent. It does not
875 * check for overlong encodings or invalid characters. A zero
876 * is returned if the format is not consistent.
877 * Note that a file of all zeros will be returned as UTF8.
878 */
879
isUTF8(unsigned char * data,int length)880 int isUTF8(unsigned char *data, int length)
881 {
882 int count = 0;
883 while (length-- > 0) {
884 unsigned char d = *(data++);
885 switch (count) {
886 case 0: /* First character */
887 if ((d & 0x80) == 0)
888 continue; /* 7 bit ASCII */
889 if ((d & 0xE0) == 0xC0) {
890 count = 1; /* 2 byte code */
891 break;
892 }
893 if ((d & 0xF0) == 0xE0) {
894 count = 2; /* 3 byte code */
895 break;
896 }
897 if ((d & 0xF8) == 0xF0) {
898 count = 3; /* 4 byte code */
899 break;
900 }
901 return 0;
902 default:
903 count--;
904 if ((d & 0xC0) != 0x80)
905 return 0;
906 break;
907 }
908 }
909 return (count == 0) ? 1 : 0;
910 }
911
decodeBase64Func(sqlite3_context * context,int argc,sqlite3_value ** argv)912 static void decodeBase64Func(sqlite3_context *context, int argc, sqlite3_value **argv){
913 int resultLength;
914 int errorCode = 0;
915 unsigned char *result = NULL;
916 assert( argc==1 );
917 switch( sqlite3_value_type(argv[0]) ){
918 case SQLITE_BLOB:
919 case SQLITE_TEXT: {
920 const char *data = sqlite3_value_text(argv[0]);
921 int dataLength = sqlite3_value_bytes(argv[0]);
922 errorCode = decodeBase64(&result, &resultLength, data, dataLength);
923 if (errorCode == ERROR_NONE) {
924 if (isUTF8(result, resultLength))
925 sqlite3_result_text(context, result, resultLength, &freeResult);
926 else
927 sqlite3_result_blob(context, result, resultLength, &freeResult);
928 } else {
929 if (sqlite3_value_type(argv[0]) == SQLITE_TEXT)
930 sqlite3_result_text(context, data, dataLength, NULL);
931 else
932 sqlite3_result_blob(context, data, dataLength, NULL);
933 }
934 break;
935 }
936 default: {
937 sqlite3_result_null(context);
938 break;
939 }
940 }
941 }
942
943 /** RegisterExtensionFormats
944 *
945 * Register the parsing functions with sqlite
946 */
947
RegisterExtensionFormats(sqlite3 * db)948 int RegisterExtensionFormats(sqlite3 *db)
949 {
950 sqlite3_create_function(db, "plist", 1, 0, db, plistFunc, 0, 0);
951 sqlite3_create_function(db, "unBase64", 1, 0, db, decodeBase64Func, 0, 0);
952 sqlite3_create_function(db, "toBase64", 1, 0, db, encodeBase64Func, 0, 0);
953 }
954
955 #ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE
956
957 #ifdef _WIN32
958 __declspec(dllexport)
959 #endif
960
sqlite3_extension_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)961 int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
962 {
963 int rc = SQLITE_OK;
964 SQLITE_EXTENSION_INIT2(pApi);
965 RegisterExtensionFormats(db);
966 return rc;
967 }
968
969 #endif
970
971
972