private Task <ShapefileRecordInfoCollection> BuildShapeIndexData(IRandomAccessStream stream, CancellationTokenSource cancellationTokenSource)
        {
            var token = cancellationTokenSource.Token;

            var task = Task.Factory.StartNew(
                async() =>
            {
                if (cancellationTokenSource.IsCancellationRequested)
                {
                    return(null);
                }

                using (var shapeStream = stream.CloneStream())
                {
                    int offset = 36;
                    shapeStream.Seek((ulong)offset);

                    byte[] boundingBox = new byte[32];
                    await shapeStream.ReadAsync(boundingBox.AsBuffer(), 32u, InputStreamOptions.Partial);

                    var recordInfos          = new ShapefileRecordInfoCollection();
                    recordInfos.BoundingRect = GetBoundingRect(boundingBox, this.CoordinateValueConverter);

                    offset = 100;
                    shapeStream.Seek((ulong)offset);

                    while (shapeStream.Position < shapeStream.Size)
                    {
                        if (cancellationTokenSource.IsCancellationRequested)
                        {
                            return(null);
                        }

                        byte[] recordHeader = new byte[8];
                        await shapeStream.ReadAsync(recordHeader.AsBuffer(), 8u, InputStreamOptions.Partial);

                        // The content length for a record is the length of the record contents section measured in 16-bit words.
                        int contentLength = ToInt32BigEndian(recordHeader, 4) * 2;

                        offset += 8;
                        recordInfos.Add(new ShapefileRecordInfo()
                        {
                            ContentOffset = offset, ContentLength = contentLength
                        });

                        offset += contentLength;
                        shapeStream.Seek((ulong)offset);
                    }

                    return(recordInfos);
                }
            },
                token).Unwrap();

            return(task);
        }
        private MapShapeModelCollection ProcessItems(IRandomAccessStream shapeStream, ShapefileRecordInfoCollection recordInfos, CancellationTokenSource cancellationTokenSource)
        {
            if (cancellationTokenSource.IsCancellationRequested)
            {
                return(null);
            }

            int itemCount = recordInfos.Count;
            int maxDegreeOfParallelism = Environment.ProcessorCount;

            if (itemCount < maxDegreeOfParallelism)
            {
                maxDegreeOfParallelism = itemCount;
            }

            int remainder  = itemCount % maxDegreeOfParallelism;
            int multiplier = (itemCount / maxDegreeOfParallelism) + (remainder > 0 ? 1 : 0);

            var token = cancellationTokenSource.Token;
            List <Task <MapShapeModelCollection> > tasks = new List <Task <MapShapeModelCollection> >();

            for (int i = 0; i < maxDegreeOfParallelism; i++)
            {
                int start = i * multiplier;
                int end   = Math.Min((i + 1) * multiplier, itemCount);

                ParseShapeTaskState taskState = new ParseShapeTaskState()
                {
                    Start   = start,
                    End     = end,
                    Records = recordInfos,
                    Stream  = shapeStream,
                    CancellationTokenSource = cancellationTokenSource,
                    CoordinateConverter     = this.CoordinateValueConverter
                };

                var task = Task.Factory.StartNew <Task <MapShapeModelCollection> >(ParseShapes, taskState, token, TaskCreationOptions.AttachedToParent, TaskScheduler.Current).Unwrap();

                tasks.Add(task);
            }

            Task.WaitAll(tasks.ToArray());

            MapShapeModelCollection models = tasks[0].Result;

            for (int i = 1; i < maxDegreeOfParallelism; i++)
            {
                var modelsToMerge = tasks[i].Result;
                if (modelsToMerge == null)
                {
                    continue;
                }

                foreach (var model in modelsToMerge)
                {
                    models.Add(model);
                }
            }

            models.BoundingRect = recordInfos.BoundingRect;

            return(models);
        }