mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-02 16:49:41 +02:00
535 lines
12 KiB
C
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
|