compoundfile.cs

来自「Excel的操作,其中可以读取及写入Excel 文件」· CS 代码 · 共 362 行

CS
362
字号
using System;
using System.Collections;

using Microsoft.Fawvw.Components.NExcel.ExcelCommon;
using Microsoft.Fawvw.Components.NExcel.Biff;

namespace Microsoft.Fawvw.Components.NExcel.Read.Biff
{
	
	/// <summary> Reads in and defrags an OLE compound compound file
	/// (Made public only for the PropertySets demo)
	/// </summary>
	public sealed class CompoundFile:BaseCompoundFile
	{
		/// <summary> Gets the property sets</summary>
		/// <returns> the list of property sets
		/// </returns>
		public string[] PropertySetNames
		{
			get
			{
				string[] sets = new string[propertySets.Count];
				for (int i = 0; i < sets.Length; i++)
				{
					PropertyStorage ps = (PropertyStorage) propertySets[i];
					sets[i] = ps.name;
				}
				
				return sets;
			}
			
		}
		/// <summary> The logger</summary>
		private static Logger logger;
		
		/// <summary> The original OLE stream, organized into blocks, which can
		/// appear at any physical location in the file
		/// </summary>
		private sbyte[] data;
		/// <summary> The number of blocks it takes to store the big block depot</summary>
		private int numBigBlockDepotBlocks;
		/// <summary> The start block of the small block depot</summary>
		private int sbdStartBlock;
		/// <summary> The start block of the root entry</summary>
		private int rootStartBlock;
		/// <summary> The header extension block</summary>
		private int extensionBlock;
		/// <summary> The number of header extension blocks</summary>
		private int numExtensionBlocks;
		/// <summary> The root entry</summary>
		private sbyte[] rootEntry;
		/// <summary> The sequence of blocks which comprise the big block chain</summary>
		private int[] bigBlockChain;
		/// <summary> The sequence of blocks which comprise the small block chain</summary>
		private int[] smallBlockChain;
		/// <summary> The chain of blocks which comprise the big block depot</summary>
		private int[] bigBlockDepotBlocks;
		/// <summary> The list of property sets</summary>
		private ArrayList propertySets;
		
		/// <summary> The workbook settings</summary>
		private WorkbookSettings settings;
		
