private VltBlockContainer ReadBlock(BinaryReader reader) { if (reader.BaseStream.Position == reader.BaseStream.Length) { return(null); } var block = new VltBlock { Position = reader.BaseStream.Position, Type = (VltMarker)reader.ReadInt32(), BlockLength = reader.ReadInt32(), }; if (!block.IsBlank()) { var vltType = block.Type; VltBlockContainer bc; switch (vltType) { case VltMarker.VltMagic: bc = new HeaderBlock(); break; case VltMarker.TableStart: bc = new TableStartBlock(); break; case VltMarker.TableEnd: bc = new TableEndBlock(); break; default: bc = new PlaceholderBlock(); break; } bc.Block = block; bc.Read(reader); block.SeekToNextBlock(reader.BaseStream); return(bc); } return(null); }
/// <summary> /// Ensure that the given range of placeholders is granular. /// </summary> /// <param name="id">Start of the range, measured in granular placeholders</param> /// <param name="size">Size of the range, measured in granular placeholders</param> /// <param name="splitPlaceholderCallback">Callback function to run when splitting placeholders, calls with (start, middle)</param> public void EnsurePlaceholders(ulong id, ulong size, Action <ulong, ulong> splitPlaceholderCallback) { // Search 1 before and after the placeholders, as we may need to expand/join granular regions surrounding the requested area. ulong endId = id + size; ulong searchStartId = id == 0 ? 0 : (id - 1); int blockCount = _placeholders.FindOverlapsNonOverlapping(searchStartId, (endId - searchStartId) + 1, ref _foundBlocks); PlaceholderBlock first = _foundBlocks[0]; PlaceholderBlock last = _foundBlocks[blockCount - 1]; bool overlapStart = first.EndAddress >= id && id != 0; bool overlapEnd = last.Address <= endId; for (int i = 0; i < blockCount; i++) { // Go through all non-granular blocks in the range and create placeholders. PlaceholderBlock block = _foundBlocks[i]; if (block.Address <= id && block.EndAddress >= endId && block.IsGranular) { return; // The region we're searching for is already granular. } if (!block.IsGranular) { ulong placeholderStart = Math.Max(block.Address, id); ulong placeholderEnd = Math.Min(block.EndAddress - 1, endId); if (placeholderStart != block.Address && placeholderStart != block.EndAddress) { splitPlaceholderCallback(block.Address, placeholderStart - block.Address); } for (ulong j = placeholderStart; j < placeholderEnd; j++) { splitPlaceholderCallback(j, 1); } } if (!((block == first && overlapStart) || (block == last && overlapEnd))) { // Remove blocks that will be replaced _placeholders.Remove(block); } } if (overlapEnd) { if (!(first == last && overlapStart)) { _placeholders.Remove(last); } if (last.IsGranular) { endId = last.EndAddress; } else if (last.EndAddress != endId) { _placeholders.Add(new PlaceholderBlock(endId, last.EndAddress - endId, false)); } } if (overlapStart && first.IsGranular) { first.ExtendTo(endId); } else { if (overlapStart) { first.ExtendTo(id); } _placeholders.Add(new PlaceholderBlock(id, endId - id, true)); } ValidateList(); }
/// <summary> /// Coalesces placeholders in a given region, as they are not being used. /// This assumes that the region only contains placeholders - all views and allocations must have been replaced with placeholders. /// </summary> /// <param name="id">Start of the range, measured in granular placeholders</param> /// <param name="size">Size of the range, measured in granular placeholders</param> /// <param name="coalescePlaceholderCallback">Callback function to run when coalescing two placeholders, calls with (start, end)</param> public void RemovePlaceholders(ulong id, ulong size, Action <ulong, ulong> coalescePlaceholderCallback) { ulong endId = id + size; int blockCount = _placeholders.FindOverlapsNonOverlapping(id, size, ref _foundBlocks); PlaceholderBlock first = _foundBlocks[0]; PlaceholderBlock last = _foundBlocks[blockCount - 1]; // All granular blocks must have non-granular blocks surrounding them, unless they start at 0. // We must extend the non-granular blocks into the granular ones. This does mean that we need to search twice. if (first.IsGranular || last.IsGranular) { ulong surroundStart = Math.Max(0, (first.IsGranular && first.Address != 0) ? first.Address - 1 : id); blockCount = _placeholders.FindOverlapsNonOverlapping( surroundStart, (last.IsGranular ? last.EndAddress + 1 : endId) - surroundStart, ref _foundBlocks); first = _foundBlocks[0]; last = _foundBlocks[blockCount - 1]; } if (first == last) { return; // Already coalesced. } PlaceholderBlock extendBlock = id == 0 ? null : first; bool newBlock = false; for (int i = extendBlock == null ? 0 : 1; i < blockCount; i++) { // Go through all granular blocks in the range and extend placeholders. PlaceholderBlock block = _foundBlocks[i]; ulong blockEnd = block.EndAddress; ulong extendFrom; ulong extent = Math.Min(blockEnd, endId); if (block.Address < id && blockEnd > id) { block.ExtendTo(id); extendBlock = null; } else { _placeholders.Remove(block); } if (extendBlock == null) { extendFrom = id; extendBlock = new PlaceholderBlock(id, extent - id, false); _placeholders.Add(extendBlock); if (blockEnd > extent) { _placeholders.Add(new PlaceholderBlock(extent, blockEnd - extent, true)); // Skip the next non-granular block, and extend from that into the granular block afterwards. // (assuming that one is still in the requested range) if (i + 1 < blockCount) { extendBlock = _foundBlocks[i + 1]; } i++; } newBlock = true; } else { extendFrom = extendBlock.Address; extendBlock.ExtendTo(block.IsGranular ? extent : block.EndAddress); } if (block.IsGranular) { ulong placeholderStart = Math.Max(block.Address, id); ulong placeholderEnd = extent; if (newBlock) { placeholderStart++; newBlock = false; } for (ulong j = placeholderStart; j < placeholderEnd; j++) { coalescePlaceholderCallback(extendFrom, (j + 1) - extendFrom); } if (extent < block.EndAddress) { _placeholders.Add(new PlaceholderBlock(placeholderEnd, block.EndAddress - placeholderEnd, true)); ValidateList(); return; } } else { coalescePlaceholderCallback(extendFrom, block.EndAddress - extendFrom); } } ValidateList(); }
public BlockBase CreateAndInitialiseBlock(View hostView, Node parentNode, BlockBase parentBlock, BlockDefinition definition, FieldList contentData, bool isRoot) { if (definition != null) { BlockBase block = null; if (definition is ContainerBlockDefinition) { ContainerBlockDefinition cdef = (ContainerBlockDefinition)definition; switch (cdef.HintedType) { case UIHintedType.ApplicationBar: block = new ApplicationBarBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.NativeMessageBox: block = new NativeMessageBoxBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.TabBar: block = new TabBarBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.ActionSheet: block = new ActionSheetBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.Pivot: block = new PivotBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.Panorama: block = new PanoramaBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.None: default: { if (cdef is BoxLayoutBlockDefinition) { block = new BoxLayoutBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); } else if (cdef is GridBlockDefinition) { block = new GridBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); } else if (cdef is ListBlockDefinition) { block = new ListBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); } else if (cdef is FrameDefinition) { block = new FrameBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); } break; } } } else if (definition is CommonAtomicBlockDefinition) { CommonAtomicBlockDefinition cabdef = (CommonAtomicBlockDefinition)definition; switch (cabdef.HintedType) { case UIHintedType.ApplicationBarOptions: block = new ApplicationBarOptionsBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.ApplicationBarButton: block = new ApplicationBarButtonBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.ApplicationBarMenuItem: block = new ApplicationBarMenuItemBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.NativeMessageBoxBody: block = new NativeMessageBoxBodyBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.NativeMessageBoxButton: block = new NativeMessageBoxButtonBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.TabBarButton: block = new TabBarButtonBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.SystemTray: block = new SystemTrayBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.Placeholder: block = new PlaceholderBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); break; case UIHintedType.None: default: { if (cabdef is AtomicBlockDefinition) { block = new AtomicBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); } else if (cabdef is SingleSlotBlockDefinition) { block = new SingleSlotBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); } break; } } } else if (definition is ScrollingTextBlockDefinition) { block = new ScrollingTextBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); } else if (definition is MapPluginBlockDefinition) { block = new MapPluginBlock(hostView, parentNode, parentBlock, definition, contentData, isRoot); } if (block != null) { if (block.IsHidden) { block.Visibility = Visibility.Collapsed; } return(block); } } return(null); }