www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - array and pointers

reply Alberto <reda zioale.it> writes:
hi, I have just started to play with D, and I have some little problem.

In C I did something like:

#define uchar  unsigned char

void aes_ecb_decrypt(aes_context *ctx, uchar *input, uchar *output, uint
len ) {
    int n;
    uchar *pin, *pout;

    // test to validate parameters..

    n = len;
    pin = input;
    pout = output;

    while( n > 0 ) {
        decrypt_block(ctx, pin, pout );
        pin  += 16;
        pout += 16;
        n -= 16;
    }
}

in D:

void decrypt_block(ubyte[] input, ubyte[] output) ;

ubyte[] ecb_decrypt(in ubyte[] input)
	in {
		assert(input.length > 0);
	}
	out(output) {
		assert(output.length == input.length);
	}
	body {
		int i,n, idx;
		ubyte[] pin;
		ubyte[] pout;
		ubyte[] output;
		
		n = input.length;
		output.length = n;
		idx=0;
			
		while( n > 0 ) {
			if (idx+BLOCK_SIZE >= input.length) {
				//we must decrypt less then BLOCK_SIZE
				decrypt_block(input[idx..$], output[idx..$]);
			} else {
				decrypt_block( input[idx..idx+BLOCK_SIZE], output[idx..idx+BLOCK_SIZE]);
			}
			idx += BLOCK_SIZE;
			n -= BLOCK_SIZE;
		}
		return output;
	}
	
but I don't think that is the right way..
There is a simpler way using pointers like in C?
I have tried to use something like:


	int n;
	ubyte *pin;
	ubyte *pout;
	ubyte[] output;
			
	n = input.length;
	output.length = n;
	pin = input.ptr;
	pout = output.ptr;
			
	while( n > 0 ) {
		decrypt_block(cast(ubyte[])pin, cast(ubyte[])pout);
		pin  += 16;
		pout += 16;
		n -= 16;
	}

but I get:
test_aes.d(158): Error: e2ir: cannot cast from ubyte* to ubyte[]
test_aes.d(158): Error: e2ir: cannot cast from ubyte* to ubyte[]

yes I can modify decrypt_block, but this is not the point, I want just
understand how can I solve it, in a D way.
Jan 25 2007
parent reply Matthew Wesley <mwesley acm.org> writes:
On Thu, 25 Jan 2007 12:36:53 +0100
Alberto <reda zioale.it> wrote:

 hi, I have just started to play with D, and I have some little
 problem.
 
 In C I did something like:
 
 #define uchar  unsigned char
 
 void aes_ecb_decrypt(aes_context *ctx, uchar *input, uchar *output,
 uint len ) {
     int n;
     uchar *pin, *pout;
 
     // test to validate parameters..
 
     n = len;
     pin = input;
     pout = output;
 
     while( n > 0 ) {
         decrypt_block(ctx, pin, pout );
         pin  += 16;
         pout += 16;
         n -= 16;
     }
 }
 
 in D:
 
 void decrypt_block(ubyte[] input, ubyte[] output) ;
 
 ubyte[] ecb_decrypt(in ubyte[] input)
 	in {
 		assert(input.length > 0);
 	}
 	out(output) {
 		assert(output.length == input.length);
 	}
 	body {
 		int i,n, idx;
 		ubyte[] pin;
 		ubyte[] pout;
 		ubyte[] output;
 		
 		n = input.length;
 		output.length = n;
 		idx=0;
 			
 		while( n > 0 ) {
 			if (idx+BLOCK_SIZE >= input.length) {
 				//we must decrypt less then BLOCK_SIZE
 				decrypt_block(input[idx..$],
 output[idx..$]); } else {
 				decrypt_block( input[idx..idx+BLOCK_SIZE],
 output[idx..idx+BLOCK_SIZE]); }
 			idx += BLOCK_SIZE;
 			n -= BLOCK_SIZE;
 		}
 		return output;
 	}
 	
 but I don't think that is the right way..
 There is a simpler way using pointers like in C?
 I have tried to use something like:
 
 
 	int n;
 	ubyte *pin;
 	ubyte *pout;
 	ubyte[] output;
 			
 	n = input.length;
 	output.length = n;
 	pin = input.ptr;
 	pout = output.ptr;
 			
 	while( n > 0 ) {
 		decrypt_block(cast(ubyte[])pin, cast(ubyte[])pout);
 		pin  += 16;
 		pout += 16;
 		n -= 16;
 	}
 
 but I get:
 test_aes.d(158): Error: e2ir: cannot cast from ubyte* to ubyte[]
 test_aes.d(158): Error: e2ir: cannot cast from ubyte* to ubyte[]
 
 yes I can modify decrypt_block, but this is not the point, I want just
 understand how can I solve it, in a D way.
 
 

