Beispiel #1
0
        private ContainerEntry FindContainerAtDepth(long position, int desiredDepth)
        {
            // Find the first container ending after position.
            ContainerEntry firstAfter      = _containerIndex.FirstEndingAfter(position);
            int            firstAfterDepth = _containerIndex.Depth(firstAfter);

            // Find the ancestor at the desired depth. If there is one, and it contains position, we can use it
            ContainerEntry firstAtDepth = AncestorAtDepth(firstAfter, firstAfterDepth, desiredDepth);

            if (firstAtDepth.Contains(position))
            {
                return(firstAtDepth);
            }

            // If nothing deep enough was indexed, we must find the nearest point of known depth and walk the BION
            long seekToPosition;
            int  seekToDepth;

            // The nearest point is...
            if (firstAfter.StartByteOffset < position)
            {
                // The start of the first container ending after position, if it starts before position
                seekToPosition = firstAfter.StartByteOffset;
                seekToDepth    = firstAfterDepth - 1;
            }
            else if (firstAfter.Index > 0)
            {
                // The end of the container before that, if it started after position
                ContainerEntry lastBefore = _containerIndex[firstAfter.Index - 1];
                seekToPosition = lastBefore.EndByteOffset;
                seekToDepth    = _containerIndex.Depth(lastBefore) - 1;
            }
            else
            {
                // The start of the document, if the first container was found
                seekToPosition = 0;
                seekToDepth    = 0;
            }

            // Seek to that position and read until we find a container at the right depth which contains position
            _bionReader.Seek(seekToPosition);
            long lastContainerStart = -1;
            long lastContainerEnd   = -1;

            while (_bionReader.BytesRead < position + 3)
            {
                _bionReader.Read();

                if (_bionReader.Depth + seekToDepth == desiredDepth)
                {
                    lastContainerStart = _bionReader.BytesRead - 1;
                    _bionReader.SkipRest();
                    lastContainerEnd = _bionReader.BytesRead;
                }
            }

            ContainerEntry found = new ContainerEntry(lastContainerStart, lastContainerEnd, -1);

            if (!found.Contains(position))
            {
                return(ContainerEntry.Empty);
            }

            return(found);
        }