用于生成 Office 文件的 .NET 组件。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
13 KiB

8 years ago
/* ====================================================================
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.
==================================================================== */
namespace Npoi.Core.DDF
8 years ago
{
using Npoi.Core.Util;
8 years ago
using System;
8 years ago
using System.Collections.Generic;
using System.Text;
/// <summary>
/// The base abstract record from which all escher records are defined. Subclasses will need
/// to define methods for serialization/deserialization and for determining the record size.
/// @author Glen Stampoultzis
/// </summary>
abstract public class EscherRecord : ICloneable
{
private static BitField fInstance = BitFieldFactory.GetInstance(0xfff0);
private static BitField fVersion = BitFieldFactory.GetInstance(0x000f);
private short _options;
private short _recordId;
/// <summary>
/// Initializes a new instance of the <see cref="EscherRecord"/> class.
/// </summary>
8 years ago
public EscherRecord() {
8 years ago
}
/// <summary>
/// Delegates to FillFields(byte[], int, EscherRecordFactory)
/// </summary>
/// <param name="data">The data.</param>
/// <param name="f">The f.</param>
/// <returns></returns>
8 years ago
public int FillFields(byte[] data, IEscherRecordFactory f) {
8 years ago
return FillFields(data, 0, f);
}
/// <summary>
/// The contract of this method is to deSerialize an escher record including
/// it's children.
/// </summary>
/// <param name="data">The byte array containing the Serialized escher
/// records.</param>
/// <param name="offset">The offset into the byte array.</param>
/// <param name="recordFactory">A factory for creating new escher records.</param>
8 years ago
/// <returns>The number of bytes written.</returns>
8 years ago
public abstract int FillFields(byte[] data, int offset, IEscherRecordFactory recordFactory);
/// <summary>
8 years ago
/// Reads the 8 byte header information and populates the
8 years ago
/// <c>options</c>
8 years ago
/// and
8 years ago
/// <c>recordId</c>
/// records.
/// </summary>
/// <param name="data">the byte array to Read from</param>
/// <param name="offset">the offset to start Reading from</param>
/// <returns>the number of bytes remaining in this record. This</returns>
8 years ago
protected int ReadHeader(byte[] data, int offset) {
8 years ago
//EscherRecordHeader header = EscherRecordHeader.ReadHeader(data, offset);
//_options = header.Options;
//_recordId = header.RecordId;
//return header.RemainingBytes;
_options = LittleEndian.GetShort(data, offset);
_recordId = LittleEndian.GetShort(data, offset + 2);
int remainingBytes = LittleEndian.GetInt(data, offset + 4);
return remainingBytes;
}
/// <summary>
/// Read the options field from header and return instance part of it.
/// </summary>
/// <param name="data">the byte array to read from</param>
/// <param name="offset">the offset to start reading from</param>
/// <returns>value of instance part of options field</returns>
8 years ago
protected static short ReadInstance(byte[] data, int offset) {
short options = LittleEndian.GetShort(data, offset);
return fInstance.GetShortValue(options);
8 years ago
}
8 years ago
8 years ago
/// <summary>
/// Determine whether this is a container record by inspecting the option
/// field.
/// </summary>
/// <value>
/// <c>true</c> if this instance is container record; otherwise, <c>false</c>.
/// </value>
8 years ago
public bool IsContainerRecord {
8 years ago
get { return Version == (short)0x000f; }
}
/// <summary>
/// Gets or sets the options field for this record. All records have one
/// </summary>
/// <value>The options.</value>
8 years ago
internal virtual short Options {
8 years ago
get { return _options; }
set
{
Version = (fVersion.GetShortValue(value));
Instance = (fInstance.GetShortValue(value));
this._options = value;
}
}
/// <summary>
/// Serializes to a new byte array. This is done by delegating to
/// Serialize(int, byte[]);
/// </summary>
/// <returns>the Serialized record.</returns>
8 years ago
public byte[] Serialize() {
8 years ago
byte[] retval = new byte[RecordSize];
8 years ago
int length = Serialize(0, retval);
8 years ago
return retval;
}
8 years ago
8 years ago
/// <summary>
/// Serializes to an existing byte array without serialization listener.
/// This is done by delegating to Serialize(int, byte[], EscherSerializationListener).
/// </summary>
/// <param name="offset">the offset within the data byte array.</param>
/// <param name="data">the data array to Serialize to.</param>
/// <returns>The number of bytes written.</returns>
8 years ago
public int Serialize(int offset, byte[] data) {
8 years ago
return Serialize(offset, data, new NullEscherSerializationListener());
}
/// <summary>
/// Serializes the record to an existing byte array.
/// </summary>
/// <param name="offset">the offset within the byte array.</param>
/// <param name="data">the offset within the byte array</param>
/// <param name="listener">a listener for begin and end serialization events. This.
/// is useful because the serialization is
/// hierarchical/recursive and sometimes you need to be able
/// break into that.
/// </param>
/// <returns></returns>
public abstract int Serialize(int offset, byte[] data, EscherSerializationListener listener);
/// <summary>
/// Subclasses should effeciently return the number of bytes required to
/// Serialize the record.
/// </summary>
/// <value>number of bytes</value>
abstract public int RecordSize { get; }
/// <summary>
/// Return the current record id.
/// </summary>
/// <value>The 16 bit record id.</value>
8 years ago
public virtual short RecordId {
8 years ago
get { return _recordId; }
set { this._recordId = value; }
}
8 years ago
8 years ago
/// <summary>
/// Gets or sets the child records.
/// </summary>
/// <value>Returns the children of this record. By default this will
/// be an empty list. EscherCotainerRecord is the only record that may contain children.</value>
8 years ago
public virtual List<EscherRecord> ChildRecords {
8 years ago
get { return new List<EscherRecord>(); }
set { throw new ArgumentException("This record does not support child records."); }
}
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
8 years ago
public object Clone() {
8 years ago
throw new Exception("The class " + this.GetType().Name + " needs to define a clone method");
}
8 years ago
8 years ago
/// <summary>
/// Returns the indexed child record.
/// </summary>
/// <param name="index">The index.</param>
/// <returns></returns>
8 years ago
public EscherRecord GetChild(int index) {
8 years ago
return (EscherRecord)ChildRecords[index];
}
/// <summary>
/// The display methods allows escher variables to print the record names
/// according to their hierarchy.
/// </summary>
8 years ago
/// <param name="indent">The current indent level.</param>
public virtual void Display(int indent) {
for (int i = 0; i < indent * 4; i++) {
8 years ago
Console.Write(' ');
}
Console.WriteLine(RecordName);
}
/// <summary>
/// Gets the name of the record.
/// </summary>
/// <value>The name of the record.</value>
public abstract String RecordName { get; }
/// <summary>
/// This class Reads the standard escher header.
/// </summary>
internal class DeleteEscherRecordHeader
{
private short options;
private short recordId;
private int remainingBytes;
8 years ago
private DeleteEscherRecordHeader() {
8 years ago
}