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);
        }