/* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for Additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ /* ================================================================ * About NPOI * Author: Tony Qu * Author's email: tonyqus (at) gmail.com * Author's Blog: tonyqus.wordpress.com.cn (wp.tonyqus.cn) * HomePage: http://www.codeplex.com/npoi * Contributors: * * ==============================================================*/ using System; using System.Collections.Generic; using System.IO; using HH.WMS.Utils.NPOI.POIFS.Common; using HH.WMS.Utils.NPOI.POIFS.FileSystem; using HH.WMS.Utils.NPOI.POIFS.NIO; using HH.WMS.Utils.NPOI.Util; namespace HH.WMS.Utils.NPOI.POIFS.Storage { /// /// This class manages and creates the Block Allocation Table, which is /// basically a set of linked lists of block indices. /// Each block of the filesystem has an index. The first block, the /// header, is skipped; the first block after the header is index 0, /// the next is index 1, and so on. /// A block's index is also its index into the Block Allocation /// Table. The entry that it finds in the Block Allocation Table is the /// index of the next block in the linked list of blocks making up a /// file, or it is set to -2: end of list. /// * /// @author Marc Johnson (mjohnson at apache dot org) /// public class BlockAllocationTableWriter : BlockWritable, BATManaged { private List _entries; private BATBlock[] _blocks; private int _start_block; private POIFSBigBlockSize _bigBlockSize; private static int _default_size = 128; /// /// Initializes a new instance of the class. /// public BlockAllocationTableWriter(POIFSBigBlockSize bigBlockSize) { _start_block = POIFSConstants.END_OF_CHAIN; _entries = new List(_default_size); _blocks = new BATBlock[ 0 ]; _bigBlockSize = bigBlockSize; } /// /// Create the BATBlocks we need /// /// start block index of BAT blocks public int CreateBlocks() { int xbat_blocks = 0; int bat_blocks = 0; while (true) { int calculated_bat_blocks = BATBlock.CalculateStorageRequirements(_bigBlockSize, bat_blocks + xbat_blocks + _entries.Count); int calculated_xbat_blocks = HeaderBlockWriter.CalculateXBATStorageRequirements(_bigBlockSize,calculated_bat_blocks); if ((bat_blocks == calculated_bat_blocks) && (xbat_blocks == calculated_xbat_blocks)) { // stable ... we're OK break; } else { bat_blocks = calculated_bat_blocks; xbat_blocks = calculated_xbat_blocks; } } int startBlock = AllocateSpace(bat_blocks); AllocateSpace(xbat_blocks); SimpleCreateBlocks(); return startBlock; } /// /// Allocate space for a block of indices /// /// the number of blocks to allocate space for /// the starting index of the blocks public int AllocateSpace(int blockCount) { int startBlock = _entries.Count; if (blockCount > 0) { int limit = blockCount - 1; int index = startBlock + 1; for (int k = 0; k < limit; k++) { _entries.Add(index++); } _entries.Add(POIFSConstants.END_OF_CHAIN); } return startBlock; } /// /// Sets the start block for this instance /// /// /// index into the array of BigBlock instances making up the the filesystem /// public int StartBlock { get { return _start_block; } set { _start_block = value; } } /// /// create the BATBlocks /// internal void SimpleCreateBlocks() { _blocks = BATBlock.CreateBATBlocks(_bigBlockSize, _entries.ToArray()); } /// /// Write the storage to an OutputStream /// /// the OutputStream to which the stored data should be written public void WriteBlocks(Stream stream) { for (int j = 0; j < _blocks.Length; j++) { _blocks[ j ].WriteBlocks(stream); } } //public static void WriteBlock(BATBlock bat, byte[] block) public static void WriteBlock(BATBlock bat, ByteBuffer block) { bat.WriteData(block); } /// /// Gets the number of BigBlock's this instance uses /// /// count of BigBlock instances public int CountBlocks { get { return _blocks.Length; } } } }