/* ==================================================================== 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; using System.Text; using System.IO; using HH.WMS.Utils.NPOI.POIFS.Common; using System.Collections.Generic; namespace HH.WMS.Utils.NPOI.POIFS.Storage { /// /// Storage for documents that are too small to use regular /// DocumentBlocks for their data /// @author Marc Johnson (mjohnson at apache dot org) /// public class SmallDocumentBlock : BlockWritable, ListManagedBlock { private static int BLOCK_SHIFT = 6; private byte[] _data; private static byte _default_fill = ( byte ) 0xff; private static int _block_size = 1 << BLOCK_SHIFT; private static int BLOCK_MASK = _block_size - 1; private static int _blocks_per_big_block = POIFSConstants.BIG_BLOCK_SIZE / _block_size; private POIFSBigBlockSize _bigBlockSize; public SmallDocumentBlock(POIFSBigBlockSize bigBlockSize, byte[] data, int index) { _bigBlockSize = bigBlockSize; _blocks_per_big_block = GetBlocksPerBigBlock(bigBlockSize); _data = new byte[_block_size]; System.Array.Copy(data, index*_block_size, _data, 0, _block_size); } public SmallDocumentBlock(POIFSBigBlockSize bigBlockSize) { _bigBlockSize = bigBlockSize; _blocks_per_big_block = GetBlocksPerBigBlock(bigBlockSize); _data = new byte[_block_size]; } private static int GetBlocksPerBigBlock(POIFSBigBlockSize bigBlockSize) { return bigBlockSize.GetBigBlockSize()/_block_size; } /// /// convert a single long array into an array of SmallDocumentBlock /// instances /// /// the byte array to be converted /// the intended size of the array (which may be smaller) /// an array of SmallDocumentBlock instances, filled from /// the array public static SmallDocumentBlock [] Convert(POIFSBigBlockSize bigBlockSize, byte [] array, int size) { SmallDocumentBlock[] rval = new SmallDocumentBlock[ (size + _block_size - 1) / _block_size ]; int offset = 0; for (int k = 0; k < rval.Length; k++) { rval[ k ] = new SmallDocumentBlock(bigBlockSize); if (offset < array.Length) { int length = Math.Min(_block_size, array.Length - offset); Array.Copy(array, offset, rval[ k ]._data, 0, length); if (length != _block_size) { for (int i = length; i < _block_size; i++) rval[k]._data[i] = _default_fill; } } else { for (int j = 0; j < rval[k]._data.Length; j++) { rval[k]._data[j] = _default_fill; } } offset += _block_size; } return rval; } /// /// fill out a List of SmallDocumentBlocks so that it fully occupies /// a Set of big blocks /// /// the List to be filled out. /// number of big blocks the list encompasses public static int Fill(POIFSBigBlockSize bigBlockSize,IList blocks) { int _blocks_per_big_block = GetBlocksPerBigBlock(bigBlockSize); int count = blocks.Count; int big_block_count = (count + _blocks_per_big_block - 1) / _blocks_per_big_block; int full_count = big_block_count * _blocks_per_big_block; for (; count < full_count; count++) { blocks.Add(MakeEmptySmallDocumentBlock(bigBlockSize)); } return big_block_count; } /// /// Factory for creating SmallDocumentBlocks from DocumentBlocks /// /// the original DocumentBlocks /// the total document size /// an array of new SmallDocumentBlocks instances public static SmallDocumentBlock [] Convert(POIFSBigBlockSize bigBlocksSize, BlockWritable [] store, int size) { using (MemoryStream stream = new MemoryStream()) { for (int j = 0; j < store.Length; j++) { store[j].WriteBlocks(stream); } byte[] data = stream.ToArray(); SmallDocumentBlock[] rval = new SmallDocumentBlock[ ConvertToBlockCount(size) ]; for (int index = 0; index < rval.Length; index++) { rval[index] = new SmallDocumentBlock(bigBlocksSize,data, index); } return rval; } } /// /// create a list of SmallDocumentBlock's from raw data /// /// the raw data containing the SmallDocumentBlock /// a List of SmallDocumentBlock's extracted from the input public static List Extract(POIFSBigBlockSize bigBlockSize, ListManagedBlock [] blocks) { int _blocks_per_big_block = GetBlocksPerBigBlock(bigBlockSize); List sdbs = new List(); for (int j = 0; j < blocks.Length; j++) { byte[] data = blocks[ j ].Data; for (int k = 0; k < _blocks_per_big_block; k++) { sdbs.Add(new SmallDocumentBlock(bigBlockSize, data, k)); } } return sdbs; } /// /// Read data from an array of SmallDocumentBlocks /// /// the blocks to Read from. /// the buffer to Write the data into. /// the offset into the array of blocks to Read from public static void Read(BlockWritable[] blocks, byte[] buffer, int offset) { int firstBlockIndex = offset / _block_size; int firstBlockOffSet = offset % _block_size; int lastBlockIndex = (offset + buffer.Length - 1) / _block_size; if (firstBlockIndex == lastBlockIndex) { Array.Copy( (( SmallDocumentBlock ) blocks[ firstBlockIndex ])._data, firstBlockOffSet, buffer, 0, buffer.Length); } else { int buffer_offset = 0; Array.Copy( (( SmallDocumentBlock ) blocks[ firstBlockIndex ])._data, firstBlockOffSet, buffer, buffer_offset, _block_size - firstBlockOffSet); buffer_offset += _block_size - firstBlockOffSet; for (int j = firstBlockIndex + 1; j < lastBlockIndex; j++) { Array.Copy((( SmallDocumentBlock ) blocks[ j ])._data, 0, buffer, buffer_offset, _block_size); buffer_offset += _block_size; } Array.Copy( (( SmallDocumentBlock ) blocks[ lastBlockIndex ])._data, 0, buffer, buffer_offset, buffer.Length - buffer_offset); } } public static DataInputBlock GetDataInputBlock(SmallDocumentBlock[] blocks, int offset) { int firstBlockIndex = offset >> BLOCK_SHIFT; int firstBlockOffset = offset & BLOCK_MASK; return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset); } /// /// Calculate the storage size of a Set of SmallDocumentBlocks /// /// number of SmallDocumentBlocks /// total size public static int CalcSize(int size) { return size * _block_size; } /// /// Makes the empty small document block. /// /// private static SmallDocumentBlock MakeEmptySmallDocumentBlock(POIFSBigBlockSize bigBlockSize) { SmallDocumentBlock block = new SmallDocumentBlock(bigBlockSize); for (int i = 0; i < block._data.Length; i++) { block._data[i] = _default_fill; } return block; } /// /// Converts to block count. /// /// The size. /// private static int ConvertToBlockCount(int size) { return (size + _block_size - 1) / _block_size; } /// /// Write the storage to an OutputStream /// /// the OutputStream to which the stored data should /// be written public void WriteBlocks(Stream stream) { stream.Write(_data,0,_data.Length); } /// /// Get the data from the block /// /// the block's data as a byte array public byte [] Data { get { return _data; } } public POIFSBigBlockSize BigBlockSize { get { return _bigBlockSize; } } } }