paulo@0: /* paulo@0: * $Id: gt_urn.c,v 1.4 2004/03/05 17:47:29 hipnod Exp $ paulo@0: * paulo@0: * Copyright (C) 2003 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: #include "gt_urn.h" paulo@0: #include "encoding/base32.h" paulo@0: #include "sha1.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: #define URN_PREFIX_LEN (sizeof("urn:")-1) paulo@0: #define SHA1_PREFIX_LEN (sizeof("sha1:")-1) paulo@0: #define BITPRINT_PREFIX_LEN (sizeof("bitprint:")-1) paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: enum urn_types paulo@0: { paulo@0: GT_URN_SHA1 = 0, paulo@0: GT_URN_BITPRINT = 1, /* for now, collapse bitprint to sha1 */ paulo@0: }; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static long get_urn_type (gt_urn_t *urn) paulo@0: { paulo@0: long tmp; paulo@0: paulo@0: memcpy (&tmp, urn, sizeof(tmp)); paulo@0: return tmp; paulo@0: } paulo@0: paulo@0: static void set_urn_type (gt_urn_t *urn, enum urn_types t) paulo@0: { paulo@0: long tmp = t; paulo@0: paulo@0: memcpy (urn, &tmp, sizeof(tmp)); paulo@0: } paulo@0: paulo@0: static unsigned char *get_urn_data (const gt_urn_t *urn) paulo@0: { paulo@0: return (unsigned char *)urn + sizeof(long); paulo@0: } paulo@0: paulo@0: static void set_urn_data (gt_urn_t *urn, const unsigned char *data, size_t len) paulo@0: { paulo@0: memcpy (get_urn_data (urn), data, len); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static size_t bin_length (enum urn_types t) paulo@0: { paulo@0: switch (t) paulo@0: { paulo@0: case GT_URN_BITPRINT: paulo@0: case GT_URN_SHA1: return SHA1_BINSIZE; paulo@0: default: return 0; paulo@0: } paulo@0: } paulo@0: paulo@0: static gt_urn_t *sha1_urn_new (const unsigned char *data) paulo@0: { paulo@0: gt_urn_t *new_urn; paulo@0: paulo@0: if (!(new_urn = malloc (SHA1_BINSIZE + sizeof(long)))) paulo@0: return NULL; paulo@0: paulo@0: /* put the identifier at the beginning */ paulo@0: set_urn_type (new_urn, GT_URN_SHA1); paulo@0: paulo@0: /* copy the data */ paulo@0: set_urn_data (new_urn, data, SHA1_BINSIZE); paulo@0: paulo@0: return new_urn; paulo@0: } paulo@0: paulo@0: gt_urn_t *gt_urn_new (const char *urn_type, const unsigned char *data) paulo@0: { paulo@0: if (!strcasecmp (urn_type, "urn:sha1")) paulo@0: return sha1_urn_new (data); paulo@0: paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: unsigned char *gt_urn_data (const gt_urn_t *urn) paulo@0: { paulo@0: if (!urn) paulo@0: return NULL; paulo@0: paulo@0: return get_urn_data (urn); paulo@0: } paulo@0: paulo@0: char *gt_urn_string (const gt_urn_t *urn) paulo@0: { paulo@0: unsigned char *data; paulo@0: char *urn_str; paulo@0: const size_t prefix_len = URN_PREFIX_LEN + SHA1_PREFIX_LEN; paulo@0: paulo@0: /* paulo@0: * This is the same for bitprint and sha1 urns, because we convert paulo@0: * to sha1 anyway. paulo@0: */ paulo@0: paulo@0: if (!(data = gt_urn_data (urn))) paulo@0: return NULL; paulo@0: paulo@0: if (!(urn_str = malloc (prefix_len + SHA1_STRLEN + 1))) paulo@0: return NULL; paulo@0: paulo@0: memcpy (urn_str, "urn:sha1:", prefix_len); paulo@0: gt_base32_encode (data, SHA1_BINSIZE, urn_str + prefix_len, SHA1_STRLEN); paulo@0: paulo@0: urn_str[prefix_len + SHA1_STRLEN] = 0; paulo@0: paulo@0: return urn_str; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static gt_urn_t *sha1_urn_parse (const char *base32) paulo@0: { paulo@0: gt_urn_t *bin; paulo@0: paulo@0: /* make sure the hash is the right length */ paulo@0: if (!gt_base32_valid (base32, SHA1_STRLEN)) paulo@0: return NULL; paulo@0: paulo@0: if (!(bin = malloc (SHA1_BINSIZE + sizeof(long)))) paulo@0: return NULL; paulo@0: paulo@0: gt_base32_decode (base32, SHA1_STRLEN, bin + sizeof(long), SHA1_BINSIZE); paulo@0: set_urn_type (bin, GT_URN_SHA1); paulo@0: paulo@0: return bin; paulo@0: } paulo@0: paulo@0: /* paulo@0: * Bitprint urns are the format: paulo@0: * paulo@0: * urn:bitprint:[32-character SHA1].[39-character TigerTree] paulo@0: * paulo@0: * We use the sha1 parsing and truncate the tigertree for now. paulo@0: */ paulo@0: static gt_urn_t *bitprint_urn_parse (const char *base32) paulo@0: { paulo@0: return sha1_urn_parse (base32); paulo@0: } paulo@0: paulo@0: gt_urn_t *gt_urn_parse (const char *str) paulo@0: { paulo@0: if (strncasecmp ("urn:", str, URN_PREFIX_LEN) != 0) paulo@0: return NULL; paulo@0: paulo@0: str += URN_PREFIX_LEN; paulo@0: paulo@0: if (!strncasecmp (str, "sha1:", SHA1_PREFIX_LEN)) paulo@0: return sha1_urn_parse (str + SHA1_PREFIX_LEN); paulo@0: paulo@0: if (!strncasecmp (str, "bitprint:", BITPRINT_PREFIX_LEN)) paulo@0: return bitprint_urn_parse (str + BITPRINT_PREFIX_LEN); paulo@0: paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: int gt_urn_cmp (gt_urn_t *a, gt_urn_t *b) paulo@0: { paulo@0: int ret; paulo@0: paulo@0: if (!a || !b) paulo@0: return -1; paulo@0: paulo@0: if ((ret = memcmp (a, b, 4))) paulo@0: return ret; paulo@0: paulo@0: return memcmp (a + sizeof(long), b + sizeof(long), paulo@0: bin_length (get_urn_type (a))); paulo@0: }