using System; using System.Collections.Generic; using System.Text; namespace Pack89KData { public class ApplicationField { #region Declarations private ushort _fieldId; private byte[] _contents; private List _fields; #endregion #region Public Properties public ushort FieldId { get { return _fieldId; } } public List Fields { get { return _fields; } } public byte[] Contents { get { return _contents; } set { _contents = value; } } public bool IsContainerField { get { bool ret = false; switch (_fieldId & 0xF0F0) { case 0x8000: { ret = true; break; } default: { break; } } return ret; } } public int SizeLength { get { int ret = 0; switch (_fieldId & 0xF0F0) { //Assume these field IDs have a "long" size case 0x8000: case 0x8070: { ret += 4; break; } default: { if (_contents.Length >= 0xFFFF) { ret += 4; } else if (_contents.Length >= 0xFF) { ret += 2; } else if (_contents.Length >= 0x0D) { ret += 1; } break; } } return ret; } } public int HeaderSize { get { return SizeLength + 2; } } public int Count { get { int ret = HeaderSize; if (_fields.Count > 0) { for (int i = 0; i < _fields.Count; i++) { ret += _fields[i].Count; } } else { ret += _contents.Length; } return ret; } } #endregion #region Constructors/Teardown public ApplicationField(ushort fieldId, byte[] contents) { _fieldId = fieldId; _contents = contents; _fields = new List(); if (IsContainerField) _fields = ApplicationField.ParseContents(contents); } #endregion #region Public Methods public static List ParseContents(byte[] data) { List ret = new List(); ushort fieldId; byte[] contents; int offset = 0; while (offset < data.Length) { fieldId = (ushort)((data[offset] << 8) | (data[offset+1] & 0xFF)); offset += 2; int size = fieldId & 0x000F; switch (size) { case 0x0D: { size = data[offset]; offset++; break; } case 0x0E: { size = (ushort)((data[offset] << 8) | (data[offset+1] & 0xFF)); offset += 2; break; } case 0x0F: { size = (ushort)((data[offset] << 24) | (data[offset+1] << 16) | (data[offset+2] << 8) | (data[offset+3] & 0xFF)); offset += 4; break; } default: { break; } } contents = new byte[size]; for (int i = 0; i < size; i++) contents[i] = data[offset+i]; offset += size; ret.Add(new ApplicationField(fieldId, contents)); } return ret; } public byte[] ToByteArray() { var ret = new List(); if (_fields.Count > 0) { var temp = new List(); for (int i = 0; i < _fields.Count; i++) { temp.AddRange(_fields[i].ToByteArray()); } ret.AddRange(_GetFieldHeader(temp.Count)); ret.AddRange(temp); } else { ret.AddRange(_GetFieldHeader(_contents.Length)); ret.AddRange(_contents); } return ret.ToArray(); } private byte[] _GetFieldHeader(int length) { var ret = new List(); int sizePrefix; switch (SizeLength) { case 0x04: { sizePrefix = 0x0F; break; } case 0x02: { sizePrefix = 0x0E; break; } case 0x01: { sizePrefix = 0x0D; break; } default: { sizePrefix = length; break; } } ret.Add((byte)(_fieldId >> 8)); ret.Add((byte)((_fieldId & 0xFF) | (sizePrefix & 0x0F))); int size = length; switch (SizeLength) { case 0x04: { ret.Add((byte)((size >> 24) & 0xFF)); ret.Add((byte)((size >> 16) & 0xFF)); ret.Add((byte)((size >> 8) & 0xFF)); ret.Add((byte)(size & 0xFF)); break; } case 0x02: { ret.Add((byte)((size >> 8) & 0xFF)); ret.Add((byte)(size & 0xFF)); break; } case 0x01: { ret.Add((byte)(size & 0xFF)); break; } default: { break; } } return ret.ToArray(); } #endregion } }