/* ====================================================================
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 HH.WMS.Utils.NPOI.DDF
{
using System;
using System.IO;
using System.Collections;
using HH.WMS.Utils.NPOI.Util;
using System.Collections.Generic;
///
/// 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
///
abstract public class EscherRecord : ICloneable
{
private short options;
private short recordId;
///
/// Initializes a new instance of the class.
///
public EscherRecord()
{
}
///
/// Delegates to FillFields(byte[], int, EscherRecordFactory)
///
/// The data.
/// The f.
///
public int FillFields(byte[] data, EscherRecordFactory f)
{
return FillFields(data, 0, f);
}
///
/// The contract of this method is to deSerialize an escher record including
/// it's children.
///
/// The byte array containing the Serialized escher
/// records.
/// The offset into the byte array.
/// A factory for creating new escher records.
/// The number of bytes written.
public abstract int FillFields(byte[] data, int offset, EscherRecordFactory recordFactory);
///
/// Reads the 8 byte header information and populates the
/// options
/// and
/// recordId
/// records.
///
/// the byte array to Read from
/// the offset to start Reading from
/// the number of bytes remaining in this record. This
protected int ReadHeader(byte[] data, int offset)
{
EscherRecordHeader header = EscherRecordHeader.ReadHeader(data, offset);
options = header.Options;
recordId = header.RecordId;
return header.RemainingBytes;
}
///
/// Determine whether this is a container record by inspecting the option
/// field.
///
///
/// true if this instance is container record; otherwise, false.
///
public bool IsContainerRecord
{
get { return (options & (short)0x000f) == (short)0x000f; }
}
///
/// Gets or sets the options field for this record. All records have one
///
/// The options.
public virtual short Options
{
get { return options; }
set { this.options = value; }
}
///
/// Serializes to a new byte array. This is done by delegating to
/// Serialize(int, byte[]);
///
/// the Serialized record.
public byte[] Serialize()
{
byte[] retval = new byte[RecordSize];
int length=Serialize(0, retval);
return retval;
}
///
/// Serializes to an existing byte array without serialization listener.
/// This is done by delegating to Serialize(int, byte[], EscherSerializationListener).
///
/// the offset within the data byte array.
/// the data array to Serialize to.
/// The number of bytes written.
public int Serialize(int offset, byte[] data)
{
return Serialize(offset, data, new NullEscherSerializationListener());
}
///
/// Serializes the record to an existing byte array.
///
/// the offset within the byte array.
/// the offset within the byte array
/// 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.
///
///
public abstract int Serialize(int offset, byte[] data, EscherSerializationListener listener);
///
/// Subclasses should effeciently return the number of bytes required to
/// Serialize the record.
///
/// number of bytes
abstract public int RecordSize { get; }
///
/// Return the current record id.
///
/// The 16 bit record id.
public virtual short RecordId
{
get { return recordId; }
set { this.recordId = value; }
}
///
/// Gets or sets the child records.
///
/// Returns the children of this record. By default this will
/// be an empty list. EscherCotainerRecord is the only record that may contain children.
public virtual List ChildRecords
{
get { return new List(); }
set { throw new ArgumentException("This record does not support child records."); }
}
///
/// Creates a new object that is a copy of the current instance.
///
///
/// A new object that is a copy of this instance.
///
public object Clone()
{
throw new Exception("The class " + this.GetType().Name + " needs to define a clone method");
}
///
/// Returns the indexed child record.
///
/// The index.
///
public EscherRecord GetChild(int index)
{
return (EscherRecord)ChildRecords[index];
}
///
/// The display methods allows escher variables to print the record names
/// according to their hierarchy.
///
/// The current indent level.
public virtual void Display(int indent)
{
for (int i = 0; i < indent * 4; i++)
{
Console.Write(' ');
}
Console.WriteLine(RecordName);
}
///
/// Gets the name of the record.
///
/// The name of the record.
public abstract String RecordName { get; }
///
/// Returns the instance part of the option record.
///
/// The instance part of the record
public short GetInstance()
{
return (short)(options >> 4);
}
///
/// This class Reads the standard escher header.
///
internal class EscherRecordHeader
{
private short options;
private short recordId;
private int remainingBytes;
private EscherRecordHeader()
{
}
///
/// Reads the header.
///
/// The data.
/// The off set.
///
public static EscherRecordHeader ReadHeader(byte[] data, int offset)
{
EscherRecordHeader header = new EscherRecordHeader();
header.options = LittleEndian.GetShort(data, offset);
header.recordId = LittleEndian.GetShort(data, offset + 2);
header.remainingBytes = LittleEndian.GetInt(data, offset + 4);
return header;
}
///
/// Gets the options.
///
/// The options.
public short Options
{
get { return options; }
}
///
/// Gets the record id.
///
/// The record id.
public virtual short RecordId
{
get { return recordId; }
}
///
/// Gets the remaining bytes.
///
/// The remaining bytes.
public int RemainingBytes
{
get { return remainingBytes; }
}
///
/// Returns a that represents the current .
///
///
/// A that represents the current .
///
public override String ToString()
{
return "EscherRecordHeader{" +
"options=" + options +
", recordId=" + recordId +
", remainingBytes=" + remainingBytes +
"}";
}
}
}
}