/// <summary> /// This method fills in the first 2 to 4 bytes of a <c>SECSItem</c>'s /// value (the <c>SECSItem</c>'s header) in its raw wire/transmission format. /// The first byte contains value of the item's format code and number of length /// bytes and the next 1 to 3 bytes contain the value of the item's length in bytes. /// <para> /// Make sure <c>buffer</c> is large enough!!! /// </para> /// </summary> /// <returns>The offset to where the payload data may loaded into the buffer.</returns> /// <param name="buffer">The buffer that will be used to contain an outgoing message item.</param> /// <param name="numberOfBytes">The number of bytes in the payload...get this right.</param> protected int PopulateSECSItemHeaderData(byte[] buffer, int numberOfBytes) { int offset = 0; buffer[0] = (byte)((SECSItemFormatCodeFunctions.GetNumberFromSECSItemFormatCode(formatCode) << 2) | outboundNumberOfLengthBytes.ValueOf()); byte[] outputLengthBytes = BitConverter.GetBytes(numberOfBytes); if (BitConverter.IsLittleEndian) { Array.Reverse(outputLengthBytes); } if (outboundNumberOfLengthBytes == SECSItemNumLengthBytes.ONE) { buffer [1] = outputLengthBytes [3]; offset = 2; } else if (outboundNumberOfLengthBytes == SECSItemNumLengthBytes.TWO) { buffer [1] = outputLengthBytes [2]; buffer [2] = outputLengthBytes [3]; offset = 3; } else if (outboundNumberOfLengthBytes == SECSItemNumLengthBytes.THREE) { buffer [1] = outputLengthBytes [1]; buffer [2] = outputLengthBytes [2]; buffer [3] = outputLengthBytes [3]; offset = 4; } else { Console.WriteLine("The case where outboundNumberOfLengthBytes is still in its NOT_INITIALIZED state should never happen."); } return(offset); }
/// <summary> /// Generates a <c>SECSItem</c> from data in "wire/transmission" format. /// </summary> /// <returns>The resulting <c>SECSItem</c>.</returns> /// <param name="data">An array of bytes that is in wire/transmission format.</param> /// <param name="offset">The byte offset into <c>data</c> where the data for /// a <c>SECSITEM</c> starts.</param> public static SECSItem GenerateSECSItem(byte[] data, int offset) { SECSItem result = null; SECSItemFormatCode formatCode = SECSItemFormatCodeFunctions.GetSECSItemFormatCodeFromNumber((byte)((data[offset] >> 2) & 0x0000003F)); int numberOfLengthBytes = (data[offset] & 0x03); int incomingDataLength = 0; switch (numberOfLengthBytes) { case 1: { byte[] temp = new byte[4]; temp[0] = 0; temp[1] = 0; temp[2] = 0; temp[3] = data[offset + 1]; if (BitConverter.IsLittleEndian) { Array.Reverse(temp); } incomingDataLength = BitConverter.ToInt32(temp, 0); break; } case 2: { byte[] temp = new byte[4]; temp[0] = 0; temp[1] = 0; temp[2] = data[offset + 1]; temp[3] = data[offset + 2]; if (BitConverter.IsLittleEndian) { Array.Reverse(temp); } incomingDataLength = BitConverter.ToInt32(temp, 0); break; } case 3: { byte[] temp = new byte[4]; temp[0] = 0; temp[1] = data[offset + 1]; temp[2] = data[offset + 2]; temp[3] = data[offset + 3]; if (BitConverter.IsLittleEndian) { Array.Reverse(temp); } incomingDataLength = BitConverter.ToInt32(temp, 0); break; } } switch (formatCode) { case SECSItemFormatCode.L: result = new ListSECSItem(data, offset); break; case SECSItemFormatCode.B: result = new BinarySECSItem(data, offset); break; case SECSItemFormatCode.BO: if (incomingDataLength == 1) { result = new BooleanSECSItem(data, offset); } else { result = new BooleanArraySECSItem(data, offset); } break; case SECSItemFormatCode.A: result = new ASCIISECSItem(data, offset); break; case SECSItemFormatCode.J8: break; case SECSItemFormatCode.C2: break; case SECSItemFormatCode.I8: if (incomingDataLength == 8) { result = new I8SECSItem(data, offset); } else { result = new I8ArraySECSItem(data, offset); } break; case SECSItemFormatCode.I1: if (incomingDataLength == 1) { result = new I1SECSItem(data, offset); } else { result = new I1ArraySECSItem(data, offset, 0); // Need to use this version because of method signature issues } break; case SECSItemFormatCode.I2: if (incomingDataLength == 2) { result = new I2SECSItem(data, offset); } else { result = new I2ArraySECSItem(data, offset); } break; case SECSItemFormatCode.I4: if (incomingDataLength == 4) { result = new I4SECSItem(data, offset); } else { result = new I4ArraySECSItem(data, offset); } break; case SECSItemFormatCode.F8: if (incomingDataLength == 8) { result = new F8SECSItem(data, offset); } else { result = new F8ArraySECSItem(data, offset); } break; case SECSItemFormatCode.F4: if (incomingDataLength == 4) { result = new F4SECSItem(data, offset); } else { result = new F4ArraySECSItem(data, offset); } break; case SECSItemFormatCode.U8: if (incomingDataLength == 8) { result = new U8SECSItem(data, offset); } else { result = new U8ArraySECSItem(data, offset); } break; case SECSItemFormatCode.U1: if (incomingDataLength == 1) { result = new U1SECSItem(data, offset); } else { result = new U1ArraySECSItem(data, offset, 0); // Remember to use the proper constructor for this case } break; case SECSItemFormatCode.U2: if (incomingDataLength == 2) { result = new U2SECSItem(data, offset); } else { result = new U2ArraySECSItem(data, offset); } break; case SECSItemFormatCode.U4: if (incomingDataLength == 4) { result = new U4SECSItem(data, offset); } else { result = new U4ArraySECSItem(data, offset); } break; case SECSItemFormatCode.UNDEFINED: break; case SECSItemFormatCode.HeaderOnly: break; default: break; } return(result); }
protected SECSItem(byte[] data, int itemOffset) { int incomingDataLength = 0; if (data.Length == 0) { formatCode = SECSItemFormatCode.HeaderOnly; inboundNumberOfLengthBytes = 0; data = null; return; } formatCode = SECSItemFormatCodeFunctions.getSECSItemFormatCodeFromNumber((byte)((data[itemOffset] >> 2) & 0x0000003F)); inboundNumberOfLengthBytes = (data[itemOffset] & 0x03); byte[] temp1 = new byte[4]; switch (inboundNumberOfLengthBytes) { case 1: { temp1[0] = 0; temp1[1] = 0; temp1[2] = 0; temp1[3] = data[itemOffset + 1]; break; } case 2: { temp1[0] = 0; temp1[1] = 0; temp1[2] = data[itemOffset + 1]; temp1[3] = data[itemOffset + 2]; break; } case 3: { temp1[0] = 0; temp1[1] = data[itemOffset + 1]; temp1[2] = data[itemOffset + 2]; temp1[3] = data[itemOffset + 3]; break; } } if (BitConverter.IsLittleEndian) { Array.Reverse(temp1); } incomingDataLength = BitConverter.ToInt32(temp1, 0); if (formatCode == SECSItemFormatCode.L) { numberOfElements = incomingDataLength; } else { lengthInBytes = incomingDataLength; } }
/// <summary> /// This is a base class constructor for a SECSItem. This form of the constructor /// is used when parsing wire/transmission format data and converting it into /// its "C# form". /// /// This constructor sets the following base class attributes from the provided data: /// <c>formatCode</c>, /// <c>inboundNumberOfLengthBytes</c>, /// <c>outboundNumberOfLengthBytes</c> /// <c>lengthInBytes</c> or if the <c>formatCode</c> is of type <c>L</c>(List) <c>lengthInBytes</c> /// will be the number of items in the list. /// /// The exception <c>ArgumentException</c> will be thrown in the following circumstances: /// the <c>data</c> argument is <c>null</c>, the <c>data</c> argument has a length of zero, or /// the number of length bytes parsed out is zero. /// /// In normal use the only time the <c>ArgumentException</c> /// exception should be caught is if you are reading data from a piece of /// equipment that does not properly speak SECS and you want to be able to /// recover from the error gracefully.Typically the ACM process will have /// detected this equipment and it will not be allowed into the factory in /// the first place. /// </summary> protected SECSItem(byte[] data, int itemOffset) { if (data == null) { throw new ArgumentNullException("\"data\" argument must not be null."); } if (data.Length < 2) { throw new ArgumentException("\"data\" argument must have a length >= 2."); } /* * if (data.Length == 0) * { * throw new ArgumentException ("The number of length bytes is not allowed to be ZERO."); * } */ formatCode = SECSItemFormatCodeFunctions.GetSECSItemFormatCodeFromNumber((byte)((data[itemOffset] >> 2) & 0x0000003F)); byte[] temp1 = new byte[4]; switch (data [itemOffset] & 0x03) { case 0: { throw new ArgumentException("The number of length bytes is not allowed to be ZERO."); } case 1: { inboundNumberOfLengthBytes = SECSItemNumLengthBytes.ONE; outboundNumberOfLengthBytes = inboundNumberOfLengthBytes; temp1[0] = 0; temp1[1] = 0; temp1[2] = 0; temp1[3] = data[itemOffset + 1]; break; } case 2: { inboundNumberOfLengthBytes = SECSItemNumLengthBytes.TWO; outboundNumberOfLengthBytes = inboundNumberOfLengthBytes; if (data.Length < 3) { throw new ArgumentException("With two length bytes the minimum length for the \"data\" argument is 3."); } temp1[0] = 0; temp1[1] = 0; temp1[2] = data[itemOffset + 1]; temp1[3] = data[itemOffset + 2]; break; } case 3: { inboundNumberOfLengthBytes = SECSItemNumLengthBytes.THREE; outboundNumberOfLengthBytes = inboundNumberOfLengthBytes; if (data.Length < 4) { throw new ArgumentException("With three length bytes the minimum length for the \"data\" argument is 4."); } temp1[0] = 0; temp1[1] = data[itemOffset + 1]; temp1[2] = data[itemOffset + 2]; temp1[3] = data[itemOffset + 3]; break; } } if (BitConverter.IsLittleEndian) { Array.Reverse(temp1); } lengthInBytes = BitConverter.ToInt32(temp1, 0); /* * if (formatCode == SECSItemFormatCode.L) * numberOfElements = incomingDataLength; * else * lengthInBytes = incomingDataLength; */ }