1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-02 16:49:41 +02:00
2010-01-24 09:19:39 +00:00

535 lines
12 KiB
C

/* -*- Mode: c; c-basic-offset: 2 -*-
*
* rdf_digest.c - RDF Digest Factory / Digest implementation
*
* Copyright (C) 2000-2008, David Beckett http://www.dajobe.org/
* Copyright (C) 2000-2005, Copyright (C) 2000-2006, Copyright (C) 2000-2006, University of Bristol, UK http://www.bristol.ac.uk/
*
* This package is Free Software and part of Redland http://librdf.org/
*
* It is licensed under the following three licenses as alternatives:
* 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
* 2. GNU General Public License (GPL) V2 or any newer version
* 3. Apache License, V2.0 or any newer version
*
* You may not use this file except in compliance with at least one of
* the above three licenses.
*
* See LICENSE.html or LICENSE.txt at the top of this package for the
* complete terms and further detail along with the license texts for
* the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
*
*
*/
#ifdef HAVE_CONFIG_H
#include <rdf_config.h>
#endif
#ifdef WIN32
#include <win32_rdf_config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h> /* for abort() as used in errors */
#endif
#include <redland.h>
#ifndef STANDALONE
/* prototypes for helper functions */
static void librdf_delete_digest_factories(librdf_world* world);
/* helper functions */
static void
librdf_delete_digest_factories(librdf_world *world)
{
librdf_digest_factory *factory, *next;
for(factory=world->digests; factory; factory=next) {
next=factory->next;
LIBRDF_FREE(librdf_digest_factory, factory->name);
LIBRDF_FREE(librdf_digest_factory, factory);
}
world->digests=NULL;
}
/**
* librdf_digest_register_factory:
* @world: redland world object
* @name: the name of the hash
* @factory: function to be called to register the factory parameters
*
* Register a hash factory.
*
**/
void
librdf_digest_register_factory(librdf_world *world, const char *name,
void (*factory) (librdf_digest_factory*))
{
librdf_digest_factory *digest;
librdf_world_open(world);
#if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
LIBRDF_DEBUG2("Received registration for digest %s\n", name);
#endif
for(digest = world->digests; digest; digest = digest->next ) {
if(!strcmp(digest->name, name)) {
librdf_log(world, 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_DIGEST, NULL,
"digest %s already registered", digest->name);
return;
}
}
digest=(librdf_digest_factory*)LIBRDF_CALLOC(librdf_digest_factory, 1,
sizeof(librdf_digest_factory));
if(!digest)
goto oom;
digest->name=(char*)LIBRDF_MALLOC(cstring, strlen(name)+1);
if(!digest->name)
goto oom_tidy;
strcpy(digest->name, name);
digest->next = world->digests;
world->digests = digest;
/* Call the digest registration function on the new object */
(*factory)(digest);
#if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
LIBRDF_DEBUG4("%s has context size %d and digest size %d\n", name, digest->context_length, digest->digest_length);
#endif
return;
oom_tidy:
LIBRDF_FREE(librdf_digest, digest);
oom:
LIBRDF_FATAL1(world, LIBRDF_FROM_DIGEST, "Out of memory");
}
/**
* librdf_get_digest_factory:
* @world: redland world object
* @name: the name of the factory
*
* Get a digest factory.
*
* Return value: the factory or NULL if not found
**/
librdf_digest_factory*
librdf_get_digest_factory(librdf_world *world, const char *name)
{
librdf_digest_factory *factory;
librdf_world_open(world);
/* return 1st digest if no particular one wanted - why? */
if(!name) {
factory=world->digests;
if(!factory) {
LIBRDF_DEBUG1("No digests available\n");
return NULL;
}
} else {
for(factory=world->digests; factory; factory=factory->next) {
if(!strcmp(factory->name, name))
break;
}
/* else FACTORY with name digest_name not found -> return NULL */
}
return factory;
}
/**
* librdf_new_digest:
* @world: redland world object
* @name: the digest name to use to create this digest
*
* Constructor - create a new #librdf_digest object.
*
* After construction, data should be added to the digest using
* #librdf_digest_update or #librdf_digest_update_string with
* #librdf_digest_final to signify finishing. Then the digest
* value can be returned directly with #librdf_digest_get_digest
* of #librdf_digest_get_digest_length bytes or as a hex encoded
* string with #librdf_digest_to_string. The digest can be
* re-initialised for new data with #librdf_digest_init.
*
* Return value: new #librdf_digest object or NULL
**/
librdf_digest*
librdf_new_digest(librdf_world *world, const char *name)
{
librdf_digest_factory* factory;
librdf_world_open(world);
factory=librdf_get_digest_factory(world, name);
if(!factory)
return NULL;
return librdf_new_digest_from_factory(world, factory);
}
/**
* librdf_new_digest_from_factory:
* @world: redland world object
* @factory: the digest factory to use to create this digest
*
* Constructor - create a new #librdf_digest object.
*
* After construction, data should be added to the digest using
* #librdf_digest_update or #librdf_digest_update_string with
* #librdf_digest_final to signify finishing. Then the digest
* value can be returned directly with #librdf_digest_get_digest
* of #librdf_digest_get_digest_length bytes or as a hex encoded
* string with #librdf_digest_to_string. The digest can be
* re-initialised for new data with #librdf_digest_init.
*
* Return value: new #librdf_digest object or NULL
**/
librdf_digest*
librdf_new_digest_from_factory(librdf_world *world,
librdf_digest_factory *factory)
{
librdf_digest* d;
librdf_world_open(world);
d=(librdf_digest*)LIBRDF_CALLOC(librdf_digest, 1, sizeof(librdf_digest));
if(!d)
return NULL;
d->world=world;
d->context=(char*)LIBRDF_CALLOC(digest_context, 1, factory->context_length);
if(!d->context) {
librdf_free_digest(d);
return NULL;
}
d->digest=(unsigned char*)LIBRDF_CALLOC(digest_digest, 1,
factory->digest_length);
if(!d->digest) {
librdf_free_digest(d);
return NULL;
}
d->factory=factory;
d->factory->init(d->context);
return d;
}
/**
* librdf_free_digest:
* @digest: the digest
*
* Destructor- destroy a #librdf_digest object.
*
**/
void
librdf_free_digest(librdf_digest *digest)
{
if(digest->context)
LIBRDF_FREE(digest_context, digest->context);
if(digest->digest)
LIBRDF_FREE(digest_digest, digest->digest);
LIBRDF_FREE(librdf_digest, digest);
}
/* methods */
/**
* librdf_digest_init:
* @digest: the digest
*
* (Re)initialise the librdf_digest object.
*
* This is automatically called on construction but can be used to
* re-initialise the digest to the initial state for digesting new
* data.
**/
void
librdf_digest_init(librdf_digest* digest)
{
digest->factory->init(digest->context);
}
/**
* librdf_digest_update:
* @digest: the digest
* @buf: the data buffer
* @length: the length of the data
*
* Add more data to the librdf_digest object.
*
**/
void
librdf_digest_update(librdf_digest* digest,
const unsigned char *buf, size_t length)
{
digest->factory->update(digest->context, buf, length);
}
/**
* librdf_digest_update_string:
* @digest: the digest
* @string: string to add
*
* Add a string to the librdf_digest object.
*
**/
void
librdf_digest_update_string(librdf_digest* digest,
const unsigned char *string)
{
digest->factory->update(digest->context, string,
strlen((const char*)string));
}
/**
* librdf_digest_final:
* @digest: the digest
*
* Finish the digesting of data.
*
* The digest can now be returned via librdf_digest_get_digest().
**/
void
librdf_digest_final(librdf_digest* digest)
{
void* digest_data;
digest->factory->final(digest->context);
digest_data=(*(digest->factory->get_digest))(digest->context);
memcpy(digest->digest, digest_data, digest->factory->digest_length);
}
/**
* librdf_digest_get_digest:
* @digest: the digest
*
* Get the calculated digested value.
*
* Return value: pointer to the memory containing the digest. It will
* be #librdf_digest_get_digest_length bytes in length.
*
**/
void*
librdf_digest_get_digest(librdf_digest* digest)
{
return digest->digest;
}
/**
* librdf_digest_get_digest_length:
* @digest: the digest
*
* Get length of the calculated digested.
*
* Return value: size of the digest in bytes
*
**/
size_t
librdf_digest_get_digest_length(librdf_digest* digest)
{
return digest->factory->digest_length;
}
/**
* librdf_digest_to_string:
* @digest: the digest
*
* Get a string representation of the digest object.
*
* Return value: a newly allocated string that represents the digest.
* This must be released by the caller using free()
**/
char *
librdf_digest_to_string(librdf_digest* digest)
{
unsigned char* data=digest->digest;
int mdlen=digest->factory->digest_length;
char* b;
int i;
b=(char*)LIBRDF_MALLOC(cstring, 1+(mdlen<<1));
if(!b)
LIBRDF_FATAL1(digest->world, LIBRDF_FROM_DIGEST, "Out of memory");
for(i=0; i<mdlen; i++)
sprintf(b+(i<<1), "%02x", (unsigned int)data[i]);
b[i<<1]='\0';
return(b);
}
/**
* librdf_digest_print:
* @digest: the digest
* @fh: file handle
*
* Print the digest to a FILE handle.
*
**/
void
librdf_digest_print(librdf_digest* digest, FILE* fh)
{
char *s=librdf_digest_to_string(digest);
if(!s)
return;
fputs(s, fh);
LIBRDF_FREE(cstring, s);
}
/**
* librdf_init_digest:
* @world: redland world object
*
* INTERNAL - Initialise the digest module.
*
**/
void
librdf_init_digest(librdf_world *world)
{
#ifdef HAVE_OPENSSL_DIGESTS
librdf_digest_openssl_constructor(world);
#endif
#ifdef HAVE_LOCAL_MD5_DIGEST
librdf_digest_md5_constructor(world);
#endif
#ifdef HAVE_LOCAL_RIPEMD160_DIGEST
librdf_digest_rmd160_constructor(world);
#endif
#ifdef HAVE_LOCAL_SHA1_DIGEST
librdf_digest_sha1_constructor(world);
#endif
/* set default */
world->digest_factory=librdf_get_digest_factory(world,
world->digest_factory_name);
}
/**
* librdf_finish_digest:
* @world: redland world object
*
* INTERNAL - Terminate the digest module.
*
**/
void
librdf_finish_digest(librdf_world *world)
{
librdf_delete_digest_factories(world);
}
#endif
#ifdef STANDALONE
/* one more prototype */
int main(int argc, char *argv[]);
struct t
{
const char *type;
const char *result;
};
int
main(int argc, char *argv[])
{
librdf_digest* d;
const char *test_data="http://purl.org/net/dajobe/";
struct t test_data_answers[]={
{"MD5", "80b52def747e8748199c1a0cf66cb35c"},
{"SHA1", "67d6a7b73504ce5c6b47fd6db9b7c4939bfe5174"},
{"RIPEMD160", "83ce259f0c23642a95fc92fade583e6d8e15784d"},
{NULL, NULL},
};
int failures=0;
int i;
struct t *answer=NULL;
const char *program=librdf_basename((const char*)argv[0]);
librdf_world *world;
world=librdf_new_world();
for(i=0; ((answer= &test_data_answers[i]) && answer->type != NULL) ; i++) {
char *s;
fprintf(stdout, "%s: Trying to create new %s digest\n", program,
answer->type);
d=librdf_new_digest(world, answer->type);
if(!d) {
fprintf(stderr, "%s: Failed to create new digest type %s\n", program,
answer->type);
continue;
}
fprintf(stdout, "%s: Initialising digest type %s\n", program, answer->type);
librdf_digest_init(d);
fprintf(stdout, "%s: Writing data into digest\n", program);
librdf_digest_update(d, (unsigned char*)test_data, strlen(test_data));
fprintf(stdout, "%s: Finishing digesting\n", program);
librdf_digest_final(d);
fprintf(stdout, "%s: %s digest of data is: ", program, answer->type);
librdf_digest_print(d, stdout);
fputc('\n', stdout);
s=librdf_digest_to_string(d);
if(strcmp(s, answer->result)) {
fprintf(stderr, "%s: %s digest is wrong - expected: %s\n", program, answer->type, answer->result);
failures++;
} else
fprintf(stderr, "%s: %s digest is correct\n", program, answer->type);
LIBRDF_FREE(cstring, s);
fprintf(stdout, "%s: Freeing digest\n", program);
librdf_free_digest(d);
}
librdf_free_world(world);
/* keep gcc -Wall happy */
return failures;
}
#endif