#include <limits.h>
#include "cdf.h"
// messaggi d'errore
static const char *CDFStr_NoDati = "Dati insufficienti o inadatti.";
static const char *CDFStr_NoMemoria = "Memoria insufficiente.";
static const char *CDFStr_ChiaveNonValida = "Chiave non valida.";
static const char *CDFStr_ChiaveNonDisponibile = "Chiave non disponibile.";
static const char *CDFStr_DatiNonDisponibili = "Dati non disponibili.";
static const char *CDFStr_PercorsoFileNonValido = "Percorso file non valido.";
static const char *CDFStr_DatiNonSalvati = "Dati non salvati.";
// prototipi di funzioni non membro
static int AccettaStringa( char **dest, const char *orig,
unsigned long *lDest, unsigned long lOrig = 0xFFFFFFFF );
static char *DuplicaStringa( const char *s, unsigned long l = 0xFFFFFFFF );
static void EliminaStringa( char **s, unsigned long *l );
static void IdentificaCaratteri( char *sDati, unsigned long lDati, bool *lista );
static unsigned long RandUl( unsigned long lim );
CDF::CDF() {
InizializzaNullo();
}
CDF::CDF( const CDF& daCopiare ) {
if( !Copia(&daCopiare) ) throw CDFStr_NoMemoria;
}
CDF::~CDF() {
EliminaStringa( &chiave, &lChiave );
EliminaStringa( &dati, &lDati );
}
CDF& CDF::operator=(const CDF& daAssegnare) {
if (this == &daAssegnare) return *this; // gestisce l'auto assegnamento
if( !Copia(&daAssegnare) ) throw CDFStr_NoMemoria;
return *this;
}
void CDF::imposta_chiave( const char *sChiave, unsigned long l ) {
EliminaStringa( &chiave, &lChiave );
switch( AccettaStringa(&chiave,sChiave,&lChiave,l) ) {
case 1: throw CDFStr_NoMemoria;
case 2: throw CDFStr_ChiaveNonDisponibile;
default: VerificaChiave(); break;
}
}
const char *CDF::ricava_chiave( void ) {
if( chiave != NULL )
return DuplicaStringa( chiave, lChiave );
else return chiave;
}
void CDF::imposta_dati( int tipoDati, const char *sDati, unsigned long l ) {
EliminaStringa( &dati, &lDati );
ImpostaTipoDati( tipoDati );
if( tDati == kCDFNoDati )
throw CDFStr_DatiNonDisponibili;
switch( AccettaStringa(&dati,sDati,&lDati,l) ) {
case 1: throw CDFStr_NoMemoria;
case 2: throw CDFStr_DatiNonDisponibili;
default: VerificaChiave();
}
}
const char *CDF::ricava_dati( void ) {
if( dati != NULL )
return DuplicaStringa( dati, lDati );
else return dati;
}
void CDF::elabora( void ) {
switch( tDati ) {
case kCDFInChiaro: Codifica(); break;
case kCDFCodificati: Decodifica(); break;
default: throw CDFStr_DatiNonDisponibili;
}
}
void CDF::salva_dati( const char *percFile ) {
if( percFile == NULL ) throw CDFStr_PercorsoFileNonValido;
if( dati == NULL ) throw CDFStr_DatiNonDisponibili;
FILE *f = fopen( percFile, "w+" );
if( f == NULL ) throw CDFStr_DatiNonSalvati;
fprintf( f, dati );
fclose( f );
}
void CDF::InizializzaNullo( void ) {
chiave = NULL; // la stringa della chiave
lChiave = 0; // la quantita di caratteri nella chiave
dati = NULL; // la stringa dei dati
lDati = 0; // la quantita di caratteri nei dati
tDati = kCDFNoDati; // kCDFNoDati, kCDFInChiaro, kCDFCodificati
InizializzaCaratteriMancanti();
}
bool CDF::Copia( const CDF *originale ) {
try {
chiave = dati = NULL;
lChiave = originale->lChiave;
chiave = new char[lChiave+1];
memcpy( chiave, originale->chiave, lChiave+1 );
lDati = originale->lDati;
dati = new char[lDati+1];
memcpy( dati, originale->dati, lDati+1 );
tDati = originale->tDati;
for( int i=0; i<256; ++i )
carMancanti[i] = originale->carMancanti[i];
nCarMancanti = originale->nCarMancanti;
return true;
} catch( ... ) {
delete[] chiave;
delete[] dati;
return false;
}
}
void CDF::InizializzaCaratteriMancanti( void ) {
for( nCarMancanti=256; nCarMancanti; ) // la quantita dei caratteri mancanti
carMancanti[--nCarMancanti] = '\0'; // i caratteri mancanti nella chiave
}
void CDF::ImpostaTipoDati( int tipoDati ) {
switch( tipoDati ) {
case kCDFInChiaro:
case kCDFCodificati:
tDati = tipoDati;
break;
default:
tDati = kCDFNoDati;
}
}
bool CDF::VerificaChiave( void ) {
unsigned long i;
bool carInChiaro[256];
bool carInChiave[256];
InizializzaCaratteriMancanti();
if( chiave == NULL ) return false;
if( dati == NULL ) return true;
if( tDati == kCDFCodificati ) return true;
// identificazione dei caratteri presenti nel testo in chiaro
IdentificaCaratteri( dati, lDati, carInChiaro );
// identificazione dei caratteri presenti nella chiave
IdentificaCaratteri( chiave, lChiave, carInChiave );
// conteggio e memorizzazione dei caratteri mancanti
for( nCarMancanti=0, i=0; i<256; ++i )
if(carInChiaro[i] && !carInChiave[i])
carMancanti[nCarMancanti++] = i;
return ( nCarMancanti == 0 );
}
void CDF::Codifica( void ) {
if( chiave==NULL || dati==NULL || nCarMancanti!=0 ) throw CDFStr_NoDati;
char *buff = NULL;
char *pBuff = NULL;
char cifre[16];
int maxCifre;
unsigned long i, j;
char sep[] = { '8', '9' };
char a, b;
// rileva la quantita' massima delle cifre che possono costituire ciascuno
// degli indici che verranno memorizzati nella versione codificata del testo
sprintf( cifre, "%lo", lChiave );
maxCifre = strlen( cifre );
try { // alloca un buffer temporaneo per il testo codificato
buff = new char[lDati*(maxCifre+1)+1];
// un unsigned long ottale convertito in stringa conta un massimo
// di 11 caratteri; e' stato usato 12 per far spazio al separatore;
// "+1" invece occorre per prevedere spazio per il terminatore
pBuff = buff;
} catch( ... ) {
throw CDFStr_NoMemoria;
}
// Carattere per carattere, scorre il testo in chiaro. Per ogni carattere
// cerca un corrispondente nel file della chiave partendo da un punto casua-
// le. Quando lo trova, ne memorizza la posizione sotto forma di un numero
// in formato ottale. Le posizioni sono separate tra loro da un '8' o da un
// '9' (anche questo separatore e' scelto in modo casuale).
for( i=0; i<lDati; i++ ) {
j = RandUl( lChiave );
a = dati[i];
do {
b = chiave[j];
if( a == b ) {
if(i != lDati-1 ) {
pBuff += sprintf( pBuff, "%lo%c", j, sep[rand()%2] );
}
else {
// se siamo all'ultimo carattere, il
// separatore puo' essere o non essere aggiunto
if( rand()%5)
pBuff += sprintf( pBuff, "%lo", j );
else pBuff += sprintf( pBuff, "%lo%c", j, sep[rand()%2] );
}
}
++j;
if( j >= lChiave ) j = 0;
} while( a != b );
}
if( RinnovaDati(buff,pBuff-buff) ) {
delete[] buff;
tDati = kCDFCodificati;
}
else {
delete[] buff;
throw CDFStr_NoMemoria;
}
}
void CDF::Decodifica( void ) {
if( chiave==NULL || dati==NULL || nCarMancanti!=0 ) throw CDFStr_NoDati;
char *buff = NULL;
char *pBuff = NULL;
unsigned long pos;
char *p, *b;
char ottale[16];
char aux, prec;
try { // alloca un buffer temporaneo per il testo decodificato
buff = new char[lDati+1];
// i dati decodificati hanno sempre dimensioni minori rispetto ai dati
// codificati; "+1" occorre per prevedere spazio per il terminatore
pBuff = buff;
} catch( ... ) {
throw CDFStr_NoMemoria;
}
// Scorre il file codificato cercando i separatori '8' e '9' per isolare i
// singoli numeri ottali che indicano le posizioni dei caratteri nella chia-
// ve. Legge quei numeri e ricompone il testo in chiaro nel file temporaneo.
p = dati;
b = ottale;
prec = -1;
do {
aux = *p;
if( aux != '8' && aux != '9' && aux != '\0' ) {
*b = aux;
++b;
++p;
}
else {
if( aux == '\0' && (prec=='8'||prec=='9')) break;
*b = '\0';
sscanf( ottale, "%lo", &pos );
if( pos>=lChiave ) {
delete[] buff;
throw CDFStr_ChiaveNonValida;
}
pBuff += sprintf( pBuff, "%c", chiave[pos] );
if( aux == '\0' ) break;
b = ottale;
++p;
}
prec = aux;
} while( true );
if( RinnovaDati(buff,pBuff-buff) ) {
delete[] buff;
tDati = kCDFInChiaro;
}
else {
delete[] buff;
throw CDFStr_NoMemoria;
}
}
bool CDF::RinnovaDati( char *nuoviDati, unsigned long l ) {
if( nuoviDati == NULL ) return false;
EliminaStringa( &dati, &lDati );
tDati = kCDFNoDati;
try {
dati = new char[l+1];
memcpy( dati, nuoviDati, l+1 );
lDati = l;
return true;
} catch( ... ) {
return false;
}
}
int AccettaStringa( char **dest, const char *orig,
unsigned long *lDest, unsigned long lOrig ) {
if( orig != NULL ) {
if( lOrig == 0xFFFFFFFF ) lOrig = strlen( orig );
*dest = DuplicaStringa( orig, lOrig );
*lDest = *dest!=NULL ? lOrig : 0;
if( *dest != NULL ) return 0; else return 1;
}
else {
return 2;
}
}
char *DuplicaStringa( const char *s, unsigned long l ) {
if( l==0xFFFFFFFF ) l = strlen( s );
try {
char *esito = new char[l+1];
strcpy( esito, s );
return esito;
} catch( ... ) {
return NULL;
}
}
void EliminaStringa( char **s, unsigned long *l ) {
delete[] *s;
*s = NULL;
*l = 0;
}
void IdentificaCaratteri( char *sDati, unsigned long lDati, bool *lista ) {
unsigned long i;
for( i=0; i<256; ++i ) lista[i] = false;
if( sDati == NULL ) return;
for( i=0; i<lDati; ++i ) {
if( sDati[i]>='\0')
lista[(int)sDati[i]] = true;
else lista[(int)sDati[i]+256] = true;
}
}
unsigned long RandUl( unsigned long lim ) {
return ((((unsigned long)rand())<<17)+(((unsigned long)rand())<<2)+rand()%4)%lim;
}