		/// <summary> Initializes the compound file
		/// 
		/// </summary>
		/// <param name="d">the raw data of the ole stream
		/// </param>
		/// <param name="ws">the workbook settings
		/// </param>
		/// <exception cref=""> BiffException
		/// </exception>
		public CompoundFile(sbyte[] d, WorkbookSettings ws):base()
		{
			data = d;
			settings = ws;
			
			// First verify the OLE identifier
			for (int i = 0; i < IDENTIFIER.Length; i++)
			{
				if (data[i] != IDENTIFIER[i])
				{
					throw new BiffException(BiffException.unrecognizedOLEFile);
				}
			}
			
			propertySets = new ArrayList();
			numBigBlockDepotBlocks = IntegerHelper.getInt(data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS], data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS + 1], data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS + 2], data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS + 3]);
			sbdStartBlock = IntegerHelper.getInt(data[SMALL_BLOCK_DEPOT_BLOCK_POS], data[SMALL_BLOCK_DEPOT_BLOCK_POS + 1], data[SMALL_BLOCK_DEPOT_BLOCK_POS + 2], data[SMALL_BLOCK_DEPOT_BLOCK_POS + 3]);
			rootStartBlock = IntegerHelper.getInt(data[ROOT_START_BLOCK_POS], data[ROOT_START_BLOCK_POS + 1], data[ROOT_START_BLOCK_POS + 2], data[ROOT_START_BLOCK_POS + 3]);
			extensionBlock = IntegerHelper.getInt(data[EXTENSION_BLOCK_POS], data[EXTENSION_BLOCK_POS + 1], data[EXTENSION_BLOCK_POS + 2], data[EXTENSION_BLOCK_POS + 3]);
			numExtensionBlocks = IntegerHelper.getInt(data[NUM_EXTENSION_BLOCK_POS], data[NUM_EXTENSION_BLOCK_POS + 1], data[NUM_EXTENSION_BLOCK_POS + 2], data[NUM_EXTENSION_BLOCK_POS + 3]);
			
			bigBlockDepotBlocks = new int[numBigBlockDepotBlocks];
			
			int pos = BIG_BLOCK_DEPOT_BLOCKS_POS;
			
			int bbdBlocks = numBigBlockDepotBlocks;
			
			if (numExtensionBlocks != 0)
			{
				bbdBlocks = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;
			}
			
			for (int i = 0; i < bbdBlocks; i++)
			{
				bigBlockDepotBlocks[i] = IntegerHelper.getInt(d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
				pos += 4;
			}
			
			for (int j = 0; j < numExtensionBlocks; j++)
			{
				pos = (extensionBlock + 1) * BIG_BLOCK_SIZE;
				int blocksToRead = System.Math.Min(numBigBlockDepotBlocks - bbdBlocks, BIG_BLOCK_SIZE / 4 - 1);
				
				for (int i = bbdBlocks; i < bbdBlocks + blocksToRead; i++)
				{
					bigBlockDepotBlocks[i] = IntegerHelper.getInt(d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
					pos += 4;
				}
				
				bbdBlocks += blocksToRead;
				if (bbdBlocks < numBigBlockDepotBlocks)
				{
					extensionBlock = IntegerHelper.getInt(d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
				}
			}
			
			readBigBlockDepot();
			readSmallBlockDepot();
			
			rootEntry = readData(rootStartBlock);
			readPropertySets();
		}
		
		/// <summary> Reads the big block depot entries</summary>
		private void  readBigBlockDepot()
		{
			int pos = 0;
			int index = 0;
			bigBlockChain = new int[numBigBlockDepotBlocks * BIG_BLOCK_SIZE / 4];
			
			for (int i = 0; i < numBigBlockDepotBlocks; i++)
			{
				pos = (bigBlockDepotBlocks[i] + 1) * BIG_BLOCK_SIZE;
				
				for (int j = 0; j < BIG_BLOCK_SIZE / 4; j++)
				{
					bigBlockChain[index] = IntegerHelper.getInt(data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
					pos += 4;
					index++;
				}
			}
		}
		
		/// <summary> Reads the small block depot entries</summary>
		private void  readSmallBlockDepot()
		{
			int pos = 0;
			int index = 0;
			int sbdBlock = sbdStartBlock;
			smallBlockChain = new int[0];
			
			while (sbdBlock != - 2)
			{
				// Allocate some more space to the small block chain
				int[] oldChain = smallBlockChain;
				smallBlockChain = new int[smallBlockChain.Length + BIG_BLOCK_SIZE / 4];
				Array.Copy(oldChain, 0, smallBlockChain, 0, oldChain.Length);
				
				pos = (sbdBlock + 1) * BIG_BLOCK_SIZE;
				
				for (int j = 0; j < BIG_BLOCK_SIZE / 4; j++)
				{
					smallBlockChain[index] = IntegerHelper.getInt(data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
					pos += 4;
					index++;
				}
				
				sbdBlock = bigBlockChain[sbdBlock];
			}
		}
		
		/// <summary> Reads all the property sets</summary>
		private void  readPropertySets()
		{
			int offset = 0;
			sbyte[] d = null;
			
			while (offset < rootEntry.Length)
			{
				d = new sbyte[PROPERTY_STORAGE_BLOCK_SIZE];
				Array.Copy(rootEntry, offset, d, 0, d.Length);
				PropertyStorage ps = new PropertyStorage(this, d);
				propertySets.Add(ps);
				offset += PROPERTY_STORAGE_BLOCK_SIZE;
			}
		}
		
		/// <summary> Gets the defragmented stream from this ole compound file
		/// 
		/// </summary>
		/// <param name="streamName">the stream name to get
		/// </param>
		/// <returns> the defragmented ole stream
		/// </returns>
		/// <exception cref=""> BiffException
		/// </exception>
		public sbyte[] getStream(string streamName)
		{
			PropertyStorage ps = getPropertyStorage(streamName);
			
			if (ps.size >= SMALL_BLOCK_THRESHOLD || streamName.ToUpper().Equals("root entry".ToUpper()))
			{
				return getBigBlockStream(ps);
			}
			else
			{
				return getSmallBlockStream(ps);
			}
		}
		
		/// <summary> Gets the property set with the specified name</summary>
		/// <param name="name">the property storage name
		/// </param>
		/// <returns> the property storage record
		/// </returns>
		/// <exception cref=""> BiffException
		/// </exception>
		private PropertyStorage getPropertyStorage(string name)
		{
			// Find the workbook property
			bool found = false;
			PropertyStorage psres = null;
			foreach(PropertyStorage ps in propertySets)
			{
				if (found) break;
				if (ps.name.ToLower().Equals(name==null ? null : name.ToLower()))
				{
					found = true;
					psres = ps;
				}
			}
			
			if (!found)
			{
				throw new BiffException(BiffException.streamNotFound);
			}
			
			return psres;
		}
		
		/// <summary> Build up the resultant stream using the big blocks
		/// 
		/// </summary>
		/// <param name="ps">the property storage
		/// </param>
		/// <returns> the big block stream
		/// </returns>
		private sbyte[] getBigBlockStream(PropertyStorage ps)
		{
			int numBlocks = ps.size / BIG_BLOCK_SIZE;
			if (ps.size % BIG_BLOCK_SIZE != 0)
			{
				numBlocks++;
			}
			
			sbyte[] streamData = new sbyte[numBlocks * BIG_BLOCK_SIZE];
			
			int block = ps.startBlock;
			
			int count = 0;
			int pos = 0;
			while (block != - 2 && count < numBlocks)
			{
				pos = (block + 1) * BIG_BLOCK_SIZE;
				Array.Copy(data, pos, streamData, count * BIG_BLOCK_SIZE, BIG_BLOCK_SIZE);
				count++;
				block = bigBlockChain[block];
			}
			
			if (block != - 2 && count == numBlocks)
			{
				logger.warn("Property storage size inconsistent with block chain.");
			}
			
			return streamData;
		}
		
		/// <summary> Build up the resultant stream using the small blocks</summary>
		/// <param name="ps">the property storage
		/// </param>
		/// <returns>  the data
		/// </returns>
		/// <exception cref=""> BiffException
		/// </exception>
		private sbyte[] getSmallBlockStream(PropertyStorage ps)
		{
			PropertyStorage rootps = null;
			try
			{
				rootps = getPropertyStorage("root entry");
			}
			catch (BiffException e)
			{
				rootps = (PropertyStorage) propertySets[0];
			}
			
			sbyte[] rootdata = readData(rootps.startBlock);
			sbyte[] sbdata = new sbyte[0];
			
			int block = ps.startBlock;
			//    int count = 0;
			int pos = 0;
			while (block != - 2)
			{
				// grow the array
				sbyte[] olddata = sbdata;
				sbdata = new sbyte[olddata.Length + SMALL_BLOCK_SIZE];
				Array.Copy(olddata, 0, sbdata, 0, olddata.Length);
				
				// Copy in the new data
				pos = block * SMALL_BLOCK_SIZE;
				Array.Copy(rootdata, pos, sbdata, olddata.Length, SMALL_BLOCK_SIZE);
				block = smallBlockChain[block];
			}
			
			return sbdata;
		}
		
		/// <summary> Reads the block chain from the specified block and returns the
		/// data as a continuous stream of bytes
		/// </summary>
		/// <param name="bl">the block number
		/// </param>
		/// <returns> the data
		/// </returns>
		private sbyte[] readData(int bl)
		{
			int block = bl;
			int pos = 0;
			sbyte[] entry = new sbyte[0];
			
			while (block != - 2)
			{
				// Grow the array
				sbyte[] oldEntry = entry;
				entry = new sbyte[oldEntry.Length + BIG_BLOCK_SIZE];
				Array.Copy(oldEntry, 0, entry, 0, oldEntry.Length);
				pos = (block + 1) * BIG_BLOCK_SIZE;
				Array.Copy(data, pos, entry, oldEntry.Length, BIG_BLOCK_SIZE);
				block = bigBlockChain[block];
			}
			return entry;
		}
		static CompoundFile()
		{
			logger = Logger.getLogger(typeof(CompoundFile));
		}
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?