/*
* HashTable - ハッシュテーブル。
*
* Date: 2014-04-11
* Author: Leonardone
* Version: 2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG_FLAG 1
#if DEBUG_FLAG
# define DebugDo(d) d
#else
# define DebugDo(d)
#endif
/* --- memory --- */
#define STATIC_MEMORY 1
#if STATIC_MEMORY
#define MEMORY_SIZE (4220)
char buf[MEMORY_SIZE + 1];
int bufptr;
void *myMalloc(size_t s) {
char *tmp = buf + bufptr;
DebugDo
(printf("free: %d, request: %d\n", MEMORY_SIZE
- bufptr
, s
)); bufptr += s;
if (bufptr > MEMORY_SIZE) {
bufptr -= s;
return NULL;
}
return (void*)tmp;
}
# define Calloc(s1, s2) myMalloc((s1)*(s2))
# define Malloc(s) myMalloc(s)
# define Realloc(p, s) myMalloc(s)
# define Free(p)
#else
# define Calloc(s1, s2) calloc(s1, s2)
# define Malloc(s) malloc(s)
# define Realloc(p, s) realloc(p, s)
# define Free(p) free(p)
#endif
/* --- hashtable.h --- */
#define MINIMUM_HASHTABLESIZE (0x0002)
#define MAXIMUM_HASHTABLESIZE (0x7FFF)
struct _hashtable;
struct _tabledata;
typedef struct _hashtable HashTable, *LPHashTable;
typedef struct _tabledata TableData, *LPTableData;
extern LPHashTable newHashTable(const int tablesize, int (*keycmp)(const void *key1, const int key1len, const void *key2, const int key2len), int (*hash)(const void *key, const int keylen, const int tablesize));
extern void releaseHashTable(LPHashTable htable);
extern int addDataIntoHashTable(LPHashTable htable, const void *key, const int keylen, const void *data, const int size);
extern int getDataFromHashTable(const LPHashTable htable, const void *key, const int keylen, void *data, const int size);
extern int removeDataFromHashTable(LPHashTable htable, const void *key, const int keylen);
extern int existKeyInHashTable(LPHashTable htable, const void *key, const int keylen);
extern int setDataIntoHashTable(LPHashTable htable, const void *key, const int keylen, const void *data, const int size);
extern int countDataInHashTable(LPHashTable htable);
extern int getAllKeysInHashTable(const LPHashTable htable, int (*func)(const void *key, const int keylen));
extern int getAllDataInHashTable(const LPHashTable htable, int (*func)(const void *key, const int keylen, const void *data, const int size));
struct _hashtable {
int count;
int tablesize;
int (*keycmp)(const void* key1, const int key1len, const void *key2, const int key2len);
int (*hash)(const void *key, const int keylen, const int tablesize);
LPTableData *table;
};
struct _tabledata {
void *key;
int keylen;
void *data;
int size;
LPTableData next;
};
/* --- hashtable_static.h --- */
#define HASH_DEEP (5)
static int defaultHash(const void *key, const int keylen, const int tablesize);
static LPTableData *searchPlace(const LPHashTable htable, const void *key, const int keylen);
static void releaseTableData(LPTableData ptbdata, int chain);
static int defaultKeycmp(const void *key1, const int key1len, const void *key2, const int key2len);
static int getHash(const LPHashTable htable, const void *key, const int keylen);
/* --- test.c --- */
int addIntIntoHashTable(LPHashTable htable, const char *key, const int value) {
int ret
= addDataIntoHashTable
(htable
, key
, strlen(key
) + 1, &value
, sizeof(int)); if (ret == 1) {
DebugDo
(printf("add(success): %s, value: %d\n", key
, value
)); } else if (ret == 2) {
DebugDo
(printf("add(failure): %s, value: %d\n", key
, value
)); } else {
DebugDo
(printf("add(fatal error): %s\n", key
)); }
return ret;
}
int getIntFromHashTable(const LPHashTable htable, const char *key, int *value) {
int ret
= getDataFromHashTable
(htable
, key
, strlen(key
) + 1, (void*)value
, sizeof(int)); if (ret) {
DebugDo
(printf("get(success): %s, size: %d\n", key
, ret
)); } else {
DebugDo
(printf("get(failure): %s\n", key
)); }
return ret;
}
int setIntIntoHashTable(LPHashTable htable, const char *key, const int value) {
int ret
= setDataIntoHashTable
(htable
, key
, strlen(key
) + 1, &value
, sizeof(int)); if (ret == 1) {
DebugDo
(printf("set/new(success): %s, value: %d\n", key
, value
)); } else if (ret == 2) {
DebugDo
(printf("set/update(success): %s, value: %d\n", key
, value
)); } else {
DebugDo
(printf("set(fatal error): %s\n", key
)); }
return ret;
}
int func1(const void *key, const int keylen) {
printf("key: %s\n", (char*)key
); return 0;
}
int func2(const void *key, const int keylen, const void *data, const int size) {
printf("key: %s, data: %d\n", (char*)key
, *(int*)data
); return 0;
}
int main(void) {
LPHashTable htable = newHashTable(1024, NULL, NULL);
int v = 0;
if (htable == NULL) {
printf("init Hashtable(fatal error)\n"); }
addIntIntoHashTable(htable, "foo", 111);
addIntIntoHashTable(htable, "bar", 222);
addIntIntoHashTable(htable, "baz", 333);
addIntIntoHashTable(htable, "fuga", 987);
addIntIntoHashTable(htable, "piyo", 654);
if (htable) {
printf("cnt: %d\n", htable
->count
); }
printf("cnt: %d\n", countDataInHashTable
(htable
));
addIntIntoHashTable(htable, "hoge", 123);
addIntIntoHashTable(htable, "hoge", 246);
getIntFromHashTable(htable, "hoge", &v);
printf("cnt: %d\n", countDataInHashTable
(htable
));
setIntIntoHashTable(htable, "hoge", 345);
setIntIntoHashTable(htable, "foobar", 999);
getIntFromHashTable(htable, "hoge", &v);
getIntFromHashTable(htable, "baz", &v);
printf("cnt: %d\n", countDataInHashTable
(htable
));
getAllKeysInHashTable(htable, func1);
removeDataFromHashTable(htable, "baz", 4);
removeDataFromHashTable(htable, "baz", 4);
removeDataFromHashTable(htable, "test", 5);
printf("cnt: %d\n", countDataInHashTable
(htable
));
if (htable) { /* 非公開関数なので内部にエラートラップが無い */
printf("sch: %d\n", (int)searchPlace
(htable
, "hoge", 5)); printf("sch: %d\n", (int)searchPlace
(htable
, "abc", 4)); printf("*sch: %d\n", (int)*searchPlace
(htable
, "hoge", 5)); printf("*sch: %d\n", (int)*searchPlace
(htable
, "abc", 4)); if (*searchPlace(htable, "hoge", 5)) {
printf("*sch-d: %d\n", *(int*)(*searchPlace
(htable
, "hoge", 5))->data
); }
if (*searchPlace(htable, "bar", 4)) {
printf("*sch-d: %d\n", *(int*)(*searchPlace
(htable
, "bar", 4))->data
); }
}
printf("ext: %d\n", existKeyInHashTable
(htable
, "hoge", 5)); printf("ext: %d\n", existKeyInHashTable
(htable
, "abc", 4)); printf("ext: %d\n", existKeyInHashTable
(htable
, "foo", 4)); printf("ext: %d\n", existKeyInHashTable
(htable
, "baz", 4)); printf("ext: %d\n", existKeyInHashTable
(htable
, "fuga", 5)); printf("ext: %d\n", existKeyInHashTable
(htable
, "piyo", 5));
getAllDataInHashTable(htable, func2);
releaseHashTable(htable);
return 0;
}
/* --- hashtable.c --- */
/* +++ extern functions +++ */
/**
* 新しいHashTableを作る。
* @param tablesize
* @param keycmp
* @param hash
* @return
*/
LPHashTable newHashTable(const int tablesize,
int (*keycmp)(const void *key1, const int key1len, const void *key2, const int key2len),
int (*hash)(const void *key, const int keylen, const int tablesize)) {
/* calloc は 0 で初期化される */
LPHashTable htable;
if (tablesize < MINIMUM_HASHTABLESIZE || tablesize > MAXIMUM_HASHTABLESIZE) {
return NULL; /* 引数エラー */
}
htable = (LPHashTable)Calloc(1, sizeof(HashTable));
if (htable == NULL) {
return NULL; /* メモリ確保失敗 */
}
htable->table = (LPTableData *)Calloc(tablesize, sizeof(LPTableData));
if (htable->table == NULL) {
Free(htable);
return NULL; /* メモリ確保失敗 */
}
htable->tablesize = tablesize;
if (keycmp == NULL) {
htable->keycmp = defaultKeycmp;
} else {
htable->keycmp = keycmp;
}
if (hash == NULL) {
htable->hash = defaultHash;
} else {
htable->hash = hash;
}
DebugDo
(printf("init HashTable(%d)\n", tablesize
)); return htable;
}
/**
* HashTableをメモリから解放する。
* @param htable
*/
void releaseHashTable(LPHashTable htable) {
int i;
int tablesize;
LPTableData *ptbdata;
if (htable == NULL) {
return; /* ぬるぽ */
}
tablesize = htable->tablesize;
for (i = 0; i < tablesize; ++i) {
ptbdata = htable->table + i;
if (*ptbdata != NULL) {
releaseTableData(*ptbdata, 1);
}
}
Free(htable->table);
Free(htable);
DebugDo
(printf("release HashTable(%d)\n", tablesize
));}
/**
* HashTableにデータを追加する。既にキー名が存在する場合は失敗する。
* @param htable
* @param key
* @param keylen
* @param data
* @param size
* @return
*/
int addDataIntoHashTable(LPHashTable htable, const void *key, const int keylen, const void *data, const int size) {
LPTableData *ptbdata;
if (htable == NULL || key == NULL || data == NULL || size < 1 || keylen < 1) {
return 0; /* 引数エラー */
}
ptbdata = searchPlace(htable, key, keylen);
if (*ptbdata == NULL) {
*ptbdata = (LPTableData)Calloc(1, sizeof(TableData));
if (*ptbdata == NULL) {
return 0; /* メモリ確保失敗 */
}
(*ptbdata)->key = Malloc(keylen);
if ((*ptbdata)->key == NULL) {
Free(*ptbdata);
*ptbdata = NULL;
return 0; /* メモリ確保失敗 */
}
(*ptbdata)->data = Malloc(size);
if ((*ptbdata)->data == NULL) {
Free((*ptbdata)->key);
Free(*ptbdata);
*ptbdata = NULL;
return 0; /* メモリ確保失敗 */
}
memcpy((*ptbdata
)->key
, key
, keylen
); (*ptbdata)->keylen = keylen;
memcpy((*ptbdata
)->data
, data
, size
); (*ptbdata)->size = size;
++(htable->count);
return 1; /* 成功 */
}
return 2; /* キー名重複 */
}
/**
* HashTableからキー名のデータを取得する。
* @param htable
* @param key
* @param keylen
* @param data
* @param size
* @return
*/
int getDataFromHashTable(const LPHashTable htable, const void *key, const int keylen, void *data, const int size) {
int minsize;
LPTableData tbdata;
if (htable == NULL || key == NULL || data == NULL || size < 1 || keylen < 1) {
return 0; /* 引数エラー */
}
tbdata = *searchPlace(htable, key, keylen);
if (tbdata != NULL) {
minsize = tbdata->size < size ? tbdata->size : size;
memcpy(data
, tbdata
->data
, minsize
); return minsize;
}
return 0;
}
/**
* HashTableにデータを書き込む。既にキー名のデータがある場合は上書きする。
* @param htable
* @param key
* @param keylen
* @param data
* @param size
* @return
*/
int setDataIntoHashTable(LPHashTable htable, const void *key, const int keylen, const void *data, const int size) {
int ret = 1;
void *temp;
LPTableData *ptbdata;
if (htable == NULL || key == NULL || data == NULL || size < 1 || keylen < 1) {
return 0; /* 引数エラー */
}
ptbdata = searchPlace(htable, key, keylen);
if (*ptbdata == NULL) {
*ptbdata = (LPTableData)Calloc(1, sizeof(TableData));
if (*ptbdata == NULL) {
return 0; /* メモリ確保失敗 */
}
(*ptbdata)->key = Malloc(keylen);
if ((*ptbdata)->key == NULL) {
Free(*ptbdata);
*ptbdata = NULL;
return 0; /* メモリ確保失敗 */
}
(*ptbdata)->data = Malloc(size);
if ((*ptbdata)->data == NULL) {
Free((*ptbdata)->key);
Free(*ptbdata);
*ptbdata = NULL;
return 0; /* メモリ確保失敗 */
}
memcpy((*ptbdata
)->key
, key
, keylen
); (*ptbdata)->keylen = keylen;
(*ptbdata)->size = size;
++(htable->count);
} else {
if ((*ptbdata)->size != size) {
temp = Realloc((*ptbdata)->data, size);
if (temp == NULL) {
return 0; /* メモリ確保失敗 */
}
(*ptbdata)->data = temp;
(*ptbdata)->size = size;
}
ret = 2;
}
memcpy((*ptbdata
)->data
, data
, size
); return ret;
}
/**
* HashTable内の指定キー名のデータを削除する。
* @param htable HashTable。
* @param key キー名。
* @return 削除できたら(1)、失敗したら(0)。
*/
int removeDataFromHashTable(LPHashTable htable, const void *key, const int keylen) {
LPTableData *ptbdata;
LPTableData tbdata;
if (htable == NULL || key == NULL || keylen < 1) {
return 0; /* ぬるぽ */
}
ptbdata = searchPlace(htable, key, keylen);
if (*ptbdata != NULL) {
tbdata = *ptbdata;
*ptbdata = tbdata->next;
releaseTableData(tbdata, 0);
--(htable->count);
DebugDo
(printf("remove(success): %d %d\n", *(char*)key
, keylen
)); return 1;
}
DebugDo
(printf("remove(failure): %d %d\n", *(char*)key
, keylen
)); return 0;
}
/**
* HashTable内にキー名のデータが存在するか書くにする。
* @param htable HashTable。
* @param key 探すキー名。
* @param keylen
* @return 存在すれば(1)、存在しなければ(0)。
*/
int existKeyInHashTable(LPHashTable htable, const void *key, const int keylen) {
if (htable == NULL || key == NULL || keylen < 1) {
return 0; /* ぬるぽ */
}
return *searchPlace(htable, key, keylen) != NULL;
}
/**
* HashTable内のデータ数を返す。
* @param htable HashTable。
* @return データ数。
*/
int countDataInHashTable(LPHashTable htable) {
if (htable == NULL) {
return 0; /* ぬるぽ */
}
return htable->count;
}
/**
* HashTable内のキー名を全て取得する。
* @param htable
* @param func
* @return
*/
int getAllKeysInHashTable(const LPHashTable htable, int (*func)(const void *key, const int keylen)) {
int i;
int ret;
int tablesize;
LPTableData *ptbdata;
LPTableData tbdata;
if (htable == NULL || func == NULL) {
return 0;
}
DebugDo
(printf("allkey(start)\n")); ptbdata = htable->table;
tablesize = htable->tablesize;
for (i = 0; i < tablesize; ++i) {
tbdata = *ptbdata;
while (tbdata != NULL) {
ret = (*func)(tbdata->key, tbdata->keylen);
if (ret) {
DebugDo
(printf("allkey(stop)\n")); return 2;
}
tbdata = tbdata->next;
}
++ptbdata;
}
DebugDo
(printf("allkey(done)\n")); return 1;
}
/**
* HashTable内のデータを全て取得する。
* @param htable
* @param func
* @return
*/
int getAllDataInHashTable(const LPHashTable htable, int (*func)(const void *key, const int keylen, const void *data, const int size)) {
int i;
int ret;
int tablesize;
LPTableData *ptbdata;
LPTableData tbdata;
if (htable == NULL || func == NULL) {
return 0;
}
DebugDo
(printf("alldata(start)\n")); ptbdata = htable->table;
tablesize = htable->tablesize;
for (i = 0; i < tablesize; ++i) {
tbdata = *ptbdata;
while (tbdata != NULL) {
ret = (*func)(tbdata->key, tbdata->keylen, tbdata->data, tbdata->size);
if (ret) {
DebugDo
(printf("alldata(stop)\n")); return 2;
}
tbdata = tbdata->next;
}
++ptbdata;
}
DebugDo
(printf("alldata(done)\n")); return 1;
}
/* +++ static functions +++ */
/**
* キーの比較。
* @param key1
* @param key1len
* @param key2
* @param key2len
* @return
*/
int defaultKeycmp(const void *key1, const int key1len, const void *key2, const int key2len) {
if (key1len != key2len) {
return key1len - key2len;
}
return memcmp(key1
, key2
, key1len
); }
/**
* ハッシュ関数。キー名からハッシュ値を生成する。
* @param key キー名。
* @param keylen
* @param tablesize
* @return ハッシュ値。
*/
int defaultHash(const void *key, const int keylen, const int tablesize) {
int i;
char *p = (char*)key;
int v = (int)*p;
int lm = keylen - 1;
for (i = 0; i < HASH_DEEP && i < lm; i++) {
v ^= (int)(*p) * (int)(*(p + 1));
++p;
}
return v;
}
/**
* ハッシュ値を取得する。
* @param htable
* @param key
* @param keyleln
*/
int getHash(const LPHashTable htable, const void *key, const int keylen) {
int h = (*(htable->hash))(key, keylen, htable->tablesize);
if (h < 0) {
h = ~h;
}
return h % htable->tablesize;
}
/**
* HashTableからキー名のデータを格納する場所(アドレス)を探す。
* @param htable キー名を探すHashTable。
* @param key 探すキー名。
* @param keylen
* @return 格納されてる場所(アドレス)。
*/
LPTableData *searchPlace(const LPHashTable htable, const void *key, const int keylen) {
int h = getHash(htable, key, keylen);
LPTableData *ptbdata = htable->table + h;
while (*ptbdata != NULL) {
if ((*(htable->keycmp))((*ptbdata)->key, (*ptbdata)->keylen, key, keylen) == 0) {
break;
}
ptbdata = &(*ptbdata)->next;
}
DebugDo
(printf("hash: %d %d -> %d\n", *(char*)key
, keylen
, h
)); return ptbdata;
}
/**
* TableDataをメモリから解放する。
* @param ptbdata 解放するデータ。
* @param chain nextにあるTableDataも解放する(1)かしない(0)か。
*/
void releaseTableData(LPTableData tbdata, int chain) {
if (tbdata == NULL) {
return;
}
if (chain) {
releaseTableData(tbdata->next, chain);
}
DebugDo
(printf("release TableData: %d %d\n", *((char*)(tbdata
->key
)), tbdata
->keylen
)); Free(tbdata->key);
Free(tbdata->data);
Free(tbdata);
}
LyoKICogSGFzaFRhYmxlIC0g44OP44OD44K344Ol44OG44O844OW44Or44CCCiAqCiAqIERhdGU6IDIwMTQtMDQtMTEKICogQXV0aG9yOiBMZW9uYXJkb25lCiAqIFZlcnNpb246IDIuMAogKi8KI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0cmluZy5oPgoKI2RlZmluZSBERUJVR19GTEFHIDEKCiNpZiBERUJVR19GTEFHCiMgIGRlZmluZSBEZWJ1Z0RvKGQpIGQKI2Vsc2UKIyAgZGVmaW5lIERlYnVnRG8oZCkKI2VuZGlmCgovKiAtLS0gbWVtb3J5IC0tLSAqLwoKI2RlZmluZSBTVEFUSUNfTUVNT1JZIDEKCiNpZiBTVEFUSUNfTUVNT1JZCgojZGVmaW5lIE1FTU9SWV9TSVpFICg0MjIwKQpjaGFyIGJ1ZltNRU1PUllfU0laRSArIDFdOwppbnQgYnVmcHRyOwoKdm9pZCAqbXlNYWxsb2Moc2l6ZV90IHMpIHsKCWNoYXIgKnRtcCA9IGJ1ZiArIGJ1ZnB0cjsKCURlYnVnRG8ocHJpbnRmKCJmcmVlOiAlZCwgcmVxdWVzdDogJWRcbiIsIE1FTU9SWV9TSVpFIC0gYnVmcHRyLCBzKSk7CglidWZwdHIgKz0gczsKCWlmIChidWZwdHIgPiBNRU1PUllfU0laRSkgewoJCWJ1ZnB0ciAtPSBzOwoJCXJldHVybiBOVUxMOwoJfQoJcmV0dXJuICh2b2lkKil0bXA7Cn0KCiMgIGRlZmluZSBDYWxsb2MoczEsIHMyKSBteU1hbGxvYygoczEpKihzMikpCiMgIGRlZmluZSBNYWxsb2MocykgICAgICBteU1hbGxvYyhzKQojICBkZWZpbmUgUmVhbGxvYyhwLCBzKSAgbXlNYWxsb2MocykKIyAgZGVmaW5lIEZyZWUocCkgICAgICAgIAojZWxzZQojICBkZWZpbmUgQ2FsbG9jKHMxLCBzMikgY2FsbG9jKHMxLCBzMikKIyAgZGVmaW5lIE1hbGxvYyhzKSAgICAgIG1hbGxvYyhzKQojICBkZWZpbmUgUmVhbGxvYyhwLCBzKSAgcmVhbGxvYyhwLCBzKQojICBkZWZpbmUgRnJlZShwKSAgICAgICAgZnJlZShwKQojZW5kaWYKCi8qIC0tLSBoYXNodGFibGUuaCAtLS0gKi8KCiNkZWZpbmUgTUlOSU1VTV9IQVNIVEFCTEVTSVpFICgweDAwMDIpCiNkZWZpbmUgTUFYSU1VTV9IQVNIVEFCTEVTSVpFICgweDdGRkYpCgpzdHJ1Y3QgX2hhc2h0YWJsZTsKc3RydWN0IF90YWJsZWRhdGE7Cgp0eXBlZGVmIHN0cnVjdCBfaGFzaHRhYmxlIEhhc2hUYWJsZSwgKkxQSGFzaFRhYmxlOwp0eXBlZGVmIHN0cnVjdCBfdGFibGVkYXRhIFRhYmxlRGF0YSwgKkxQVGFibGVEYXRhOwoKZXh0ZXJuIExQSGFzaFRhYmxlIG5ld0hhc2hUYWJsZShjb25zdCBpbnQgdGFibGVzaXplLCBpbnQgKCprZXljbXApKGNvbnN0IHZvaWQgKmtleTEsIGNvbnN0IGludCBrZXkxbGVuLCBjb25zdCB2b2lkICprZXkyLCBjb25zdCBpbnQga2V5MmxlbiksIGludCAoKmhhc2gpKGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbiwgY29uc3QgaW50IHRhYmxlc2l6ZSkpOwpleHRlcm4gdm9pZCByZWxlYXNlSGFzaFRhYmxlKExQSGFzaFRhYmxlIGh0YWJsZSk7CmV4dGVybiBpbnQgYWRkRGF0YUludG9IYXNoVGFibGUoTFBIYXNoVGFibGUgaHRhYmxlLCBjb25zdCB2b2lkICprZXksIGNvbnN0IGludCBrZXlsZW4sIGNvbnN0IHZvaWQgKmRhdGEsIGNvbnN0IGludCBzaXplKTsKZXh0ZXJuIGludCBnZXREYXRhRnJvbUhhc2hUYWJsZShjb25zdCBMUEhhc2hUYWJsZSBodGFibGUsIGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbiwgdm9pZCAqZGF0YSwgY29uc3QgaW50IHNpemUpOwpleHRlcm4gaW50IHJlbW92ZURhdGFGcm9tSGFzaFRhYmxlKExQSGFzaFRhYmxlIGh0YWJsZSwgY29uc3Qgdm9pZCAqa2V5LCBjb25zdCBpbnQga2V5bGVuKTsKZXh0ZXJuIGludCBleGlzdEtleUluSGFzaFRhYmxlKExQSGFzaFRhYmxlIGh0YWJsZSwgY29uc3Qgdm9pZCAqa2V5LCBjb25zdCBpbnQga2V5bGVuKTsKZXh0ZXJuIGludCBzZXREYXRhSW50b0hhc2hUYWJsZShMUEhhc2hUYWJsZSBodGFibGUsIGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbiwgY29uc3Qgdm9pZCAqZGF0YSwgY29uc3QgaW50IHNpemUpOwpleHRlcm4gaW50IGNvdW50RGF0YUluSGFzaFRhYmxlKExQSGFzaFRhYmxlIGh0YWJsZSk7CmV4dGVybiBpbnQgZ2V0QWxsS2V5c0luSGFzaFRhYmxlKGNvbnN0IExQSGFzaFRhYmxlIGh0YWJsZSwgaW50ICgqZnVuYykoY29uc3Qgdm9pZCAqa2V5LCBjb25zdCBpbnQga2V5bGVuKSk7CmV4dGVybiBpbnQgZ2V0QWxsRGF0YUluSGFzaFRhYmxlKGNvbnN0IExQSGFzaFRhYmxlIGh0YWJsZSwgaW50ICgqZnVuYykoY29uc3Qgdm9pZCAqa2V5LCBjb25zdCBpbnQga2V5bGVuLCBjb25zdCB2b2lkICpkYXRhLCBjb25zdCBpbnQgc2l6ZSkpOwoKc3RydWN0IF9oYXNodGFibGUgewoJaW50IGNvdW50OwoJaW50IHRhYmxlc2l6ZTsKCWludCAoKmtleWNtcCkoY29uc3Qgdm9pZCoga2V5MSwgY29uc3QgaW50IGtleTFsZW4sIGNvbnN0IHZvaWQgKmtleTIsIGNvbnN0IGludCBrZXkybGVuKTsKCWludCAoKmhhc2gpKGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbiwgY29uc3QgaW50IHRhYmxlc2l6ZSk7CglMUFRhYmxlRGF0YSAqdGFibGU7Cn07CgpzdHJ1Y3QgX3RhYmxlZGF0YSB7Cgl2b2lkICprZXk7CglpbnQga2V5bGVuOwoJdm9pZCAqZGF0YTsKCWludCBzaXplOwoJTFBUYWJsZURhdGEgbmV4dDsKfTsKCi8qIC0tLSBoYXNodGFibGVfc3RhdGljLmggLS0tICovCgojZGVmaW5lIEhBU0hfREVFUCAoNSkKCnN0YXRpYyBpbnQgZGVmYXVsdEhhc2goY29uc3Qgdm9pZCAqa2V5LCBjb25zdCBpbnQga2V5bGVuLCBjb25zdCBpbnQgdGFibGVzaXplKTsKc3RhdGljIExQVGFibGVEYXRhICpzZWFyY2hQbGFjZShjb25zdCBMUEhhc2hUYWJsZSBodGFibGUsIGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbik7CnN0YXRpYyB2b2lkIHJlbGVhc2VUYWJsZURhdGEoTFBUYWJsZURhdGEgcHRiZGF0YSwgaW50IGNoYWluKTsKc3RhdGljIGludCBkZWZhdWx0S2V5Y21wKGNvbnN0IHZvaWQgKmtleTEsIGNvbnN0IGludCBrZXkxbGVuLCBjb25zdCB2b2lkICprZXkyLCBjb25zdCBpbnQga2V5Mmxlbik7CnN0YXRpYyBpbnQgZ2V0SGFzaChjb25zdCBMUEhhc2hUYWJsZSBodGFibGUsIGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbik7CgovKiAtLS0gdGVzdC5jIC0tLSAqLwoKaW50IGFkZEludEludG9IYXNoVGFibGUoTFBIYXNoVGFibGUgaHRhYmxlLCBjb25zdCBjaGFyICprZXksIGNvbnN0IGludCB2YWx1ZSkgewoJaW50IHJldCA9IGFkZERhdGFJbnRvSGFzaFRhYmxlKGh0YWJsZSwga2V5LCBzdHJsZW4oa2V5KSArIDEsICZ2YWx1ZSwgc2l6ZW9mKGludCkpOwoJaWYgKHJldCA9PSAxKSB7CgkJRGVidWdEbyhwcmludGYoImFkZChzdWNjZXNzKTogJXMsIHZhbHVlOiAlZFxuIiwga2V5LCB2YWx1ZSkpOwoJfSBlbHNlIGlmIChyZXQgPT0gMikgewoJCURlYnVnRG8ocHJpbnRmKCJhZGQoZmFpbHVyZSk6ICVzLCB2YWx1ZTogJWRcbiIsIGtleSwgdmFsdWUpKTsKCX0gZWxzZSB7CgkJRGVidWdEbyhwcmludGYoImFkZChmYXRhbCBlcnJvcik6ICVzXG4iLCBrZXkpKTsKCX0KCXJldHVybiByZXQ7Cn0KCmludCBnZXRJbnRGcm9tSGFzaFRhYmxlKGNvbnN0IExQSGFzaFRhYmxlIGh0YWJsZSwgY29uc3QgY2hhciAqa2V5LCBpbnQgKnZhbHVlKSB7CglpbnQgcmV0ID0gZ2V0RGF0YUZyb21IYXNoVGFibGUoaHRhYmxlLCBrZXksIHN0cmxlbihrZXkpICsgMSwgKHZvaWQqKXZhbHVlLCBzaXplb2YoaW50KSk7CglpZiAocmV0KSB7CgkJRGVidWdEbyhwcmludGYoImdldChzdWNjZXNzKTogJXMsIHNpemU6ICVkXG4iLCBrZXksIHJldCkpOwoJfSBlbHNlIHsKCQlEZWJ1Z0RvKHByaW50ZigiZ2V0KGZhaWx1cmUpOiAlc1xuIiwga2V5KSk7Cgl9CglyZXR1cm4gcmV0Owp9CgppbnQgc2V0SW50SW50b0hhc2hUYWJsZShMUEhhc2hUYWJsZSBodGFibGUsIGNvbnN0IGNoYXIgKmtleSwgY29uc3QgaW50IHZhbHVlKSB7CglpbnQgcmV0ID0gc2V0RGF0YUludG9IYXNoVGFibGUoaHRhYmxlLCBrZXksIHN0cmxlbihrZXkpICsgMSwgJnZhbHVlLCBzaXplb2YoaW50KSk7CglpZiAocmV0ID09IDEpIHsKCQlEZWJ1Z0RvKHByaW50Zigic2V0L25ldyhzdWNjZXNzKTogJXMsIHZhbHVlOiAlZFxuIiwga2V5LCB2YWx1ZSkpOwoJfSBlbHNlIGlmIChyZXQgPT0gMikgewoJCURlYnVnRG8ocHJpbnRmKCJzZXQvdXBkYXRlKHN1Y2Nlc3MpOiAlcywgdmFsdWU6ICVkXG4iLCBrZXksIHZhbHVlKSk7Cgl9IGVsc2UgewoJCURlYnVnRG8ocHJpbnRmKCJzZXQoZmF0YWwgZXJyb3IpOiAlc1xuIiwga2V5KSk7Cgl9CglyZXR1cm4gcmV0Owp9CgppbnQgZnVuYzEoY29uc3Qgdm9pZCAqa2V5LCBjb25zdCBpbnQga2V5bGVuKSB7CglwcmludGYoImtleTogJXNcbiIsIChjaGFyKilrZXkpOwoJcmV0dXJuIDA7Cn0KCmludCBmdW5jMihjb25zdCB2b2lkICprZXksIGNvbnN0IGludCBrZXlsZW4sIGNvbnN0IHZvaWQgKmRhdGEsIGNvbnN0IGludCBzaXplKSB7CglwcmludGYoImtleTogJXMsIGRhdGE6ICVkXG4iLCAoY2hhciopa2V5LCAqKGludCopZGF0YSk7CglyZXR1cm4gMDsKfQoKaW50IG1haW4odm9pZCkgewoJCglMUEhhc2hUYWJsZSBodGFibGUgPSBuZXdIYXNoVGFibGUoMTAyNCwgTlVMTCwgTlVMTCk7CglpbnQgdiA9IDA7CgkKCWlmIChodGFibGUgPT0gTlVMTCkgewoJCXByaW50ZigiaW5pdCBIYXNodGFibGUoZmF0YWwgZXJyb3IpXG4iKTsKCX0KCQoJYWRkSW50SW50b0hhc2hUYWJsZShodGFibGUsICJmb28iLCAxMTEpOwoJYWRkSW50SW50b0hhc2hUYWJsZShodGFibGUsICJiYXIiLCAyMjIpOwoJYWRkSW50SW50b0hhc2hUYWJsZShodGFibGUsICJiYXoiLCAzMzMpOwoJYWRkSW50SW50b0hhc2hUYWJsZShodGFibGUsICJmdWdhIiwgOTg3KTsKCWFkZEludEludG9IYXNoVGFibGUoaHRhYmxlLCAicGl5byIsIDY1NCk7CgkKCWlmIChodGFibGUpIHsKCQlwcmludGYoImNudDogJWRcbiIsIGh0YWJsZS0+Y291bnQpOwoJfQoJcHJpbnRmKCJjbnQ6ICVkXG4iLCBjb3VudERhdGFJbkhhc2hUYWJsZShodGFibGUpKTsKCglhZGRJbnRJbnRvSGFzaFRhYmxlKGh0YWJsZSwgImhvZ2UiLCAxMjMpOwoJYWRkSW50SW50b0hhc2hUYWJsZShodGFibGUsICJob2dlIiwgMjQ2KTsKCWdldEludEZyb21IYXNoVGFibGUoaHRhYmxlLCAiaG9nZSIsICZ2KTsKCXByaW50ZigiZ2V0OiAlZFxuIiwgdik7CgoJcHJpbnRmKCJjbnQ6ICVkXG4iLCBjb3VudERhdGFJbkhhc2hUYWJsZShodGFibGUpKTsKCglzZXRJbnRJbnRvSGFzaFRhYmxlKGh0YWJsZSwgImhvZ2UiLCAzNDUpOwoJc2V0SW50SW50b0hhc2hUYWJsZShodGFibGUsICJmb29iYXIiLCA5OTkpOwoJZ2V0SW50RnJvbUhhc2hUYWJsZShodGFibGUsICJob2dlIiwgJnYpOwoJcHJpbnRmKCJnZXQ6ICVkXG4iLCB2KTsKCglnZXRJbnRGcm9tSGFzaFRhYmxlKGh0YWJsZSwgImJheiIsICZ2KTsKCXByaW50ZigiZ2V0OiAlZFxuIiwgdik7CgoJcHJpbnRmKCJjbnQ6ICVkXG4iLCBjb3VudERhdGFJbkhhc2hUYWJsZShodGFibGUpKTsKCQoJZ2V0QWxsS2V5c0luSGFzaFRhYmxlKGh0YWJsZSwgZnVuYzEpOwoJCglyZW1vdmVEYXRhRnJvbUhhc2hUYWJsZShodGFibGUsICJiYXoiLCA0KTsKCXJlbW92ZURhdGFGcm9tSGFzaFRhYmxlKGh0YWJsZSwgImJheiIsIDQpOwoJcmVtb3ZlRGF0YUZyb21IYXNoVGFibGUoaHRhYmxlLCAidGVzdCIsIDUpOwoKCXByaW50ZigiY250OiAlZFxuIiwgY291bnREYXRhSW5IYXNoVGFibGUoaHRhYmxlKSk7CgoJaWYgKGh0YWJsZSkgeyAvKiDpnZ7lhazplovplqLmlbDjgarjga7jgaflhoXpg6jjgavjgqjjg6njg7zjg4jjg6njg4Pjg5fjgYznhKHjgYQgKi8KCQlwcmludGYoInNjaDogJWRcbiIsIChpbnQpc2VhcmNoUGxhY2UoaHRhYmxlLCAiaG9nZSIsIDUpKTsKCQlwcmludGYoInNjaDogJWRcbiIsIChpbnQpc2VhcmNoUGxhY2UoaHRhYmxlLCAiYWJjIiwgNCkpOwoJCXByaW50ZigiKnNjaDogJWRcbiIsIChpbnQpKnNlYXJjaFBsYWNlKGh0YWJsZSwgImhvZ2UiLCA1KSk7CgkJcHJpbnRmKCIqc2NoOiAlZFxuIiwgKGludCkqc2VhcmNoUGxhY2UoaHRhYmxlLCAiYWJjIiwgNCkpOwoJCWlmICgqc2VhcmNoUGxhY2UoaHRhYmxlLCAiaG9nZSIsIDUpKSB7CgkJCXByaW50ZigiKnNjaC1kOiAlZFxuIiwgKihpbnQqKSgqc2VhcmNoUGxhY2UoaHRhYmxlLCAiaG9nZSIsIDUpKS0+ZGF0YSk7CgkJfQoJCWlmICgqc2VhcmNoUGxhY2UoaHRhYmxlLCAiYmFyIiwgNCkpIHsKCQkJcHJpbnRmKCIqc2NoLWQ6ICVkXG4iLCAqKGludCopKCpzZWFyY2hQbGFjZShodGFibGUsICJiYXIiLCA0KSktPmRhdGEpOwoJCX0KCX0KCglwcmludGYoImV4dDogJWRcbiIsIGV4aXN0S2V5SW5IYXNoVGFibGUoaHRhYmxlLCAiaG9nZSIsIDUpKTsKCXByaW50ZigiZXh0OiAlZFxuIiwgZXhpc3RLZXlJbkhhc2hUYWJsZShodGFibGUsICJhYmMiLCA0KSk7CglwcmludGYoImV4dDogJWRcbiIsIGV4aXN0S2V5SW5IYXNoVGFibGUoaHRhYmxlLCAiZm9vIiwgNCkpOwoJcHJpbnRmKCJleHQ6ICVkXG4iLCBleGlzdEtleUluSGFzaFRhYmxlKGh0YWJsZSwgImJheiIsIDQpKTsKCXByaW50ZigiZXh0OiAlZFxuIiwgZXhpc3RLZXlJbkhhc2hUYWJsZShodGFibGUsICJmdWdhIiwgNSkpOwoJcHJpbnRmKCJleHQ6ICVkXG4iLCBleGlzdEtleUluSGFzaFRhYmxlKGh0YWJsZSwgInBpeW8iLCA1KSk7CgkKCWdldEFsbERhdGFJbkhhc2hUYWJsZShodGFibGUsIGZ1bmMyKTsKCQoJcmVsZWFzZUhhc2hUYWJsZShodGFibGUpOwoJCglyZXR1cm4gMDsKfQoKLyogLS0tIGhhc2h0YWJsZS5jIC0tLSAqLwoKLyogKysrIGV4dGVybiBmdW5jdGlvbnMgKysrICovCgovKioKICog5paw44GX44GESGFzaFRhYmxl44KS5L2c44KL44CCCiAqIEBwYXJhbSB0YWJsZXNpemUKICogQHBhcmFtIGtleWNtcAogKiBAcGFyYW0gaGFzaAogKiBAcmV0dXJuCiAqLwpMUEhhc2hUYWJsZSBuZXdIYXNoVGFibGUoY29uc3QgaW50IHRhYmxlc2l6ZSwgCgkJaW50ICgqa2V5Y21wKShjb25zdCB2b2lkICprZXkxLCBjb25zdCBpbnQga2V5MWxlbiwgY29uc3Qgdm9pZCAqa2V5MiwgY29uc3QgaW50IGtleTJsZW4pLAoJCWludCAoKmhhc2gpKGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbiwgY29uc3QgaW50IHRhYmxlc2l6ZSkpIHsKCS8qIGNhbGxvYyDjga8gMCDjgafliJ3mnJ/ljJbjgZXjgozjgosgKi8KCUxQSGFzaFRhYmxlIGh0YWJsZTsKCWlmICh0YWJsZXNpemUgPCBNSU5JTVVNX0hBU0hUQUJMRVNJWkUgfHwgdGFibGVzaXplID4gTUFYSU1VTV9IQVNIVEFCTEVTSVpFKSB7CgkJcmV0dXJuIE5VTEw7IC8qIOW8leaVsOOCqOODqeODvCAqLyAKCX0KCWh0YWJsZSA9IChMUEhhc2hUYWJsZSlDYWxsb2MoMSwgc2l6ZW9mKEhhc2hUYWJsZSkpOwoJaWYgKGh0YWJsZSA9PSBOVUxMKSB7CgkJcmV0dXJuIE5VTEw7IC8qIOODoeODouODqueiuuS/neWkseaVlyAqLwoJfQoJaHRhYmxlLT50YWJsZSA9IChMUFRhYmxlRGF0YSAqKUNhbGxvYyh0YWJsZXNpemUsIHNpemVvZihMUFRhYmxlRGF0YSkpOwoJaWYgKGh0YWJsZS0+dGFibGUgPT0gTlVMTCkgewoJCUZyZWUoaHRhYmxlKTsKCQlyZXR1cm4gTlVMTDsgLyog44Oh44Oi44Oq56K65L+d5aSx5pWXICovCgl9CglodGFibGUtPnRhYmxlc2l6ZSA9IHRhYmxlc2l6ZTsKCWlmIChrZXljbXAgPT0gTlVMTCkgewoJCWh0YWJsZS0+a2V5Y21wID0gZGVmYXVsdEtleWNtcDsKCX0gZWxzZSB7CgkJaHRhYmxlLT5rZXljbXAgPSBrZXljbXA7Cgl9CglpZiAoaGFzaCA9PSBOVUxMKSB7CgkJaHRhYmxlLT5oYXNoID0gZGVmYXVsdEhhc2g7Cgl9IGVsc2UgewoJCWh0YWJsZS0+aGFzaCA9IGhhc2g7Cgl9CglEZWJ1Z0RvKHByaW50ZigiaW5pdCBIYXNoVGFibGUoJWQpXG4iLCB0YWJsZXNpemUpKTsKCXJldHVybiBodGFibGU7Cn0KCi8qKgogKiBIYXNoVGFibGXjgpLjg6Hjg6Ljg6rjgYvjgonop6PmlL7jgZnjgovjgIIKICogQHBhcmFtIGh0YWJsZQogKi8Kdm9pZCByZWxlYXNlSGFzaFRhYmxlKExQSGFzaFRhYmxlIGh0YWJsZSkgewoJaW50IGk7CglpbnQgdGFibGVzaXplOwoJTFBUYWJsZURhdGEgKnB0YmRhdGE7CglpZiAoaHRhYmxlID09IE5VTEwpIHsKCQlyZXR1cm47IC8qIOOBrOOCi+OBvSAqLwoJfQoJdGFibGVzaXplID0gaHRhYmxlLT50YWJsZXNpemU7Cglmb3IgKGkgPSAwOyBpIDwgdGFibGVzaXplOyArK2kpIHsKCQlwdGJkYXRhID0gaHRhYmxlLT50YWJsZSArIGk7CgkJaWYgKCpwdGJkYXRhICE9IE5VTEwpIHsKCQkJcmVsZWFzZVRhYmxlRGF0YSgqcHRiZGF0YSwgMSk7CgkJfQoJfQoJRnJlZShodGFibGUtPnRhYmxlKTsKCUZyZWUoaHRhYmxlKTsKCURlYnVnRG8ocHJpbnRmKCJyZWxlYXNlIEhhc2hUYWJsZSglZClcbiIsIHRhYmxlc2l6ZSkpOwp9CgovKioKICogSGFzaFRhYmxl44Gr44OH44O844K/44KS6L+95Yqg44GZ44KL44CC5pei44Gr44Kt44O85ZCN44GM5a2Y5Zyo44GZ44KL5aC05ZCI44Gv5aSx5pWX44GZ44KL44CCCiAqIEBwYXJhbSBodGFibGUKICogQHBhcmFtIGtleQogKiBAcGFyYW0ga2V5bGVuCiAqIEBwYXJhbSBkYXRhCiAqIEBwYXJhbSBzaXplCiAqIEByZXR1cm4KICovCmludCBhZGREYXRhSW50b0hhc2hUYWJsZShMUEhhc2hUYWJsZSBodGFibGUsIGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbiwgY29uc3Qgdm9pZCAqZGF0YSwgY29uc3QgaW50IHNpemUpIHsKCUxQVGFibGVEYXRhICpwdGJkYXRhOwoJaWYgKGh0YWJsZSA9PSBOVUxMIHx8IGtleSA9PSBOVUxMIHx8IGRhdGEgPT0gTlVMTCB8fCBzaXplIDwgMSB8fCBrZXlsZW4gPCAxKSB7CgkJcmV0dXJuIDA7IC8qIOW8leaVsOOCqOODqeODvCAqLwoJfQoJcHRiZGF0YSA9IHNlYXJjaFBsYWNlKGh0YWJsZSwga2V5LCBrZXlsZW4pOwoJaWYgKCpwdGJkYXRhID09IE5VTEwpIHsKCQkqcHRiZGF0YSA9IChMUFRhYmxlRGF0YSlDYWxsb2MoMSwgc2l6ZW9mKFRhYmxlRGF0YSkpOwoJCWlmICgqcHRiZGF0YSA9PSBOVUxMKSB7CgkJCXJldHVybiAwOyAvKiDjg6Hjg6Ljg6rnorrkv53lpLHmlZcgKi8KCQl9CgkJKCpwdGJkYXRhKS0+a2V5ID0gTWFsbG9jKGtleWxlbik7CgkJaWYgKCgqcHRiZGF0YSktPmtleSA9PSBOVUxMKSB7CgkJCUZyZWUoKnB0YmRhdGEpOwoJCQkqcHRiZGF0YSA9IE5VTEw7CgkJCXJldHVybiAwOyAvKiDjg6Hjg6Ljg6rnorrkv53lpLHmlZcgKi8KCQl9CgkJKCpwdGJkYXRhKS0+ZGF0YSA9IE1hbGxvYyhzaXplKTsKCQlpZiAoKCpwdGJkYXRhKS0+ZGF0YSA9PSBOVUxMKSB7CgkJCUZyZWUoKCpwdGJkYXRhKS0+a2V5KTsKCQkJRnJlZSgqcHRiZGF0YSk7CgkJCSpwdGJkYXRhID0gTlVMTDsKCQkJcmV0dXJuIDA7IC8qIOODoeODouODqueiuuS/neWkseaVlyAqLwoJCX0KCQltZW1jcHkoKCpwdGJkYXRhKS0+a2V5LCBrZXksIGtleWxlbik7CgkJKCpwdGJkYXRhKS0+a2V5bGVuID0ga2V5bGVuOwoJCW1lbWNweSgoKnB0YmRhdGEpLT5kYXRhLCBkYXRhLCBzaXplKTsKCQkoKnB0YmRhdGEpLT5zaXplID0gc2l6ZTsKCQkrKyhodGFibGUtPmNvdW50KTsKCQlyZXR1cm4gMTsgLyog5oiQ5YqfICovCgl9CglyZXR1cm4gMjsgLyog44Kt44O85ZCN6YeN6KSHICovCn0KCi8qKgogKiBIYXNoVGFibGXjgYvjgonjgq3jg7zlkI3jga7jg4fjg7zjgr/jgpLlj5blvpfjgZnjgovjgIIKICogQHBhcmFtIGh0YWJsZQogKiBAcGFyYW0ga2V5CiAqIEBwYXJhbSBrZXlsZW4KICogQHBhcmFtIGRhdGEKICogQHBhcmFtIHNpemUKICogQHJldHVybgogKi8KaW50IGdldERhdGFGcm9tSGFzaFRhYmxlKGNvbnN0IExQSGFzaFRhYmxlIGh0YWJsZSwgY29uc3Qgdm9pZCAqa2V5LCBjb25zdCBpbnQga2V5bGVuLCB2b2lkICpkYXRhLCBjb25zdCBpbnQgc2l6ZSkgewoJaW50IG1pbnNpemU7CglMUFRhYmxlRGF0YSB0YmRhdGE7CglpZiAoaHRhYmxlID09IE5VTEwgfHwga2V5ID09IE5VTEwgfHwgZGF0YSA9PSBOVUxMIHx8IHNpemUgPCAxIHx8IGtleWxlbiA8IDEpIHsKCQlyZXR1cm4gMDsgLyog5byV5pWw44Ko44Op44O8ICovCgl9Cgl0YmRhdGEgPSAqc2VhcmNoUGxhY2UoaHRhYmxlLCBrZXksIGtleWxlbik7CglpZiAodGJkYXRhICE9IE5VTEwpIHsKCQltaW5zaXplID0gdGJkYXRhLT5zaXplIDwgc2l6ZSA/IHRiZGF0YS0+c2l6ZSA6IHNpemU7CgkJbWVtY3B5KGRhdGEsIHRiZGF0YS0+ZGF0YSwgbWluc2l6ZSk7CgkJcmV0dXJuIG1pbnNpemU7Cgl9CglyZXR1cm4gMDsKfQoKLyoqCiAqIEhhc2hUYWJsZeOBq+ODh+ODvOOCv+OCkuabuOOBjei+vOOCgOOAguaXouOBq+OCreODvOWQjeOBruODh+ODvOOCv+OBjOOBguOCi+WgtOWQiOOBr+S4iuabuOOBjeOBmeOCi+OAggogKiBAcGFyYW0gaHRhYmxlCiAqIEBwYXJhbSBrZXkKICogQHBhcmFtIGtleWxlbgogKiBAcGFyYW0gZGF0YQogKiBAcGFyYW0gc2l6ZQogKiBAcmV0dXJuCiAqLwppbnQgc2V0RGF0YUludG9IYXNoVGFibGUoTFBIYXNoVGFibGUgaHRhYmxlLCBjb25zdCB2b2lkICprZXksIGNvbnN0IGludCBrZXlsZW4sIGNvbnN0IHZvaWQgKmRhdGEsIGNvbnN0IGludCBzaXplKSB7CglpbnQgcmV0ID0gMTsKCXZvaWQgKnRlbXA7CglMUFRhYmxlRGF0YSAqcHRiZGF0YTsKCWlmIChodGFibGUgPT0gTlVMTCB8fCBrZXkgPT0gTlVMTCB8fCBkYXRhID09IE5VTEwgfHwgc2l6ZSA8IDEgfHwga2V5bGVuIDwgMSkgewoJCXJldHVybiAwOyAvKiDlvJXmlbDjgqjjg6njg7wgKi8KCX0KCXB0YmRhdGEgPSBzZWFyY2hQbGFjZShodGFibGUsIGtleSwga2V5bGVuKTsKCWlmICgqcHRiZGF0YSA9PSBOVUxMKSB7CgkJKnB0YmRhdGEgPSAoTFBUYWJsZURhdGEpQ2FsbG9jKDEsIHNpemVvZihUYWJsZURhdGEpKTsKCQlpZiAoKnB0YmRhdGEgPT0gTlVMTCkgewoJCQlyZXR1cm4gMDsgLyog44Oh44Oi44Oq56K65L+d5aSx5pWXICovCgkJfQoJCSgqcHRiZGF0YSktPmtleSA9IE1hbGxvYyhrZXlsZW4pOwoJCWlmICgoKnB0YmRhdGEpLT5rZXkgPT0gTlVMTCkgewoJCQlGcmVlKCpwdGJkYXRhKTsKCQkJKnB0YmRhdGEgPSBOVUxMOwoJCQlyZXR1cm4gMDsgLyog44Oh44Oi44Oq56K65L+d5aSx5pWXICovCgkJfQoJCSgqcHRiZGF0YSktPmRhdGEgPSBNYWxsb2Moc2l6ZSk7CgkJaWYgKCgqcHRiZGF0YSktPmRhdGEgPT0gTlVMTCkgewoJCQlGcmVlKCgqcHRiZGF0YSktPmtleSk7CgkJCUZyZWUoKnB0YmRhdGEpOwoJCQkqcHRiZGF0YSA9IE5VTEw7CgkJCXJldHVybiAwOyAvKiDjg6Hjg6Ljg6rnorrkv53lpLHmlZcgKi8KCQl9CgkJbWVtY3B5KCgqcHRiZGF0YSktPmtleSwga2V5LCBrZXlsZW4pOwoJCSgqcHRiZGF0YSktPmtleWxlbiA9IGtleWxlbjsKCQkoKnB0YmRhdGEpLT5zaXplID0gc2l6ZTsKCQkrKyhodGFibGUtPmNvdW50KTsKCX0gZWxzZSB7CgkJaWYgKCgqcHRiZGF0YSktPnNpemUgIT0gc2l6ZSkgewoJCQl0ZW1wID0gUmVhbGxvYygoKnB0YmRhdGEpLT5kYXRhLCBzaXplKTsKCQkJaWYgKHRlbXAgPT0gTlVMTCkgewoJCQkJcmV0dXJuIDA7IC8qIOODoeODouODqueiuuS/neWkseaVlyAqLwoJCQl9CgkJCSgqcHRiZGF0YSktPmRhdGEgPSB0ZW1wOwoJCQkoKnB0YmRhdGEpLT5zaXplID0gc2l6ZTsKCQl9CgkJcmV0ID0gMjsKCX0KCW1lbWNweSgoKnB0YmRhdGEpLT5kYXRhLCBkYXRhLCBzaXplKTsKCXJldHVybiByZXQ7Cn0KCi8qKgogKiBIYXNoVGFibGXlhoXjga7mjIflrprjgq3jg7zlkI3jga7jg4fjg7zjgr/jgpLliYrpmaTjgZnjgovjgIIKICogQHBhcmFtIGh0YWJsZSBIYXNoVGFibGXjgIIKICogQHBhcmFtIGtleSAgICDjgq3jg7zlkI3jgIIKICogQHJldHVybiDliYrpmaTjgafjgY3jgZ/jgokoMSnjgIHlpLHmlZfjgZfjgZ/jgokoMCnjgIIKICovCmludCByZW1vdmVEYXRhRnJvbUhhc2hUYWJsZShMUEhhc2hUYWJsZSBodGFibGUsIGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbikgewoJTFBUYWJsZURhdGEgKnB0YmRhdGE7CglMUFRhYmxlRGF0YSB0YmRhdGE7CglpZiAoaHRhYmxlID09IE5VTEwgfHwga2V5ID09IE5VTEwgfHwga2V5bGVuIDwgMSkgewoJCXJldHVybiAwOyAvKiDjgazjgovjgb0gKi8KCX0KCXB0YmRhdGEgPSBzZWFyY2hQbGFjZShodGFibGUsIGtleSwga2V5bGVuKTsKCWlmICgqcHRiZGF0YSAhPSBOVUxMKSB7CgkJdGJkYXRhID0gKnB0YmRhdGE7CgkJKnB0YmRhdGEgPSB0YmRhdGEtPm5leHQ7CgkJcmVsZWFzZVRhYmxlRGF0YSh0YmRhdGEsIDApOwoJCS0tKGh0YWJsZS0+Y291bnQpOwoJCURlYnVnRG8ocHJpbnRmKCJyZW1vdmUoc3VjY2Vzcyk6ICVkICVkXG4iLCAqKGNoYXIqKWtleSwga2V5bGVuKSk7CgkJcmV0dXJuIDE7Cgl9CglEZWJ1Z0RvKHByaW50ZigicmVtb3ZlKGZhaWx1cmUpOiAlZCAlZFxuIiwgKihjaGFyKilrZXksIGtleWxlbikpOwoJcmV0dXJuIDA7Cn0KCi8qKgogKiBIYXNoVGFibGXlhoXjgavjgq3jg7zlkI3jga7jg4fjg7zjgr/jgYzlrZjlnKjjgZnjgovjgYvmm7jjgY/jgavjgZnjgovjgIIKICogQHBhcmFtIGh0YWJsZSBIYXNoVGFibGXjgIIKICogQHBhcmFtIGtleSAgICDmjqLjgZnjgq3jg7zlkI3jgIIKICogQHBhcmFtIGtleWxlbgogKiBAcmV0dXJuIOWtmOWcqOOBmeOCjOOBsCgxKeOAgeWtmOWcqOOBl+OBquOBkeOCjOOBsCgwKeOAggogKi8KaW50IGV4aXN0S2V5SW5IYXNoVGFibGUoTFBIYXNoVGFibGUgaHRhYmxlLCBjb25zdCB2b2lkICprZXksIGNvbnN0IGludCBrZXlsZW4pIHsKCWlmIChodGFibGUgPT0gTlVMTCB8fCBrZXkgPT0gTlVMTCB8fCBrZXlsZW4gPCAxKSB7CgkJcmV0dXJuIDA7IC8qIOOBrOOCi+OBvSAqLwoJfQoJcmV0dXJuICpzZWFyY2hQbGFjZShodGFibGUsIGtleSwga2V5bGVuKSAhPSBOVUxMOwp9CgovKioKICogSGFzaFRhYmxl5YaF44Gu44OH44O844K/5pWw44KS6L+U44GZ44CCCiAqIEBwYXJhbSBodGFibGUgSGFzaFRhYmxl44CCCiAqIEByZXR1cm4g44OH44O844K/5pWw44CCCiAqLwppbnQgY291bnREYXRhSW5IYXNoVGFibGUoTFBIYXNoVGFibGUgaHRhYmxlKSB7CglpZiAoaHRhYmxlID09IE5VTEwpIHsKCQlyZXR1cm4gMDsgLyog44Gs44KL44G9ICovCgl9CglyZXR1cm4gaHRhYmxlLT5jb3VudDsKfQoKLyoqCiAqIEhhc2hUYWJsZeWGheOBruOCreODvOWQjeOCkuWFqOOBpuWPluW+l+OBmeOCi+OAggogKiBAcGFyYW0gaHRhYmxlCiAqIEBwYXJhbSBmdW5jCiAqIEByZXR1cm4KICovCmludCBnZXRBbGxLZXlzSW5IYXNoVGFibGUoY29uc3QgTFBIYXNoVGFibGUgaHRhYmxlLCBpbnQgKCpmdW5jKShjb25zdCB2b2lkICprZXksIGNvbnN0IGludCBrZXlsZW4pKSB7CglpbnQgaTsKCWludCByZXQ7CglpbnQgdGFibGVzaXplOwoJTFBUYWJsZURhdGEgKnB0YmRhdGE7CglMUFRhYmxlRGF0YSB0YmRhdGE7CglpZiAoaHRhYmxlID09IE5VTEwgfHwgZnVuYyA9PSBOVUxMKSB7CgkJcmV0dXJuIDA7Cgl9CglEZWJ1Z0RvKHByaW50ZigiYWxsa2V5KHN0YXJ0KVxuIikpOwoJcHRiZGF0YSA9IGh0YWJsZS0+dGFibGU7Cgl0YWJsZXNpemUgPSBodGFibGUtPnRhYmxlc2l6ZTsKCWZvciAoaSA9IDA7IGkgPCB0YWJsZXNpemU7ICsraSkgewoJCXRiZGF0YSA9ICpwdGJkYXRhOwoJCXdoaWxlICh0YmRhdGEgIT0gTlVMTCkgewoJCQlyZXQgPSAoKmZ1bmMpKHRiZGF0YS0+a2V5LCB0YmRhdGEtPmtleWxlbik7CgkJCWlmIChyZXQpIHsKCQkJCURlYnVnRG8ocHJpbnRmKCJhbGxrZXkoc3RvcClcbiIpKTsKCQkJCXJldHVybiAyOwoJCQl9CgkJCXRiZGF0YSA9IHRiZGF0YS0+bmV4dDsKCQl9CgkJKytwdGJkYXRhOwoJfQoJRGVidWdEbyhwcmludGYoImFsbGtleShkb25lKVxuIikpOwoJcmV0dXJuIDE7Cn0KCi8qKgogKiBIYXNoVGFibGXlhoXjga7jg4fjg7zjgr/jgpLlhajjgablj5blvpfjgZnjgovjgIIKICogQHBhcmFtIGh0YWJsZQogKiBAcGFyYW0gZnVuYwogKiBAcmV0dXJuCiAqLwppbnQgZ2V0QWxsRGF0YUluSGFzaFRhYmxlKGNvbnN0IExQSGFzaFRhYmxlIGh0YWJsZSwgaW50ICgqZnVuYykoY29uc3Qgdm9pZCAqa2V5LCBjb25zdCBpbnQga2V5bGVuLCBjb25zdCB2b2lkICpkYXRhLCBjb25zdCBpbnQgc2l6ZSkpIHsKCWludCBpOwoJaW50IHJldDsKCWludCB0YWJsZXNpemU7CglMUFRhYmxlRGF0YSAqcHRiZGF0YTsKCUxQVGFibGVEYXRhIHRiZGF0YTsKCWlmIChodGFibGUgPT0gTlVMTCB8fCBmdW5jID09IE5VTEwpIHsKCQlyZXR1cm4gMDsKCX0KCURlYnVnRG8ocHJpbnRmKCJhbGxkYXRhKHN0YXJ0KVxuIikpOwoJcHRiZGF0YSA9IGh0YWJsZS0+dGFibGU7Cgl0YWJsZXNpemUgPSBodGFibGUtPnRhYmxlc2l6ZTsKCWZvciAoaSA9IDA7IGkgPCB0YWJsZXNpemU7ICsraSkgewoJCXRiZGF0YSA9ICpwdGJkYXRhOwoJCXdoaWxlICh0YmRhdGEgIT0gTlVMTCkgewoJCQlyZXQgPSAoKmZ1bmMpKHRiZGF0YS0+a2V5LCB0YmRhdGEtPmtleWxlbiwgdGJkYXRhLT5kYXRhLCB0YmRhdGEtPnNpemUpOwoJCQlpZiAocmV0KSB7CgkJCQlEZWJ1Z0RvKHByaW50ZigiYWxsZGF0YShzdG9wKVxuIikpOwoJCQkJcmV0dXJuIDI7CgkJCX0KCQkJdGJkYXRhID0gdGJkYXRhLT5uZXh0OwoJCX0KCQkrK3B0YmRhdGE7Cgl9CglEZWJ1Z0RvKHByaW50ZigiYWxsZGF0YShkb25lKVxuIikpOwoJcmV0dXJuIDE7Cn0KCi8qICsrKyBzdGF0aWMgZnVuY3Rpb25zICsrKyAqLwoKLyoqCiAqIOOCreODvOOBruavlOi8g+OAggogKiBAcGFyYW0ga2V5MQogKiBAcGFyYW0ga2V5MWxlbgogKiBAcGFyYW0ga2V5MgogKiBAcGFyYW0ga2V5MmxlbgogKiBAcmV0dXJuCiAqLwppbnQgZGVmYXVsdEtleWNtcChjb25zdCB2b2lkICprZXkxLCBjb25zdCBpbnQga2V5MWxlbiwgY29uc3Qgdm9pZCAqa2V5MiwgY29uc3QgaW50IGtleTJsZW4pIHsKCWlmIChrZXkxbGVuICE9IGtleTJsZW4pIHsKCQlyZXR1cm4ga2V5MWxlbiAtIGtleTJsZW47Cgl9CglyZXR1cm4gbWVtY21wKGtleTEsIGtleTIsIGtleTFsZW4pOwp9CgovKioKICog44OP44OD44K344Ol6Zai5pWw44CC44Kt44O85ZCN44GL44KJ44OP44OD44K344Ol5YCk44KS55Sf5oiQ44GZ44KL44CCCiAqIEBwYXJhbSBrZXkgICAgICAgIOOCreODvOWQjeOAggogKiBAcGFyYW0ga2V5bGVuCiAqIEBwYXJhbSB0YWJsZXNpemUKICogQHJldHVybiDjg4/jg4Pjgrfjg6XlgKTjgIIKICovCmludCBkZWZhdWx0SGFzaChjb25zdCB2b2lkICprZXksIGNvbnN0IGludCBrZXlsZW4sIGNvbnN0IGludCB0YWJsZXNpemUpIHsKCWludCBpOwoJY2hhciAqcCA9IChjaGFyKilrZXk7CglpbnQgdiA9IChpbnQpKnA7CglpbnQgbG0gPSBrZXlsZW4gLSAxOwoJZm9yIChpID0gMDsgaSA8IEhBU0hfREVFUCAmJiBpIDwgbG07IGkrKykgewoJCXYgXj0gKGludCkoKnApICogKGludCkoKihwICsgMSkpOwoJCSsrcDsKCX0KCXJldHVybiB2Owp9CgovKioKICog44OP44OD44K344Ol5YCk44KS5Y+W5b6X44GZ44KL44CCCiAqIEBwYXJhbSBodGFibGUKICogQHBhcmFtIGtleQogKiBAcGFyYW0ga2V5bGVsbgogKi8KaW50IGdldEhhc2goY29uc3QgTFBIYXNoVGFibGUgaHRhYmxlLCBjb25zdCB2b2lkICprZXksIGNvbnN0IGludCBrZXlsZW4pIHsKCWludCBoID0gKCooaHRhYmxlLT5oYXNoKSkoa2V5LCBrZXlsZW4sIGh0YWJsZS0+dGFibGVzaXplKTsKCWlmIChoIDwgMCkgewoJCWggPSB+aDsKCX0KCXJldHVybiBoICUgaHRhYmxlLT50YWJsZXNpemU7Cn0KCi8qKgogKiBIYXNoVGFibGXjgYvjgonjgq3jg7zlkI3jga7jg4fjg7zjgr/jgpLmoLzntI3jgZnjgovloLTmiYAo44Ki44OJ44Os44K5KeOCkuaOouOBmeOAggogKiBAcGFyYW0gaHRhYmxlIOOCreODvOWQjeOCkuaOouOBmUhhc2hUYWJsZeOAggogKiBAcGFyYW0ga2V5ICAgIOaOouOBmeOCreODvOWQjeOAggogKiBAcGFyYW0ga2V5bGVuCiAqIEByZXR1cm4g5qC857SN44GV44KM44Gm44KL5aC05omAKOOCouODieODrOOCuSnjgIIKICovCkxQVGFibGVEYXRhICpzZWFyY2hQbGFjZShjb25zdCBMUEhhc2hUYWJsZSBodGFibGUsIGNvbnN0IHZvaWQgKmtleSwgY29uc3QgaW50IGtleWxlbikgewoJaW50IGggPSBnZXRIYXNoKGh0YWJsZSwga2V5LCBrZXlsZW4pOwoJTFBUYWJsZURhdGEgKnB0YmRhdGEgPSBodGFibGUtPnRhYmxlICsgaDsKCXdoaWxlICgqcHRiZGF0YSAhPSBOVUxMKSB7CgkJaWYgKCgqKGh0YWJsZS0+a2V5Y21wKSkoKCpwdGJkYXRhKS0+a2V5LCAoKnB0YmRhdGEpLT5rZXlsZW4sIGtleSwga2V5bGVuKSA9PSAwKSB7CgkJCWJyZWFrOwoJCX0KCQlwdGJkYXRhID0gJigqcHRiZGF0YSktPm5leHQ7Cgl9CglEZWJ1Z0RvKHByaW50ZigiaGFzaDogJWQgJWQgLT4gJWRcbiIsICooY2hhciopa2V5LCBrZXlsZW4sIGgpKTsKCXJldHVybiBwdGJkYXRhOwp9CgovKioKICogVGFibGVEYXRh44KS44Oh44Oi44Oq44GL44KJ6Kej5pS+44GZ44KL44CCCiAqIEBwYXJhbSBwdGJkYXRhIOino+aUvuOBmeOCi+ODh+ODvOOCv+OAggogKiBAcGFyYW0gY2hhaW4gICBuZXh044Gr44GC44KLVGFibGVEYXRh44KC6Kej5pS+44GZ44KLKDEp44GL44GX44Gq44GEKDAp44GL44CCCiAqLwp2b2lkIHJlbGVhc2VUYWJsZURhdGEoTFBUYWJsZURhdGEgdGJkYXRhLCBpbnQgY2hhaW4pIHsKCWlmICh0YmRhdGEgPT0gTlVMTCkgewoJCXJldHVybjsKCX0KCWlmIChjaGFpbikgewoJCXJlbGVhc2VUYWJsZURhdGEodGJkYXRhLT5uZXh0LCBjaGFpbik7Cgl9CglEZWJ1Z0RvKHByaW50ZigicmVsZWFzZSBUYWJsZURhdGE6ICVkICVkXG4iLCAqKChjaGFyKikodGJkYXRhLT5rZXkpKSwgdGJkYXRhLT5rZXlsZW4pKTsKCUZyZWUodGJkYXRhLT5rZXkpOwoJRnJlZSh0YmRhdGEtPmRhdGEpOwoJRnJlZSh0YmRhdGEpOwp9