www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Endianness and Tango

reply Mael <mael.primet gmail.com> writes:
Content-Type: text/plain

Hello,

this is a noob question, but I'm learning Tango/D, and I'm a bit lost with all
the possibilities I'm offered to read/write a file. The format of the file is a
bit fuzzy, since it has, say, a BigEndian part followed by a LittleEndian part,
so I must switch protocols in the middle of the reading and writing. What
should be the
best approach ?

For now, I do :

read( char[] filename )
{
  auto file = new FileConduit( filename ) ;
  version( LittleEndian ) auto inp = new EndianInput!( short )( file );
  version( BigEndian ) auto inp = file ;
  read some stuf... ;

  version( LittleEndian ) auto inp2 = file ;
  version( BigEndian ) auto inp2 = new EndianInput!( float )( file );
  read some stuff... ;
}

and same for writing (with FileConduit.WriteCreate, and EndianOutput!( short ))

the reading seems to work fine, but the writing does not work (looks like when
I do the second outpf = file ; it starts writing again from the beginning of
the file rather than where I left it before. Plus the code looks ugly, to me,
and I don't like having to specify the EndianInput!(short) thing, I'd prefer to
tell at the point where I read something, what is the value I will be reading.
Someone has a clue ?

I attached my FImage.d  library file


}
May 28 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Mael" wrote
 Hello,

 this is a noob question, but I'm learning Tango/D, and I'm a bit lost with 
 all the possibilities I'm offered to read/write a file. The format of the 
 file is a bit fuzzy, since it has, say, a BigEndian part followed by a 
 LittleEndian part, so I must switch protocols in the middle of the reading 
 and writing. What should be the
 best approach ?

 For now, I do :

 read( char[] filename )
 {
  auto file = new FileConduit( filename ) ;
  version( LittleEndian ) auto inp = new EndianInput!( short )( file );
  version( BigEndian ) auto inp = file ;
  read some stuf... ;

  version( LittleEndian ) auto inp2 = file ;
  version( BigEndian ) auto inp2 = new EndianInput!( float )( file );
  read some stuff... ;
 }

 and same for writing (with FileConduit.WriteCreate, and EndianOutput!( 
 short ))

 the reading seems to work fine, but the writing does not work (looks like 
 when I do the second outpf = file ; it starts writing again from the 
 beginning of the file rather than where I left it before. Plus the code 
 looks ugly, to me, and I don't like having to specify the 
 EndianInput!(short) thing, I'd prefer to tell at the point where I read 
 something, what is the value I will be reading. Someone has a clue ?

You should probably use the Protocol classes as they allow reading/writing different types from/to a stream without re-opening. i.e.: // the second argument says don't expect a length argument for arrays. version( LittleEndian ) auto proto = new EndianProtocol( file, false ) ; version( BigEndian ) auto proto = new NativeProtocol( file, false); auto inp = new Reader(proto); short[4] res; auto _res = res[]; inp.get( _res ); if( res[0] != 0x4952 ) throw new Exception( "Invalid RIM file" ); int length_comment = res[1] ; this.width = res[2] ; this.height = res[3] ; assert( width >= 0 && height >= 0 ); int length_header = base_length_header + length_comment ; file.seek( length_header ); inp.buffer.clear(); // flush all content out of the buffer this.data = new float[width*height] ; inp.read( data ); Note: didn't compile this or test it :) -Steve
May 28 2008
parent reply Mael <mael.primet gmail.com> writes:
Okay thanks,

can you just explain your _res trick ? Why does calling the get method with res
doesn't work and says "cast(short[])res is not an lvalue" ?
 
May 29 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Mael" wrote
 Okay thanks,

 can you just explain your _res trick ? Why does calling the get method 
 with res doesn't work and says "cast(short[])res is not an lvalue" ?

_res is an array slice, res is a static array. Under the hood of the compiler, these are viewed as totally separate types. In fact, two static arrays of different size are viewed as different types. However, one can implicitly cast a static array to an array slice, which is what the function is expecting. However, whenever you cast, you are creating a temporary variable, which cannot be an lvalue (a value that can be assigned to). A ref parameter must take an lvalue because it must be able to write to it. Because Reader uses ref as a parameter for its array, you must pass it a true lvalue, which is what _res is. It would be impossible for Reader to accept ref parameters to all sizes of static arrays, since they are all considered different types, and I don't even know that you can ref a static array, so you must do this trick. Very kludgy, but it works :) Hopefully at some point in the future, D will be able to remedy this. -Steve
May 29 2008
parent Mael <mael.primet gmail.com> writes:
Okay, sure, static arrays aren't represented with a length + ptr, I don't know
why I assumed this.
May 29 2008