problem with reading file headers

Shurikn

Well-known member
Joined
Jul 14, 2004
Messages
60
i got 2 diferent problems, depending on what date im reading, when im reading a short my problem is that the bytes are inversed, the first 2 bytes in the file are FFD8 and when read the give me D8FF, since i read it in a short it gives me 55551 when it should give me 65496... i know this is probably stupid and everyone knew that byte were inversed or something... but how can I compare shorts if there dont have the value they are suposed to....

my second problem is when i read a string...
all my strings i read from the file are missing le last char
my string is suposed to give me "JFIF\0" and instead i get "JFIF", then I tough it was maybe just because of the null char so I checked elsewere in my code where Im suposed to get the value "RIFF" and get "RIF" instead...

anyone can help?
 
First off the bytes FF D8 equal the number 0xD8FF so Im not shore what your problem there is.

How are you reading the four CC in? Remeber that in .NET, Strings are unicode strings not a null terminated array of bytes like in C.
 
I read the header that way:

C#:
	[StructLayout(LayoutKind.Sequential)]
	public struct EnTeteJPG
	{
		public ushort SOI;
		public ushort JFIFMarker;
		public ushort length;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst=5)]
		public string identifier;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
		public byte[] version;
		public byte units;
		public short Xdensity;
        public short Ydensity;
        public byte Xthumbnail;// 0 = no thumbnail
		public byte Ythumbnail;// 0 = no thumbnail
	}

public bool LireFichier(string nomFichier)
		{
			byte[] data=new byte[Marshal.SizeOf(entete)];
			GCHandle handle;
			IntPtr ptr;

			System.IO.FileStream stream= new System.IO.FileStream(nomFichier,FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None);
			stream.Read(data,0,data.Length);
			stream.Close();

			handle=GCHandle.Alloc(data,GCHandleType.Pinned);
			ptr=handle.AddrOfPinnedObject();
			entete=(EnTeteJPG)Marshal.PtrToStructure(ptr,typeof(EnTeteJPG));
			handle.Free();

			this.nomFichier=nomFichier;
			if(entete.SOI!=0xD8FF)
			{
				return false;
			}
			if(entete.JFIFMarker!=0xE0FF)
			{
				return false;
			}

			if(entete.identifier!="JFIF\0")
			{
				return false;
			}
			return true;
		}
 
Try using LPStr instead of ByValTStr or you can set the CharSet of the StuctLayoutAttribute to Ansi.
 
Last edited by a moderator:
using LPStr instead of ByValTStr cause the program to an
An unhandled exception of type System.NullReferenceException occurred in mscorlib.dll

Additional information: Object reference not set to an instance of an object.

when the code reach

entete=(EnteteAvi)Marshal.PtrToStructure(ptr,typeof(EnteteAvi));

and the StructLayoutAttribute CharSet=CharSet.Ansi didnt change anythig, I still get 4 chars array instead of 5... Now I could probably change the
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=5)]
and put SizeConst=6 and id probably get my 5 chars, but then I would probably lose a byte, that is probably pretty usefull to the struct structure....
 
ill give you another code part to show you what i mean

C#:
	[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]
	public struct EnteteAvi
	{
		[MarshalAs(UnmanagedType.LPStr, SizeConst=4)]
		public string chunkId;
		public Int32 fileSize;
		[MarshalAs(UnmanagedType.LPStr, SizeConst=4)]
		public string fileType;
		[MarshalAs(UnmanagedType.LPStr, SizeConst=4)]
		public string subChunk1ID;
		public Int32 subChunk1Size;
		[MarshalAs(UnmanagedType.LPStr, SizeConst=4)]
		public string subChunk1Type;
		public Int32 cb;
		public Int32 MicroSecPerFrame;
		public Int32 MaxBytePerSec;
		public Int32 PaddingGranularity;
		public Int32 Flags;
		public Int32 TotalFrames;
		public Int32 InitialFrames;
		public Int32 Streams;
		public Int32 SuggestedBufferSize;
		public Int32 Width;
		public Int32 Height;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
		public Int32[] Reserved;
	}


		public bool LireFichier(string nomFichier)
		{
			byte[] data=new byte[Marshal.SizeOf(entete)];
			GCHandle handle;
			IntPtr ptr;

			System.IO.FileStream stream= new System.IO.FileStream(nomFichier,FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None);
			stream.Read(data,0,data.Length);
			stream.Close();

			handle=GCHandle.Alloc(data,GCHandleType.Pinned);
			ptr=handle.AddrOfPinnedObject();
			entete=(EnteteAvi)Marshal.PtrToStructure(ptr,typeof(EnteteAvi));
			handle.Free();


			this.nomFichier=nomFichier;

			if(entete.chunkId!="RIFF")
			{
				return false;
			}
			if(entete.fileType!="AVI ")
			{
				return false;
			}
			if(entete.subChunk1ID!="avih")
			{
				return false;
			}
			return true;
		}

as you see in there, im asking for 4 char in my struct, and I compare with RIFF entete.chunkId is returning "RIF" wich is lacking 1 char!
 
IngisKahn said:
You have to use ByValTStr on fixed length strings that are not null terminated.

sure but it was byvaltstr from the begining, i only tryed with that when you said that... but still Im missing a char.
 
ok, after searching like crazy I fond a way to do it... even if it may not be the best way its working!

first i had to change back my struct to make it use only byte array:
C#:
	[StructLayout(LayoutKind.Sequential,Pack=1,CharSet=CharSet.Ansi)]
	public struct EnteteAvi
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
		public byte[] chunkId;
		public Int32 fileSize;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
		public byte[] fileType;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
		public byte[] subChunk1ID;
		public Int32 subChunk1Size;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
		public byte[] subChunk1Type;
		public Int32 cb;
		public Int32 MicroSecPerFrame;
		public Int32 MaxBytePerSec;
		public Int32 PaddingGranularity;
		public Int32 Flags;
		public Int32 TotalFrames;
		public Int32 InitialFrames;
		public Int32 Streams;
		public Int32 SuggestedBufferSize;
		public Int32 Width;
		public Int32 Height;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
		public Int32[] Reserved;
	}

the writing in the strunct still goes well, the only other change is when I compare to what I need, I need to use:
C#:
if(System.Text.Encoding.ASCII.GetString(entete.chunkId,0,4)!="RIFF")
			{
				return false;
			}

and itS now working, it see my 4 char instead of magically losing the last one
 
Back
Top