private static Task <DbfHeader> BuildDbfHeaderData(IRandomAccessStream stream, Encoding encoding, CancellationTokenSource cancellationTokenSource) { var token = cancellationTokenSource.Token; var task = Task.Factory.StartNew(async() => { if (cancellationTokenSource.IsCancellationRequested) { return(null); } if (stream.Size < 32) { throw new NotSupportedException(InvalidFormat); } using (var dataStream = stream.CloneStream()) { byte[] header = new byte[32]; await dataStream.ReadAsync(header.AsBuffer(), 32u, InputStreamOptions.Partial); byte fileType = header[0]; if (!AllowedTypes.Contains(fileType)) { throw new NotSupportedException(InvalidFormat); } DbfHeader dbfHeader = new DbfHeader(); dbfHeader.RecordsCount = BitConverter.ToInt32(header, 4); dbfHeader.RecordsOffset = BitConverter.ToInt16(header, 8); dbfHeader.RecordLength = BitConverter.ToInt16(header, 10); if (encoding == null) { byte languageDriver = header[29]; encoding = DbfEncoding.GetEncoding(languageDriver); } dbfHeader.Encoding = encoding; // header is 32 bytes + n field descriptors * 32 bytes + carriage return byte (0x0D) int fieldDescriptorCount = (dbfHeader.RecordsOffset - 32 - 1) / 32; byte[] fieldDescriptor; DbfFieldInfo dbfField; for (int i = 0; i < fieldDescriptorCount; i++) { if (cancellationTokenSource.IsCancellationRequested) { return(null); } fieldDescriptor = new byte[32]; await dataStream.ReadAsync(fieldDescriptor.AsBuffer(), 32u, InputStreamOptions.Partial); dbfField = new DbfFieldInfo(); dbfField.Name = encoding.GetString(fieldDescriptor, 0, 11).Replace("\0", string.Empty); dbfField.NativeDbfType = (char)fieldDescriptor[11]; dbfField.Length = fieldDescriptor[16]; dbfField.DecimalCount = fieldDescriptor[17]; dbfHeader.Fields.Add(dbfField); } return(dbfHeader); } }, token).Unwrap(); return(task); }
private static object TransformDbfValue(DbfFieldInfo field, string fieldValue, IAttributeValueConverter valueConverter) { switch (field.NativeDbfType) { // Currency case 'Y': // Numeric case 'N': // Float case 'F': // Double case 'B': // NOTE: numeric overflow is physically stored as asterisks in the DBF file. fieldValue = fieldValue.TrimStart(' ', '*'); break; // Integer case 'I': // TODO: Handle integer overflow // NOTE: Integer fields cannot handle overflow as asterisks in DBF file because they are stored in binary format. // Overflow in integer field is represented by the lowest integer value -2**32. fieldValue = fieldValue.TrimStart(' '); break; // Date case 'D': if (string.IsNullOrEmpty(fieldValue.TrimEnd(' '))) { fieldValue = DateTime.MinValue.ToString(CultureInfo.InvariantCulture); } else { fieldValue = fieldValue.Substring(0, 4) + "-" + fieldValue.Substring(4, 2) + "-" + fieldValue.Substring(6, 2); } break; // DateTime case 'T': fieldValue = fieldValue.Substring(0, 4) + "-" + fieldValue.Substring(4, 2) + "-" + fieldValue.Substring(6, 2) + " " + fieldValue.Substring(8, 2) + ":" + fieldValue.Substring(10, 2) + ":" + fieldValue.Substring(12, 2); break; case 'L': if (fieldValue.ToUpper() == "T" || fieldValue.ToUpper() == "Y") { fieldValue = bool.TrueString; } else { fieldValue = bool.FalseString; } break; default: fieldValue = fieldValue.TrimEnd(' '); break; } object result = null; if (!string.IsNullOrEmpty(fieldValue)) { result = Convert.ChangeType(fieldValue, field.MappedType, CultureInfo.InvariantCulture); } // NOTE: Optionally allow the user to customize the field value / field value type. if (valueConverter != null) { result = valueConverter.Convert(result, field.Name, field.MappedType); } return(result); }