commit 6634ce4f3bf233266c8c3aa54dedf081ae7e3434 Author: Martin Szulecki <opens...@sukimashita.com> Date: Tue Jul 27 16:14:17 2010 +0200
[sqlitedb] Implement iPhoneSortKey and iPhoneSortSection sqlite functions The latest iOS 4 post process commands expect these sqlite functions to be defined or a range of commands will fail. The implementation is ugly as it attempts to emulate the data blob structure as closely as possible to the one iTunes generates. src/itdb_sqlite.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 178 insertions(+), 0 deletions(-) --- diff --git a/src/itdb_sqlite.c b/src/itdb_sqlite.c index b107e4e..5b8f216 100644 --- a/src/itdb_sqlite.c +++ b/src/itdb_sqlite.c @@ -1572,6 +1572,180 @@ leave: return res; } +static void sort_key_get_buffer_boundaries(const char* sval, int *length, int *word_offset) +{ + int word_count = 0; + int i = 0; + int l = 0; + int o = 0; + char *sval_uppercase = NULL; + if (sval && strlen(sval)) { + sval_uppercase = g_ascii_strup(sval, strlen(sval)); + while (sval_uppercase[i]) { + if (g_ascii_isalnum(sval_uppercase[i])) { + l++; + } else { + switch (sval_uppercase[i]) { + case ' ': + word_count++; + l++; + break; + case ':': + case '-': + case ',': + case '.': + case '\'': + default: + l += 2; + break; + } + } + i++; + } + free(sval_uppercase); + + word_count++; + /* magic + transformed string + length + word weights + null */ + o = 1 + l + 3; + l = o + (word_count*2) + 1; + } else { + l = 4; + } + + *length = l; + *word_offset = o; +} + +static void sqlite_func_iphone_sort_key(sqlite3_context *context, int argc, sqlite3_value **argv) +{ + const char *sval; + char *sval_uppercase = NULL; + + char *buffer = NULL; + + int word_count = 0; + int word_offset = 0; + int word_length = 0; + int i = 0; + int buffer_index = 0; + int buffer_size = 0; + + if (argc != 1) + fprintf(stderr, "[%s] Error: Unexpected number of arguments: %d\n", __func__, argc); + + switch (sqlite3_value_type(argv[0])) { + case SQLITE_TEXT: + sval = (const char*)sqlite3_value_text(argv[0]); + sort_key_get_buffer_boundaries(sval, &buffer_size, &word_offset); + buffer = (char*)malloc(buffer_size); + memset(buffer, '\0', buffer_size); + buffer[buffer_index] = 0x31; + if (sval) { + if (buffer_size > 4) { + buffer[buffer_index++] = 0x30; + /* transform text value */ + /* uppercase the text */ + sval_uppercase = g_ascii_strup(sval, strlen(sval)); + while (sval_uppercase[i]) { + word_length++; + if (g_ascii_isalnum(sval_uppercase[i])) { + /* transform regular character */ + buffer[buffer_index++] = sval_uppercase[i] - (0x55 - sval_uppercase[i]); + } else { + /* transform special chars (punctuation,special) */ + switch (sval_uppercase[i]) { + case ' ': + buffer[buffer_index++] = 0x06; + word_length--; + + /* since we reached word end, calculate word weight */ + buffer[word_offset + word_count*2] = 0x8f; + buffer[word_offset + word_count*2 + 1] = (char)(0x86 - word_length); + word_count++; + word_length = 0; + break; + case ':': + buffer[buffer_index++] = 0x07; + buffer[buffer_index++] = 0xd8; + break; + case '-': + buffer[buffer_index++] = 0x07; + buffer[buffer_index++] = 0x90; + break; + case ',': + buffer[buffer_index++] = 0x07; + buffer[buffer_index++] = 0xb2; + break; + case '.': + buffer[buffer_index++] = 0x08; + buffer[buffer_index++] = 0x51; + break; + case '\'': + buffer[buffer_index++] = 0x07; + buffer[buffer_index++] = 0x31; + break; + default: + /* FIXME: We just simulate "-" for any other char, needs proper conversion */ + buffer[buffer_index++] = 0x07; + buffer[buffer_index++] = 0x90; + break; + } + } + i++; + } + g_free(sval_uppercase); + + /* calculate word weight for last word */ + buffer[word_offset + word_count*2] = 0x8f; + buffer[word_offset + word_count*2 + 1] = 3 + word_length; + word_count++; + word_length = 0; + + /* write length of input string */ + buffer[word_offset - 3] = 0x01; + buffer[word_offset - 2] = i + 4; /* length of input string + 4 */ + buffer[word_offset - 1] = 0x01; + } else { + buffer[0] = 0x31; + buffer[1] = 0x01; + buffer[2] = 0x01; + } + } + sqlite3_result_blob(context, buffer, buffer_size, free); + break; + case SQLITE_NULL: + buffer = (char*)malloc(4); + memcpy(buffer, "\x31\x01\x01\x00", 4); + sqlite3_result_blob(context, buffer, 4, free); + break; + default: + sqlite3_result_null(context); + break; + } +} + +static void sqlite_func_iphone_sort_section(sqlite3_context *context, int argc, sqlite3_value **argv) +{ + const unsigned char *sval; + int res = 26; + + if (argc != 1) + fprintf(stderr, "[%s] Error: Unexpected number of arguments: %d\n", __func__, argc); + + switch (sqlite3_value_type(argv[0])) { + case SQLITE_BLOB: + case SQLITE_TEXT: + sval = sqlite3_value_text(argv[0]); + if (sval && (sval[0] == 0x30) && (sval[1] >= 0x2D) && (sval[1] <= 0x5F)) { + res = (sval[1] - 0x2D) / 2; + } + break; + default: + break; + } + sqlite3_result_int(context, res); +} + static void run_post_process_commands(Itdb_iTunesDB *itdb, const char *outpath, const char *uuid) { plist_t plist_node = NULL; @@ -1743,6 +1917,10 @@ static void run_post_process_commands(Itdb_iTunesDB *itdb, const char *outpath, i++; } + printf("[%s] binding functions\n", __func__); + sqlite3_create_function(db, "iPhoneSortKey", 1, SQLITE_ANY, NULL, &sqlite_func_iphone_sort_key, NULL, NULL); + sqlite3_create_function(db, "iPhoneSortSection", 1, SQLITE_ANY, NULL, &sqlite_func_iphone_sort_section, NULL, NULL); + cnt = plist_array_get_size(user_ver_cmds); printf("[%s] Running %d post process commands now\n", __func__, cnt); ------------------------------------------------------------------------------ Learn how Oracle Real Application Clusters (RAC) One Node allows customers to consolidate database storage, standardize their database environment, and, should the need arise, upgrade to a full multi-node Oracle RAC database without downtime or disruption http://p.sf.net/sfu/oracle-sfdevnl _______________________________________________ gtkpod-cvs2 mailing list gtkpod-cvs2@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2