Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Accessing an array in Memo field
Message
De
17/08/2012 12:35:53
 
 
À
13/08/2012 08:08:07
Information générale
Forum:
Visual FoxPro
Catégorie:
Base de données, Tables, Vues, Index et syntaxe SQL
Divers
Thread ID:
01550185
Message ID:
01550645
Vues:
49
Hi,
Been away for a few days so only just saw this.
Thank you very much, I'll dig into it next week.....

>>Don't think I'll get a chance to pursue this until after next week but I may take you up on your offer of extra help if I'm stuck....
>
>Ok, here it comes
>
>(1) Sample input and output
>
>(2) Explanation, design, choices
>
>(3) Full code at the end
>
>
>
>
>(1) Sample input and output
>
>vfp code
>
>	local abc
>	
>	abc=repl('x', 256)
>	abcshort = '1234546'
>	a2345678900=.f.
>	a2345678901=.t.
>	a2345678902=804.3
>	a2345678903={^2012/01/01}
>	a2345678904={^2012/01/01 01:02:03}
>	a2345678905=$-1234.5678
>	a2345678906 = null
>	
>	
>	dime aa[2]
>	aa[1] = 1
>	aa[2] = 2
>
>	dime LongNameArray[4, 3]
>	local i, j
>	for i = 1 to alen(LongNameArray, 1)
>		for j = 1 to alen(LongNameArray, 2)
>			LongNameArray[i, j] = i + j/100
>		endfor
>	endfor
>	
>	save to 'd:\tmp\1.txt'
>
>
>Code to produce the output below
>
>	class VfpVariableTest
>	{
>		public static void Main()
>		{
>			byte[] bytes = File.ReadAllBytes(@"d:\tmp\1.txt");
>
>			Dictionary<String, VfpVariable> dict = VfpMemoryRestore.GetVariables(bytes, false);
>
>			foreach (var v in dict)
>			{
>				Console.Write("Name: {0} Type: {1}", v.Value.Name, v.Value.Type);
>
>				if (v.Value.Type == VfpValueType.Array)
>				{
>					if (v.Value.Value is VfpVariable[])
>					{	// one dimensional array
>						VfpVariable[] vfpArray = v.Value.Value as VfpVariable[];
>						Console.WriteLine();
>						for (int i = 0; i < vfpArray.Length; i++)
>							Console.WriteLine("{0}[{1}] = {2}", vfpArray[i].Name, i, vfpArray[i].Value);
>
>					}
>					else if (v.Value.Value is VfpVariable[,])
>					{	// two dimensional array
>						VfpVariable[,] vfpArray = v.Value.Value as VfpVariable[,];
>						Console.WriteLine();
>						for (int i = 0; i <= vfpArray.GetUpperBound(0); i++)
>							for (int j = 0; j <= vfpArray.GetUpperBound(1); j++)
>								Console.WriteLine("{0}[{1},{2}] = {3}", vfpArray[i, j].Name, i, j, vfpArray[i, j].Value);
>					}
>				}
>				else if (v.Value.Value == null)
>				{
>					Console.WriteLine(" Value: {0}", "null");
>				}
>				else if (v.Value.Type == VfpValueType.Char)
>				{ // treat as chars here
>					byte[] s = (byte[])v.Value.Value;
>
>					Console.WriteLine(" Value: {0}", Encoding.Default.GetString(s, 0, s.Length));
>				}
>				else // no array
>				{
>					Console.WriteLine(" Value: {0}", v.Value.Value);
>				}
>			}
>			Console.ReadLine();
>		}
>	}
>
>output
>
>Name: ABC Type: Char Value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>Name: A2345678901 Type: Logical Value: True
>Name: A2345678902 Type: Numeric Value: 804.3
>Name: A2345678903 Type: Date Value: 01/01/2012 00:00:00
>Name: A2345678904 Type: DateTime Value: 01/01/2012 01:02:03
>Name: I Type: Numeric Value: 5
>Name: AA Type: Array
>AA[0] = 1
>AA[1] = 2
>Name: J Type: Numeric Value: 4
>Name: ABCSHORT Type: Char Value: 1234546
>Name: A2345678905 Type: Currency Value: -1234.5678
>Name: A2345678900 Type: Logical Value: False
>Name: A2345678906 Type: Logical Value: null
>Name: LONGNAMEARRAY Type: Array
>LONGNAMEARRAY[0,0] = 1.01
>LONGNAMEARRAY[0,1] = 1.02
>LONGNAMEARRAY[0,2] = 1.03
>LONGNAMEARRAY[1,0] = 2.01
>LONGNAMEARRAY[1,1] = 2.02
>LONGNAMEARRAY[1,2] = 2.03
>LONGNAMEARRAY[2,0] = 3.01
>LONGNAMEARRAY[2,1] = 3.02
>LONGNAMEARRAY[2,2] = 3.03
>LONGNAMEARRAY[3,0] = 4.01
>LONGNAMEARRAY[3,1] = 4.02
>LONGNAMEARRAY[3,2] = 4.03
>
>
>
>(2) Explanation, design, choices
>
>
>We start off with a class
>
>class VfpVariable
>	{
>		public readonly string Name;
>		public VfpValueType Type { get; private set; }
>		public VfpVariableScope Scope { get; private set; }
>
>		private object _Value;
>		public object Value { get; private set;}
>	// rest of code is at the end
>
>	}
>
>
>VfpValueType is an enum
>You'll see that the vfp string is mapped to a byte array - since there is no way of knowing whether the string contains bytes or characters
>
>The vfp array is implemented as a one or two dimensional C# array of VfpVariable[]
>
>	enum VfpValueType
>	{
>		Logical = 0,	// bool
>		Numeric,		// double
>		Currency,		// decimal
>		Char,			// byte[]
>		Date,			// datetime
>		DateTime,		// datetime
>		Array,			// VfpVariable[] or VfpVariable[ , ]
>		Object			// not implemented 
>	}
>
>
>The scope is an enum - but I doubt you will care
>
>	enum VfpVariableScope
>	{
>		Public,
>		Private,
>		Local
>	}
>
>
>The Value is implemented as an object - could have subclassed - but I found it too much of a burden
>So casts ( after testing whether the Value == null) are needed
>
>There is another class which collects the variables from a byte array and returns a dictionary of variables
>
>You put the contents of the file or memo field into a byte[]. You need to tell whether the source was from a memo or not since memo fields contain two extra bytes at the beginning
>
>static class VfpMemoryRestore
>	{
>                            // rest of the code at the end
>
>		internal static Dictionary<String, VfpVariable> GetVariables(byte[] buffer, bool isMemoField)
>		{  / code at the end
>		}
>	}
>
>
>
>(3) Full code at the end
>
>
>
>	enum VfpValueType
>	{
>		Logical = 0,	// bool
>		Numeric,		// double
>		Currency,		// decimal
>		Char,			// byte[]
>		Date,			// datetime
>		DateTime,		// datetime
>		Array,			// VfpVariable[] or VfpVariable[ , ]
>		Object			// not implemented 
>	}
>
>
>
>	enum VfpVariableScope
>	{
>		Public,
>		Private,
>		Local
>	}
>
>
>
>class VfpVariable
>	{
>		public readonly string Name;
>		public VfpValueType Type { get; private set; }
>		public VfpVariableScope Scope { get; private set; }
>
>		private object _Value;
>		public object Value
>		{
>			get
>			{
>				return _Value;
>			}
>			private set
>			{
>
>				if (value == null)
>					; // ok
>				else switch(Type)
>				{
>					case VfpValueType.Array:
>						if( !(value is VfpVariable[]) && !(value is VfpVariable[,]))
>							throw new ArgumentException("Wrong value for type");
>						break;
>
>					case VfpValueType.Char:
>						if( !(value is byte[]) )
>							throw new ArgumentException("Wrong value for type");
>						break;
>
>					case VfpValueType.Currency:
>						if( ! (value is decimal) )
>							throw new ArgumentException("Wrong value for type");
>						break;
>
>					case VfpValueType.Date:
>
>						if( !(value is DateTime) || ((DateTime)value).Date != (DateTime)value)
>							throw new ArgumentException("Wrong value for type");
>						break;
>					case VfpValueType.DateTime:
>						if( !(value is DateTime) )
>							throw new ArgumentException("Wrong value for type");
>						break;
>					case VfpValueType.Logical:
>						if( !(value is bool) )
>							throw new ArgumentException("Wrong value for type");
>						break;
>					case VfpValueType.Numeric:
>						if (!(value is int) && !(value is uint) && !(value is Double))
>							throw new ArgumentException("Wrong value for type");
>						break;
>
>					case VfpValueType.Object:
>						throw new NotImplementedException("Object type");
>						break;
>					default:
>						throw new NotImplementedException("Type");
>
>				}
>				
>				_Value = value;
>			}
>		}
>		//______________________________________________________________________
>		public VfpVariable(string name, VfpValueType type, object value, VfpVariableScope scope)
>		{
>			CheckName(name);
>			Name = name;
>			Type = type;  // type must be assiged before value (see set accessor of Value)
>			Value = value;
>			Scope = scope;
>		}
>		//______________________________________________________________________
>		// other checks to add 
>		private void CheckName(string name)
>		{
>			if (String.IsNullOrWhiteSpace(name))
>				throw new ArgumentException("Invalid name");
>		}
>		//______________________________________________________________________
>	}
>
>
>
>	static class VfpMemoryRestore
>	{
>		/*
>		 * 	00-10	char[11] upper(name) '\0 terminated
>		*	11-11	char Type, if lower(): extended name, except 0 (Null)
>		*	12-15 	length strings > 254 ( type H, includes \0)
>		*	16-16	Length for
>		 *				- char <= 255 chars ( includes \0' )
>		 *				
>		 *			
>		 *			not for
>		 *				- logical
>		 *				- numeric
>		 *				- date
>		 *				- dateTime
>		 *				- null - not always
>		 *				
>		 *					
>		 *			
>		*	17-17	precision for numeric
>		*	20-23 ??
>		*	24-24	0x00 = Private/public, 0x01 = local
>		*	25-25	constant : 0x03
>		*	26-31 ?
>		&& case extended name
>		*	32-33	len Name if extended name
>		*	34-...	name
>		*	..-..	Value
>		&& otherwise
>		*	32 -	Value  (or type if 11-11 == '0'
>		*
>		 */
>		private const int EndOfFileMarker = 0x1a;
>		private const int VariableTypeOffset = 11;
>		private const int ValueOffset = 0x20;
>		private const int ScopeOffset = 24;
>		private const int ContentLengthOffset = 16;
>		private const int LongStringContentLengthOffset = 12;
>
>		//______________________________________________________________________
>		internal static Dictionary<String, VfpVariable> GetVariables(byte[] buffer, bool isMemoField)
>		{
>			Dictionary<String, VfpVariable> dict = new Dictionary<string, VfpVariable>();
>
>			int offset = isMemoField ? 2 : 0;
>
>			VfpVariable v;
>
>			while (offset < buffer.Length)
>			{
>				if (offset == buffer.Length - 1 && buffer[offset] == EndOfFileMarker)
>					break;
>
>				v = GetVariable(buffer, ref offset);
>				dict.Add(v.Name, v);
>				}
>
>			return dict;
>
>		}
>		//______________________________________________________________________
>		private static VfpVariable GetVariable(byte[] buffer, ref int offset)
>		{
>			int valueOffset;
>
>			// Name
>			// valueOffset depends on the length of the name
>			string name = GetName(buffer, offset, out valueOffset);
>
>			// Scope
>			VfpVariableScope scope = GetScope(buffer[offset + ScopeOffset]);
>			
>
>			//Type and value
>			VfpValueType type;
>
>			object value;
>			int newOffset;
>			byte[] x; // for strings
>			int contentLength;
>
>			byte varType = buffer[offset + VariableTypeOffset];
>
>			if (varType == (byte)'0')
>			{
>				type = GetVarType(buffer[offset + valueOffset]);
>				contentLength = 1;
>				value = null;
>				newOffset = offset + valueOffset + contentLength;
>			}
>			else
>			{
>				type = GetVarType(varType);
>
>				switch (type)
>				{
>					case VfpValueType.Char:
>						if (varType == (byte)'C' || varType == (byte)'c')
>						{
>							contentLength = buffer[offset + ContentLengthOffset];
>							x = new byte[contentLength - 1];
>							Array.Copy(buffer, offset + valueOffset, x, 0, contentLength - 1);
>							value = x;
>
>						}
>						else
>						{
>							contentLength = BitConverter.ToInt32(buffer, offset + LongStringContentLengthOffset);
>							x = new byte[contentLength - 1];
>							Array.Copy(buffer, offset + valueOffset, x, 0, contentLength - 1);
>							value = x;
>						}
>						newOffset = offset + valueOffset + contentLength;
>						break;
>
>					case VfpValueType.Logical:
>						contentLength = 1;
>						value = (buffer[offset +valueOffset] != 0x00);
>						newOffset = offset + valueOffset + contentLength;
>						break;
>
>					case VfpValueType.Numeric:
>						contentLength = 8;
>						value = BitConverter.ToDouble(buffer, offset + valueOffset);
>						newOffset = offset + valueOffset + contentLength;
>						break;
>
>					case VfpValueType.Date :
>					case VfpValueType.DateTime:
>						contentLength = 8;
>						double d = BitConverter.ToDouble(buffer, offset + valueOffset);
>						if (d == 0.0)
>							value = null;
>						else
>						{
>							if (type == VfpValueType.Date)
>								d = d < 0.0 ? Math.Ceiling(d) : Math.Floor(d);
>							value = DateTime.FromOADate(d - 2415019.0); //2415019 is julian day of 1899 dec 30 
>						}
>						newOffset = offset + valueOffset + contentLength;
>						break;
>
>					case VfpValueType.Currency:
>						contentLength = 8;
>						Int64 v64 = BitConverter.ToInt64(buffer, offset + valueOffset);
>						value = (decimal)v64 / 10000.0m;
>						newOffset = offset + valueOffset + contentLength;
>						break;
>
>					case VfpValueType.Array:
>						contentLength = 4; // for rowCount and columnCount
>						uint rowCount = BitConverter.ToUInt16(buffer, offset + valueOffset);
>						uint colCount = BitConverter.ToUInt16(buffer, offset + valueOffset + sizeof(UInt16));
>						newOffset = offset + valueOffset + contentLength;
>
>						if (colCount == 0)
>						{	// one dimensional array
>							VfpVariable[] array = new VfpVariable[rowCount];
>							for (int i = 0; i < rowCount; i++)
>								array[i] =  GetVariable(buffer, ref newOffset);
>			
>							value = array;
>						}
>						else
>						{	// two dimensional array
>							VfpVariable[,] array = new VfpVariable[rowCount, colCount];
>							for (int i = 0; i < rowCount; i++)
>								for( int j = 0; j < colCount; j++)
>									array[i, j] = GetVariable(buffer, ref newOffset);
>
>							value = array;
>						}
>						break;
>
>					default:
>						throw new NotImplementedException(String.Format("Program error: type {0}", type));
>				}
>			}
>			
>			VfpVariable v = new VfpVariable(name, type, value, scope);
>			offset = newOffset;
>			return v;
>
>		}
>		//______________________________________________________________________
>		private static VfpValueType GetVarType(byte varType)
>		{
>			VfpValueType type;
>
>			switch (varType)
>			{
>				case (byte)'C':
>				case (byte)'c':
>				case (byte)'H':
>				case (byte)'h':
>					type = VfpValueType.Char;
>					break;
>
>				case (byte)'L':
>				case (byte)'l':
>					type = VfpValueType.Logical;
>					break;
>
>				case (byte)'N':
>				case (byte)'n':
>					type = VfpValueType.Numeric;
>					break;
>
>				case (byte)'D':
>				case (byte)'d':
>					type = VfpValueType.Date;
>					break;
>
>				case (byte)'T':
>				case (byte)'t':
>					type = VfpValueType.DateTime;
>					break;
>
>				case (byte)'Y':
>				case (byte)'y':
>					type = VfpValueType.Currency;
>					break;
>
>				case (byte)'A':
>				case (byte)'a':
>					type = VfpValueType.Array;
>					break;
>
>				default:
>					throw new NotImplementedException(String.Format("Program error: GetVarType {0}", varType.ToString()));
>			}
>			return type;
>		}
>		//______________________________________________________________________
>		private static string GetName(byte[] buffer, int offset, out int valueOffset)
>		{
>			int nameOffset, count;
>
>			if (buffer[offset] != 0) //short name, null terminated 
>			{	// name <= 10 bytes
>				valueOffset = ValueOffset;
>				nameOffset = offset;
>				count = Array.IndexOf<byte>(buffer, 0, nameOffset) - nameOffset;
>				if (count < 0 || count > 10)
>					throw new Exception("Name inconsistency");
>
>			}
>			else
>			{
>				count = BitConverter.ToInt16(buffer, offset + ValueOffset);
>				valueOffset = ValueOffset + count + 2;
>				nameOffset = offset + ValueOffset + 2;
>			}
>			string name = Encoding.Default.GetString(buffer, nameOffset, count);
>
>			return name;
>		}
>		//______________________________________________________________________
>		private static VfpVariableScope GetScope(byte b)
>		{
>			VfpVariableScope scope;
>			switch (b)
>			{
>				case 0x00:
>					scope = VfpVariableScope.Private;
>					break;
>
>				case 0x01:
>					scope = VfpVariableScope.Local;
>					break;
>
>				default:
>					throw new NotImplementedException(String.Format("Program error: Scope {0}", b.ToString()));
>			}
>			return scope;
>		}
>		//______________________________________________________________________
>	}
>
Précédent
Répondre
Fil
Voir

Click here to load this message in the networking platform