The problem you are having is that arrays in D are not like arrays in C. Think of D arrays as: struct DArray { type *ptr; size_t length; } This means there is no way to cast from a pointer to a D array, because D MUST know the length of that array. Here is my solution to the same ECB problem: void[] encrypt_ECB(void[] data, void[]to) in { assert(data.length > 0); assert(to is null || to.length >= data.length + pad_length(data)); } out(ciphertext) { assert(ciphertext.length >= data.length); assert(ciphertext.length <= data.length +b_size); assert(ciphertext.length % b_size == 0); body { ubyte pad = pad_length(data); size_t total = data.length + pad; if(to is null) to = new ubyte[total]; // copy and pad data to[0 .. data.length] = data; to[data.length .. total] = pad; assert(to.length % b_size == 0); for(size_t i=0; i < data.length; i += b_size) { encipher(output[i .. i+b_size]); } return to; } This is a member function of my BlockCipherAlg abstract class. Sub-classes of BlockCipherAlg implement encipher(void[]), allowing me to write one ECB, CBC, PCBC and other chaining method implementations for all block algorithms. If you're interested, I have a nearly complete version of my crypto library framework. -- ----------------------------------------------------- PGP public key ID: pub 2048R/2C19B7E6 2006-02-19 [expires: 2007-02-19] uid Matthew Wesley <mwesley acm.org> Find it at http://pgp.mit.edu -----------------------------------------------------
Jan 25 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Matthew Wesley wrote:
 Think of D arrays as:
 
 struct DArray {
 	type *ptr;
 	size_t length;
 }

Nitpick: the members are the other way around :p. (in DMD) Not that it usually matters, but this may come up when writing inline assembly or calling extern(C) functions. This is not in the spec though, so it's implementation-dependent. However, it's not likely to change in DMD until Walter finally gets sick of printf[1]... [1]: The current layout allows him to write 'printf("%.*s", string);' to print D strings.
Jan 25 2007
parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Frits van Bommel wrote:

 Nitpick: the members are the other way around :p. (in DMD)
 Not that it usually matters, but this may come up when writing inline 
 assembly or calling extern(C) functions.
 This is not in the spec though, so it's implementation-dependent.

If you're going to nitpick, then it's implemented as a ulong (32-bit length | 32-bit ptr) in DMD and as a struct in GDC... This makes a difference for return values. Or when debugging. And it definitely will later, when D supports 64-bit as well. But most of the time, you can just use .length and .ptr :-) --anders
Jan 25 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Anders F Björklund wrote:
 Frits van Bommel wrote:
 
 Nitpick: the members are the other way around :p. (in DMD)
 Not that it usually matters, but this may come up when writing inline 
 assembly or calling extern(C) functions.
 This is not in the spec though, so it's implementation-dependent.

If you're going to nitpick, then it's implemented as a ulong (32-bit length | 32-bit ptr) in DMD and as a struct in GDC... This makes a difference for return values. Or when debugging. And it definitely will later, when D supports 64-bit as well. But most of the time, you can just use .length and .ptr :-)

Well, AFAIK the only real difference between ulongs and 8-byte structs is how they're returned from extern(C) functions (and perhaps extern(Windows/Pascal) as well). The only reason I even *know* that is that several functions (e.g. _d_arrayappendT (previously _d_arrayappend) in Phobos) have their calling conventions all screwed up ;). They get parameters passed like a C function, but return an array like a D function would. This doesn't actually matter to the typical user, since they're only called internally by compiler-generated code that expects exactly that. So for every-day use, I'd say the struct is way easier to understand and correct enough :p.
Jan 25 2007