diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..1ff0c42
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/Flac/Flac.Test/Flac.Test.csproj b/Flac/Flac.Test/Flac.Test.csproj
new file mode 100644
index 0000000..1aea248
--- /dev/null
+++ b/Flac/Flac.Test/Flac.Test.csproj
@@ -0,0 +1,85 @@
+
+
+
+ Debug
+ AnyCPU
+ {1576AB6D-F8F4-42FC-BDC7-67D08648AEA6}
+ Library
+ Properties
+ Flac.Test
+ Flac.Test
+ v3.5
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 10.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+ UnitTest
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Flac/Flac.Test/Properties/AssemblyInfo.cs b/Flac/Flac.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..33d525c
--- /dev/null
+++ b/Flac/Flac.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Flac.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Flac.Test")]
+[assembly: AssemblyCopyright("Copyright © 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("2376dc52-6d6f-40ac-a34c-44a1523983ac")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Flac/Flac.sln b/Flac/Flac.sln
new file mode 100644
index 0000000..d3539a7
--- /dev/null
+++ b/Flac/Flac.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.21005.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flac", "Flac\Flac.csproj", "{ECB7B567-6A67-43F4-89CA-64E5D9F07B97}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flac.Test", "Flac.Test\Flac.Test.csproj", "{1576AB6D-F8F4-42FC-BDC7-67D08648AEA6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {ECB7B567-6A67-43F4-89CA-64E5D9F07B97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ECB7B567-6A67-43F4-89CA-64E5D9F07B97}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ECB7B567-6A67-43F4-89CA-64E5D9F07B97}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ECB7B567-6A67-43F4-89CA-64E5D9F07B97}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1576AB6D-F8F4-42FC-BDC7-67D08648AEA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1576AB6D-F8F4-42FC-BDC7-67D08648AEA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1576AB6D-F8F4-42FC-BDC7-67D08648AEA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1576AB6D-F8F4-42FC-BDC7-67D08648AEA6}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Flac/Flac/ChannelData.cs b/Flac/Flac/ChannelData.cs
new file mode 100644
index 0000000..b7ac194
--- /dev/null
+++ b/Flac/Flac/ChannelData.cs
@@ -0,0 +1,53 @@
+using Flac.Frame;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac
+{
+ ///
+ /// FLAC channel data.
+ /// This class holds the data for the channels in a FLAC frame.
+ ///
+ public class ChannelData
+ {
+ ///
+ /// The output signal.
+ ///
+ public int[] Output
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// The risidual signal.
+ ///
+ public int[] Residual
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// The Entropy signal.
+ ///
+ public EntropyPartitionedRiceContents PartitionedRiceContents
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Creates a new instance of ChannelData
+ ///
+ /// The block size
+ public ChannelData(int size)
+ {
+ Output = new int[size];
+ Residual = new int[size];
+ PartitionedRiceContents = new EntropyPartitionedRiceContents();
+ }
+ }
+}
diff --git a/Flac/Flac/Flac.csproj b/Flac/Flac/Flac.csproj
new file mode 100644
index 0000000..3b5c0ae
--- /dev/null
+++ b/Flac/Flac/Flac.csproj
@@ -0,0 +1,76 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {ECB7B567-6A67-43F4-89CA-64E5D9F07B97}
+ Library
+ Properties
+ Flac
+ Flac
+ v3.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Flac/Flac/Frame/BadHeaderException.cs b/Flac/Flac/Frame/BadHeaderException.cs
new file mode 100644
index 0000000..3a3db4b
--- /dev/null
+++ b/Flac/Flac/Frame/BadHeaderException.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Frame
+{
+ ///
+ /// Bad header exception
+ ///
+ public class BadHeaderException : IOException
+ {
+ ///
+ /// Creates a new instance of bad header exception.
+ ///
+ public BadHeaderException()
+ : base()
+ {
+ }
+
+ ///
+ /// Creates a new instance of bad header exception with specified message.
+ ///
+ /// The message
+ public BadHeaderException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Creates a new instance of bad header exception with specified message
+ /// and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The message
+ /// The inner exception
+ public BadHeaderException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Flac/Flac/Frame/Channel.cs b/Flac/Flac/Frame/Channel.cs
new file mode 100644
index 0000000..4791bd3
--- /dev/null
+++ b/Flac/Flac/Frame/Channel.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Frame
+{
+ ///
+ /// Base class for FLAC subframe (channel) classes.
+ ///
+ public abstract class Channel
+ {
+ #region Constants
+ protected const int TypeLength = 2;
+ protected const int PartitionedRiceOrderLength = 4;
+ #endregion
+
+ protected enum EntropyCodingMethod
+ {
+ PartitionedRice = 0
+ }
+
+ ///
+ /// The FLAC Frame Header.
+ ///
+ protected Header Header { get; set; }
+
+ ///
+ /// The number of wasted bits in the frame.
+ ///
+ public int WastedBits { get; protected set; }
+
+ ///
+ /// Creates a new instance of channel.
+ ///
+ /// The FLAC Frame Header.
+ /// The number of wasted bits in the frame.
+ protected Channel(Header header, int wastedBits)
+ {
+ Header = header;
+ WastedBits = wastedBits;
+ }
+ }
+}
diff --git a/Flac/Flac/Frame/ChannelConstant.cs b/Flac/Flac/Frame/ChannelConstant.cs
new file mode 100644
index 0000000..513a920
--- /dev/null
+++ b/Flac/Flac/Frame/ChannelConstant.cs
@@ -0,0 +1,39 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Frame
+{
+ ///
+ /// FLAC constant subframe (channel) data.
+ /// This class represents a FLAC subframe (channel) for a Constant data
+ ///
+ public class ChannelConstant : Channel
+ {
+ ///
+ /// The constant signal value.
+ ///
+ private int value;
+
+ ///
+ /// Creates a new instance of ChannelConstant
+ ///
+ /// The bit reader
+ /// The FLAC Frame Header
+ /// The decoded channel data (output)
+ /// The bits-per-second
+ /// The bits wasted in the frame
+ /// Thrown if error reading from BitReader
+ public ChannelConstant(BitReader read, Header header, ChannelData channelData, int bps, int wastedBits)
+ : base(header, wastedBits)
+ {
+ value = (int)read.ReadRawUInt32(bps);
+
+ // Decode the subframe
+ for (int i = 0; i < header.BlockSize; i++)
+ channelData.Output[i] = value;
+ }
+ }
+}
diff --git a/Flac/Flac/Frame/ChannelFixed.cs b/Flac/Flac/Frame/ChannelFixed.cs
new file mode 100644
index 0000000..ab5fd9f
--- /dev/null
+++ b/Flac/Flac/Frame/ChannelFixed.cs
@@ -0,0 +1,76 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Frame
+{
+ ///
+ /// Fixed FLAC subframe (channel).
+ ///
+ public class ChannelFixed : Channel
+ {
+ private const int MaxFixedOrder = 4;
+
+ ///
+ /// The residual coding method.
+ ///
+ private Frame.EntropyCodingMethod entropyCodingMethod;
+
+ ///
+ /// The polynomial order.
+ ///
+ private int order;
+
+ ///
+ /// Warmup samples to prime the predictor, length == order.
+ ///
+ private int[] warmup = new int[MaxFixedOrder];
+
+ ///
+ /// The residual signal, length == (blocksize minus order) samples.
+ ///
+ private int[] residual;
+
+ ///
+ /// Creates a new instance of ChannelConstant
+ ///
+ /// The bit reader
+ /// The FLAC Frame Header
+ /// The decoded channel data (output)
+ /// The bits-per-second
+ /// The bits wasted in the frame
+ /// The predicate order
+ /// Thrown if error reading from BitReader
+ public ChannelFixed(BitReader read, Header header, ChannelData channelData, int bps, int wastedBits, int order)
+ : base(header, wastedBits)
+ {
+ residual = channelData.Residual;
+ this.order = order;
+
+ // Read warmup samples
+ for (int u = 0; u < order; u++)
+ warmup[u] = (int)read.ReadRawUInt32(bps);
+
+ // Read entropy coding method info
+ int type = (int)read.ReadRawUInt32(TypeLength);
+ EntropyPartitionedRice pr;
+
+ switch (type)
+ {
+ case (int)EntropyCodingMethod.PartitionedRice:
+ pr = new EntropyPartitionedRice();
+ entropyCodingMethod = pr;
+ pr.Order = (int)read.ReadRawUInt32(PartitionedRiceOrderLength);
+ pr.Contents = channelData.PartitionedRiceContents;
+ pr.ReadResidual(read, order, pr.Order, header, channelData.Residual);
+ break;
+
+ default:
+ throw new IOException("Unparseable stream!");
+ }
+ }
+ }
+}
diff --git a/Flac/Flac/Frame/EntropyCodingMethod.cs b/Flac/Flac/Frame/EntropyCodingMethod.cs
new file mode 100644
index 0000000..a86b02b
--- /dev/null
+++ b/Flac/Flac/Frame/EntropyCodingMethod.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Frame
+{
+ public interface EntropyCodingMethod
+ {
+ }
+}
diff --git a/Flac/Flac/Frame/EntropyPartitionedRice.cs b/Flac/Flac/Frame/EntropyPartitionedRice.cs
new file mode 100644
index 0000000..c8b7c7a
--- /dev/null
+++ b/Flac/Flac/Frame/EntropyPartitionedRice.cs
@@ -0,0 +1,86 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Frame
+{
+ ///
+ /// This class holds the Entropy Partitioned Rice contents.
+ ///
+ public class EntropyPartitionedRice : EntropyCodingMethod
+ {
+ #region Constants
+ private const int ParameterLength = 4; // bits
+ private const int RawLength = 5; // bits
+ private const UInt32 EscapeParameter = 15;
+ #endregion
+
+ ///
+ /// The partition order, i.e. # of contexts = 2 ^ order.
+ ///
+ public int Order { get; set; }
+
+ ///
+ /// The context's Rice parameters and/or raw bits.
+ ///
+ public EntropyPartitionedRiceContents Contents
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Read compressed signal residual data.
+ ///
+ /// The bit reader
+ /// The predicate order
+ /// The partition order
+ /// The FLAC Frame Header
+ /// The residual signal (output)
+ /// Thrown if error reading from BitReader
+ public void ReadResidual(BitReader read, int predictorOrder, int partitionOrder, Header header, int[] residual)
+ {
+ int sample = 0;
+ int partitions = 1 << partitionOrder;
+
+ int partitionSamples;
+ if (partitionOrder > 0)
+ partitionSamples = (header.BlockSize >> partitionOrder);
+ else
+ partitionSamples = (header.BlockSize - predictorOrder);
+
+ Contents = new EntropyPartitionedRiceContents();
+ Contents.EnsureSize(Math.Max(6, partitionOrder));
+ Contents.Parameters = new int[partitions]; // why allocate again?
+
+ for (int partition = 0; partition < partitions; partition++)
+ {
+ int riceParameter = (int)read.ReadRawUInt32(ParameterLength);
+ Contents.Parameters[partition] = riceParameter;
+
+ if (riceParameter < EscapeParameter)
+ {
+ int u = (partitionOrder == 0 || partition > 0) ?
+ (partitionSamples) :
+ (partitionSamples - predictorOrder);
+
+ read.ReadRiceSignedBlock(residual, sample, u, riceParameter);
+ sample += u;
+ }
+
+ else
+ {
+ riceParameter = (int)read.ReadRawUInt32(RawLength);
+ Contents.RawBits[partition] = riceParameter;
+
+ int u = (partitionOrder == 0 || partition > 0) ? (0) : (predictorOrder);
+
+ for (; u < partitionSamples; u++, sample++)
+ residual[sample] = (int)read.ReadRawUInt32(riceParameter);
+ }
+ }
+ }
+ }
+}
diff --git a/Flac/Flac/Frame/EntropyPartitionedRiceContents.cs b/Flac/Flac/Frame/EntropyPartitionedRiceContents.cs
new file mode 100644
index 0000000..2ff1ad0
--- /dev/null
+++ b/Flac/Flac/Frame/EntropyPartitionedRiceContents.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Frame
+{
+ public class EntropyPartitionedRiceContents
+ {
+ public int[] Parameters { get; set; }
+ public int[] RawBits { get; set; }
+
+ ///
+ /// The capacity of the parameters and raw_bits arrays specified as an order.
+ /// i.e. the number of array elements allocated is 2 ^ capacity_by_order.
+ ///
+ private int capacityByOrder = 0;
+
+ ///
+ /// Ensure enough menory has been allocated.
+ ///
+ /// The maximum partition order
+ public void EnsureSize(int maxPartitionOrder)
+ {
+ if (capacityByOrder >= maxPartitionOrder)
+ return;
+
+ Parameters = new int[(1 << maxPartitionOrder)];
+ RawBits = new int[(1 << maxPartitionOrder)];
+
+ capacityByOrder = maxPartitionOrder;
+ }
+ }
+}
diff --git a/Flac/Flac/Frame/Header.cs b/Flac/Flac/Frame/Header.cs
new file mode 100644
index 0000000..fbea925
--- /dev/null
+++ b/Flac/Flac/Frame/Header.cs
@@ -0,0 +1,70 @@
+using Flac.IO;
+using Flac.Metadata;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Frame
+{
+ ///
+ /// Frame header class.
+ ///
+ public class Header
+ {
+ ///
+ /// Gets or sets the number of samples per subframe.
+ ///
+ public int BlockSize { get; set; }
+
+ ///
+ /// Gets or sets the sample rate in Hz.
+ ///
+ public int SampleRate { get; set; }
+
+ ///
+ /// Gets or sets the number of channels (== number of subframes).
+ ///
+ public int Channels { get; set; }
+
+ ///
+ /// Gets or sets the channel assignment for the frame.
+ ///
+ public int ChannelAssignment { get; set; }
+
+ ///
+ /// Gets or sets the sample resolution.
+ ///
+ public int BitsPerSample { get; set; }
+
+ ///
+ /// Gets or sets the frame number or sample number of first sample in frame.
+ /// Use the number_type value to determine which to use.
+ ///
+ public int FrameNumber { get; set; }
+
+ ///
+ /// The sample number for the first sample in the frame.
+ ///
+ public int SampleNumber { get; set; }
+
+ ///
+ /// CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0)
+ /// of the raw frame header bytes, meaning everything before the CRC byte
+ /// including the sync code.
+ ///
+ protected byte crc;
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public Header(BitReader @is, byte[] headerWarmup, StreamInfo streamInfo)
+ {
+ FrameNumber = -1;
+ SampleNumber = -1;
+ }
+ }
+}
diff --git a/Flac/Flac/IO/BitReader.cs b/Flac/Flac/IO/BitReader.cs
new file mode 100644
index 0000000..2b4ed84
--- /dev/null
+++ b/Flac/Flac/IO/BitReader.cs
@@ -0,0 +1,788 @@
+using Flac.Util;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Flac.IO
+{
+ public class BitReader
+ {
+ #region Constants
+ private const int DefaultCapacity = 2048;
+ private const int BitsPerByte = 8;
+ private const int BitsPerByteLog2 = 3;
+ private const byte ByteTopBitOne = (byte)0x80;
+ #endregion
+
+ #region Private members
+ private byte[] buffer;
+ private int putByte = 0;
+ private int getByte = 0;
+ private int getBit = 0;
+ private int availBits = 0;
+ private int totalBitsRead = 0;
+ private UInt16 readCrc16 = 0;
+ private Stream stream;
+ #endregion
+
+ #region Constructor
+ ///
+ /// Creates a new instance of BitReader
+ ///
+ /// Input data stream
+ public BitReader(Stream stream)
+ {
+ buffer = new byte[DefaultCapacity];
+
+ this.stream = stream;
+ }
+ #endregion
+
+ ///
+ /// Reads data from stream.
+ ///
+ /// Number of bytes read
+ private int ReadFromStream()
+ {
+ // first shift the unconsumed buffer data toward the front as much as possible
+ if (getByte > 0 && putByte > getByte)
+ {
+ Array.Copy(buffer, getByte, buffer, 0, putByte - getByte);
+ }
+ putByte -= getByte;
+ getByte = 0;
+
+ // Set the target for reading, taking into account byte alignment
+ int bytes = buffer.Length - putByte;
+
+ // Read some data
+ bytes = stream.Read(buffer, putByte, bytes);
+ if (bytes <= 0)
+ throw new IOException("Failed to read from buffer.");
+
+ // Now we have to handle partial byte cases
+ putByte += bytes;
+ availBits += bytes << 3;
+ return bytes;
+ }
+
+ ///
+ /// Reset the bit stream.
+ ///
+ public void Reset()
+ {
+ getByte = 0;
+ getBit = 0;
+ putByte = 0;
+ availBits = 0;
+ }
+
+ ///
+ /// Reset the read CRC-16 value.
+ ///
+ /// The initial CRC-16 value
+ public void ResetReadCrc16(UInt16 seed)
+ {
+ readCrc16 = seed;
+ }
+
+ ///
+ /// Gets the the read CRC-16 value.
+ ///
+ public UInt16 ReadCrc16
+ {
+ get
+ {
+ return readCrc16;
+ }
+ }
+
+ ///
+ /// Test if the Bit Stream consumed bits is byte aligned.
+ ///
+ public bool IsConsumedByteAligned
+ {
+ get
+ {
+ return ((getBit & 0x7) == 0);
+ }
+ }
+
+ ///
+ /// Gets the number of bits to read to align the byte.
+ ///
+ public int BitsLeftForByteAlignment
+ {
+ get
+ {
+ return 8 - (getBit & 7);
+ }
+ }
+
+ ///
+ /// Gets the number of bytes left to read.
+ ///
+ public int InputBitsUnconsumed
+ {
+ get
+ {
+ return availBits >> 3;
+ }
+ }
+
+ ///
+ /// Skips over bits in bit stream without updating CRC.
+ ///
+ /// Number of bits to skip
+ /// Thrown if error reading from input stream
+ public void SkipBitsNoCrc(int bits)
+ {
+ if (bits > 0)
+ {
+ int bitsToAlign = getBit & 7;
+ if (bitsToAlign != 0)
+ {
+ int bitsToTake = Math.Min(8 - bitsToAlign, bits);
+ ReadRawUInt32(bitsToTake);
+ bits -= bitsToTake;
+ }
+
+ int bytesNeeded = bits / 8;
+ if (bytesNeeded > 0)
+ {
+ ReadByteBlockAlignedNoCrc(null, bytesNeeded);
+ bits %= 8;
+ }
+
+ if (bits > 0)
+ {
+ ReadRawUInt32(bits);
+ }
+ }
+ }
+
+ ///
+ /// Reads a single bit.
+ ///
+ /// The bit
+ /// Thrown if error reading input stream
+ public int ReadBit()
+ {
+ while (availBits <= 0)
+ {
+ ReadFromStream();
+ }
+
+ int val = ((buffer[getByte] & (0x80 >> getBit)) != 0) ? 1 : 0;
+ getBit++;
+ if (getBit == BitsPerByte)
+ {
+ readCrc16 = CRC16.Update(buffer[getByte], readCrc16);
+ getByte++;
+ getBit = 0;
+ }
+ availBits--;
+ totalBitsRead++;
+ return val;
+ }
+
+ ///
+ /// Read a bit into an integer value.
+ /// The bits of the input integer are shifted left and the
+ /// bit is placed into bit 0.
+ ///
+ /// The integer to shift and add read bit
+ /// The updated integer value
+ /// Thrown if error reading input stream
+ public UInt32 ReadBitToUInt32(UInt32 val)
+ {
+ while (availBits <= 0)
+ {
+ ReadFromStream();
+ }
+
+ val <<= 1;
+ val |= ((buffer[getByte] & (0x80 >> getBit)) != 0) ? 1u : 0u;
+ getBit++;
+ if (getBit == BitsPerByte)
+ {
+ readCrc16 = CRC16.Update(buffer[getByte], readCrc16);
+ getByte++;
+ getBit = 0;
+ }
+ availBits--;
+ totalBitsRead++;
+ return val;
+ }
+
+ ///
+ /// Peeks at the next bit and add it to the input integer.
+ /// The bits of the input integer are shifted left and the
+ /// bit is placed into bit 0.
+ ///
+ /// The input integer
+ /// The bit to peek at
+ /// The updated integer value
+ /// Thrown if error reading input stream
+ public UInt32 PeekBitToUInt32(UInt32 val, int bit)
+ {
+ while (availBits <= 0)
+ {
+ ReadFromStream();
+ }
+
+ val <<= 1;
+ if ((getBit + bit) >= BitsPerByte)
+ {
+ bit = (getBit + bit) % BitsPerByte;
+ val |= ((buffer[getByte + 1] & (0x80 >> bit)) != 0) ? 1u : 0u;
+ }
+ else
+ {
+ val |= ((buffer[getByte] & (0x80 >> (getBit + bit))) != 0) ? 1u : 0u;
+ }
+ return val;
+ }
+
+ ///
+ /// Read a bit into a long value.
+ /// The bits of the input integer are shifted left and the
+ /// bit is placed into bit 0.
+ ///
+ /// The long to shift and add read bit
+ /// The updated long value
+ /// Thrown if error reading input stream
+ public UInt64 ReadBitToUInt64(UInt64 val)
+ {
+ while (availBits <= 0)
+ {
+ ReadFromStream();
+ }
+
+ val <<= 1;
+ val |= ((buffer[getByte] & (0x80 >> getBit)) != 0) ? 1u : 0u;
+ getBit++;
+ if (getBit == BitsPerByte)
+ {
+ readCrc16 = CRC16.Update(buffer[getByte], readCrc16);
+ getByte++;
+ getBit = 0;
+ }
+ availBits--;
+ totalBitsRead++;
+ return val;
+ }
+
+ ///
+ /// Read bits into an unsigned integer.
+ ///
+ /// The number of bits to read
+ /// The bits as an unsigned integer
+ /// Thrown if error reading input stream
+ public UInt32 ReadRawUInt32(int bits)
+ {
+ UInt32 val = 0;
+ for (int i = 0; i < bits; i++)
+ {
+ val = ReadBitToUInt32(val);
+ }
+ return val;
+ }
+
+ ///
+ /// Peek at bits into an unsigned integer without advancing the input stream.
+ ///
+ /// The number of bits to read
+ /// The bits as an unsigned integer
+ /// Thrown if error reading input stream
+ public UInt32 PeekRawUInt32(int bits)
+ {
+ UInt32 val = 0;
+ for (int i = 0; i < bits; i++)
+ {
+ val = PeekBitToUInt32(val, i);
+ }
+ return val;
+ }
+
+ ///
+ /// Read bits into an unsigned long.
+ ///
+ /// The number of bits to read
+ /// The bits as an unsigned long
+ /// Thrown if error reading input stream
+ public UInt64 ReadRawUInt64(int bits)
+ {
+ UInt64 val = 0;
+ for (int i = 0; i < bits; i++)
+ {
+ val = ReadBitToUInt64(val);
+ }
+ return val;
+ }
+
+ ///
+ /// Read bits into an unsigned little endian integer.
+ ///
+ /// The bits as an unsigned integer
+ /// Thrown if error reading input stream
+ public UInt32 ReadRawUInt32LittleEndian()
+ {
+ UInt32 val = ReadRawUInt32(8);
+ UInt32 a = ReadRawUInt32(8);
+ UInt32 b = ReadRawUInt32(8);
+ UInt32 c = ReadRawUInt32(8);
+
+ return (val | (a << 8) | (b << 16) | (c << 24));
+ }
+
+ ///
+ /// Read a block of bytes (aligned) without updating the CRC value.
+ ///
+ /// The array to receive the bytes. If null, no bytes are returned
+ /// The number of bytes to read
+ /// Thrown if error reading input stream
+ public void ReadByteBlockAlignedNoCrc(byte[] val, int nvals)
+ {
+ int destlength = nvals;
+ while (nvals > 0)
+ {
+ int chunk = Math.Min(nvals, putByte - getByte);
+ if (chunk == 0)
+ {
+ ReadFromStream();
+ }
+ else
+ {
+ if (val != null)
+ Array.Copy(buffer, getByte, val, destlength - nvals, chunk);
+
+ nvals -= chunk;
+ getByte += chunk;
+ availBits -= (chunk << BitsPerByteLog2);
+ totalBitsRead += (chunk << BitsPerByteLog2);
+ }
+ }
+ }
+
+ ///
+ /// Read and count the number of zero bits.
+ ///
+ /// The number of zero bits read
+ /// Thrown if error reading input stream
+ public int ReadUnaryUnsigned()
+ {
+ int val = 0;
+ int bit = ReadBit();
+ while (bit == 0)
+ {
+ val++;
+ bit = ReadBit();
+ }
+ return val;
+ }
+
+ ///
+ /// Read a Rice Signal Block.
+ ///
+ /// The values to be returned
+ /// The starting position in the vals array
+ /// The number of values to return
+ /// The Rice parameter
+ /// Thrown if error reading input stream
+ public void ReadRiceSignedBlock(int[] vals, int pos, int nvals, int parameter)
+ {
+ int j, valI = 0;
+ int cbits = 0, uval = 0, msbs = 0, lsbsLeft = 0;
+ byte blurb, saveBlurb;
+ int state = 0; // 0 = getting unary MSBs, 1 = getting binary LSBs
+ int i = getByte;
+
+ long startBits = getByte * 8 + getBit;
+
+ if (nvals == 0)
+ return;
+
+ // We unroll the main loop to take care of partially consumed blurbs here.
+ if (getBit > 0)
+ {
+ saveBlurb = blurb = buffer[i];
+ cbits = getBit;
+ blurb <<= cbits;
+ while (true)
+ {
+ if (state == 0)
+ {
+ if (blurb != 0)
+ {
+ for (j = 0; (blurb & ByteTopBitOne) == 0; j++)
+ blurb <<= 1;
+ msbs += j;
+
+ // dispose of the unary end bit
+ blurb <<= 1;
+ j++;
+ cbits += j;
+ uval = 0;
+ lsbsLeft = parameter;
+ state++;
+ //totalBitsRead += msbs;
+ if (cbits == BitsPerByte)
+ {
+ cbits = 0;
+ readCrc16 = CRC16.Update(saveBlurb, readCrc16);
+ break;
+ }
+ }
+ else
+ {
+ msbs += BitsPerByte - cbits;
+ cbits = 0;
+ readCrc16 = CRC16.Update(saveBlurb, readCrc16);
+ //totalBitsRead += msbs;
+ break;
+ }
+ }
+ else
+ {
+ int availableBits = BitsPerByte - cbits;
+ if (lsbsLeft >= availableBits)
+ {
+ uval <<= availableBits;
+ uval |= ((blurb & 0xff) >> cbits);
+ cbits = 0;
+ readCrc16 = CRC16.Update(saveBlurb, readCrc16);
+ //totalBitsRead += availableBits;
+ if (lsbsLeft == availableBits)
+ {
+ // compose the value
+ uval |= (msbs << parameter);
+ if ((uval & 1) != 0)
+ vals[pos + valI++] = -((int)(uval >> 1)) - 1;
+ else
+ vals[pos + valI++] = (int)(uval >> 1);
+ if (valI == nvals)
+ break;
+ msbs = 0;
+ state = 0;
+ }
+ lsbsLeft -= availableBits;
+ break;
+ }
+ else
+ {
+ uval <<= lsbsLeft;
+ uval |= ((blurb & 0xff) >> (BitsPerByte - lsbsLeft));
+ blurb <<= lsbsLeft;
+ cbits += lsbsLeft;
+ //totalBitsRead += lsbsLeft;
+ // compose the value
+ uval |= (msbs << parameter);
+ if ((uval & 1) != 0)
+ vals[pos + valI++] = -((int)(uval >> 1)) - 1;
+ else
+ vals[pos + valI++] = (int)(uval >> 1);
+ if (valI == nvals)
+ {
+ // back up one if we exited the for loop because we
+ // read all nvals but the end came in the middle of
+ // a blurb
+ i--;
+ break;
+ }
+ msbs = 0;
+ state = 0;
+ }
+ }
+ }
+ i++;
+ getByte = i;
+ getBit = cbits;
+ //totalConsumedBits = (i << BITS_PER_BLURB_LOG2) | cbits;
+ //totalBitsRead += (BITS_PER_BLURB) | cbits;
+ }
+
+ // Now that we are blurb-aligned the logic is slightly simpler
+ while (valI < nvals)
+ {
+ for (; i < putByte && valI < nvals; i++)
+ {
+ saveBlurb = blurb = buffer[i];
+ cbits = 0;
+ while (true)
+ {
+ if (state == 0)
+ {
+ if (blurb != 0)
+ {
+ for (j = 0; (blurb & ByteTopBitOne) == 0; j++)
+ blurb <<= 1;
+ msbs += j;
+ // dispose of the unary end bit
+ blurb <<= 1;
+ j++;
+ cbits += j;
+ uval = 0;
+ lsbsLeft = parameter;
+ state++;
+ //totalBitsRead += msbs;
+ if (cbits == BitsPerByte)
+ {
+ cbits = 0;
+ readCrc16 = CRC16.Update(saveBlurb, readCrc16);
+ break;
+ }
+ }
+ else
+ {
+ msbs += BitsPerByte - cbits;
+ cbits = 0;
+ readCrc16 = CRC16.Update(saveBlurb, readCrc16);
+ //totalBitsRead += msbs;
+ break;
+ }
+ }
+ else
+ {
+ int availableBits = BitsPerByte - cbits;
+ if (lsbsLeft >= availableBits)
+ {
+ uval <<= availableBits;
+ uval |= ((blurb & 0xff) >> cbits);
+ cbits = 0;
+ readCrc16 = CRC16.Update(saveBlurb, readCrc16);
+ //totalBitsRead += availableBits;
+ if (lsbsLeft == availableBits)
+ {
+ // compose the value
+ uval |= (msbs << parameter);
+ if ((uval & 1) != 0)
+ vals[pos + valI++] = -((int)(uval >> 1)) - 1;
+ else
+ vals[pos + valI++] = (int)(uval >> 1);
+ if (valI == nvals)
+ break;
+ msbs = 0;
+ state = 0;
+ }
+ lsbsLeft -= availableBits;
+ break;
+ }
+ else
+ {
+ uval <<= lsbsLeft;
+ uval |= ((blurb & 0xff) >> (BitsPerByte - lsbsLeft));
+ blurb <<= lsbsLeft;
+ cbits += lsbsLeft;
+ //totalBitsRead += lsbsLeft;
+ // compose the value
+ uval |= (msbs << parameter);
+ if ((uval & 1) != 0)
+ vals[pos + valI++] = -((int)(uval >> 1)) - 1;
+ else
+ vals[pos + valI++] = (int)(uval >> 1);
+ if (valI == nvals)
+ {
+ // back up one if we exited the for loop because
+ // we read all nvals but the end came in the
+ // middle of a blurb
+ i--;
+ break;
+ }
+ msbs = 0;
+ state = 0;
+ }
+ }
+ }
+ }
+ getByte = i;
+ getBit = cbits;
+ //totalConsumedBits = (i << BITS_PER_BLURB_LOG2) | cbits;
+ //totalBitsRead += (BITS_PER_BLURB) | cbits;
+ if (valI < nvals)
+ {
+ long endBits = getByte * 8 + getBit;
+ totalBitsRead += (int)(endBits - startBits);
+ availBits -= (int)(endBits - startBits);
+ ReadFromStream();
+ // these must be zero because we can only get here if we got to
+ // the end of the buffer
+ i = 0;
+ startBits = getByte * 8 + getBit;
+ }
+ }
+
+ long endBits2 = getByte * 8 + getBit;
+ totalBitsRead += (int)(endBits2 - startBits);
+ availBits -= (int)(endBits2 - startBits);
+ }
+
+ ///
+ /// Read UTF8 integer.
+ /// On return, if *val == 0xffffffff then the utf-8 sequence was invalid, but
+ /// the return value will be true.
+ ///
+ /// The raw bytes read (output). If null, no bytes are returned
+ /// The raw bytes count.
+ /// The integer read
+ /// Thrown if error reading input stream
+ public UInt32 ReadUtf8UInt32(byte[] raw, out int rawCount)
+ {
+ UInt32 val, x;
+ UInt32 v = 0, i;
+
+ x = ReadRawUInt32(8);
+ rawCount = 0;
+
+ if (raw != null)
+ raw[rawCount++] = (byte)x;
+
+ if ((x & 0x80) == 0)
+ { // 0xxxxxxx
+ v = x;
+ i = 0;
+ }
+ else if (((x & 0xC0) != 0) && ((x & 0x20) == 0))
+ { // 110xxxxx
+ v = x & 0x1F;
+ i = 1;
+ }
+ else if (((x & 0xE0) != 0) && ((x & 0x10) == 0))
+ { // 1110xxxx
+ v = x & 0x0F;
+ i = 2;
+ }
+ else if (((x & 0xF0) != 0) && ((x & 0x08) == 0))
+ { // 11110xxx
+ v = x & 0x07;
+ i = 3;
+ }
+ else if (((x & 0xF8) != 0) && ((x & 0x04) == 0))
+ { // 111110xx
+ v = x & 0x03;
+ i = 4;
+ }
+ else if (((x & 0xFC) != 0) && ((x & 0x02) == 0))
+ { // 1111110x
+ v = x & 0x01;
+ i = 5;
+ }
+ else
+ {
+ val = 0xffffffff;
+ return val;
+ }
+ for (; i > 0; i--)
+ {
+ x = PeekRawUInt32(8);
+ if (((x & 0x80) == 0) || ((x & 0x40) != 0))
+ { // 10xxxxxx
+ val = 0xffffffff;
+ return val;
+ }
+ x = ReadRawUInt32(8);
+ if (raw != null)
+ raw[rawCount++] = (byte)x;
+
+ v <<= 6;
+ v |= (x & 0x3F);
+ }
+ val = v;
+ return val;
+ }
+
+ ///
+ /// Read UTF8 long.
+ /// On return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but
+ /// the return value will be true.
+ ///
+ /// The raw bytes read (output). If null, no bytes are returned
+ /// The raw bytes count.
+ /// The long read
+ /// Thrown if error reading input stream
+ public UInt64 ReadUtf8UInt64(byte[] raw, out int rawCount)
+ {
+ UInt64 val, v = 0;
+ UInt32 x, i;
+
+ x = ReadRawUInt32(8);
+ rawCount = 0;
+
+ if (raw != null)
+ raw[rawCount++] = (byte)x;
+
+ if (((x & 0x80) == 0))
+ { // 0xxxxxxx
+ v = x;
+ i = 0;
+ }
+ else if (((x & 0xC0) != 0) && ((x & 0x20) == 0))
+ { // 110xxxxx
+ v = x & 0x1F;
+ i = 1;
+ }
+ else if (((x & 0xE0) != 0) && ((x & 0x10) == 0))
+ { // 1110xxxx
+ v = x & 0x0F;
+ i = 2;
+ }
+ else if (((x & 0xF0) != 0) && ((x & 0x08) == 0))
+ { // 11110xxx
+ v = x & 0x07;
+ i = 3;
+ }
+ else if (((x & 0xF8) != 0) && ((x & 0x04) == 0))
+ { // 111110xx
+ v = x & 0x03;
+ i = 4;
+ }
+ else if (((x & 0xFC) != 0) && ((x & 0x02) == 0))
+ { // 1111110x
+ v = x & 0x01;
+ i = 5;
+ }
+ else if (((x & 0xFE) != 0) && ((x & 0x01) == 0))
+ { // 11111110
+ v = 0;
+ i = 6;
+ }
+ else
+ {
+ val = 0xffffffffffffffffL;
+ return val;
+ }
+ for (; i > 0; i--)
+ {
+ x = PeekRawUInt32(8);
+ if (((x & 0x80) == 0) || ((x & 0x40) != 0))
+ { // 10xxxxxx
+ val = 0xffffffffffffffffL;
+ return val;
+ }
+ x = ReadRawUInt32(8);
+
+ if (raw != null)
+ raw[rawCount++] = (byte)x;
+ v <<= 6;
+ v |= (x & 0x3F);
+ }
+
+ val = v;
+ return val;
+ }
+
+ ///
+ /// Gets total bytes read.
+ ///
+ public int TotalBytesRead
+ {
+ get
+ {
+ return (totalBitsRead + 7) / 8;
+ }
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/Application.cs b/Flac/Flac/Metadata/Application.cs
new file mode 100644
index 0000000..38210de
--- /dev/null
+++ b/Flac/Flac/Metadata/Application.cs
@@ -0,0 +1,39 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// Application Metadata block.
+ ///
+ public class Application : Metadata
+ {
+ private const int IdLength = 32; // bits
+
+ private byte[] id = new byte[4];
+ private byte[] data;
+
+ ///
+ /// Creates a new instance of application class.
+ ///
+ /// The BitReader
+ /// Length of the record
+ /// True if this is the last Metadata block in the chain
+ /// Thrown if error reading from BitReader
+ public Application(BitReader read, int length, bool isLast)
+ : base(isLast)
+ {
+ read.ReadByteBlockAlignedNoCrc(id, IdLength / 8);
+ length -= IdLength / 8;
+
+ if (length > 0)
+ {
+ data = new byte[length];
+ read.ReadByteBlockAlignedNoCrc(data, length);
+ }
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/CueIndex.cs b/Flac/Flac/Metadata/CueIndex.cs
new file mode 100644
index 0000000..f0e46c4
--- /dev/null
+++ b/Flac/Flac/Metadata/CueIndex.cs
@@ -0,0 +1,40 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// An entry into the cue track.
+ ///
+ public class CueIndex
+ {
+ private const int OffsetLength = 64; // bits
+ private const int NumberLength = 8; // bits
+ private const int ReservedLength = 3 * 8; // bits
+
+ ///
+ /// Offset in samples, relative to the track offset, of the index point.
+ ///
+ public UInt64 Offset { get; protected set; }
+
+ ///
+ /// The index point number.
+ ///
+ public byte Number { get; protected set; }
+
+ ///
+ /// Creates a new instance of CueIndex.
+ ///
+ /// The BitReader
+ /// Thrown if error reading from BitReader.
+ public CueIndex(BitReader read)
+ {
+ Offset = read.ReadRawUInt64(OffsetLength);
+ Number = (byte)read.ReadRawUInt32(NumberLength);
+ read.SkipBitsNoCrc(ReservedLength);
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/CueSheet.cs b/Flac/Flac/Metadata/CueSheet.cs
new file mode 100644
index 0000000..5c53935
--- /dev/null
+++ b/Flac/Flac/Metadata/CueSheet.cs
@@ -0,0 +1,137 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// CueSheet Metadata block.
+ ///
+ public class CueSheet : Metadata
+ {
+ #region Constants
+ private const int MediaCatalogNumberLength = 128 * 8; // bits
+ private const int LeadInLength = 64; // bits
+ private const int IsCdLength = 1; // bits
+ private const int ReservedLength = 7 + 258 * 8; // bits
+ private const int TrackCountLength = 8; // bits
+ #endregion
+
+ ///
+ /// Media catalog number.
+ /// in ASCII printable characters 0x20-0x7e. In
+ /// general, the media catalog number may be 0 to 128 bytes long; any
+ /// unused characters should be right-padded with NUL characters.
+ ///
+ protected byte[] mediaCatalogNumber = new byte[129];
+
+ ///
+ /// The number of lead-in samples.
+ ///
+ protected UInt64 leadIn = 0;
+
+ ///
+ /// True if CueSheet corresponds to a Compact Disc, else false
+ ///
+ protected bool isCD = false;
+
+ ///
+ /// The number of tracks.
+ ///
+ protected UInt32 trackCount = 0;
+
+ ///
+ /// NULL if num_tracks == 0, else pointer to array of tracks.
+ ///
+ protected CueTrack[] tracks;
+
+ ///
+ /// Creates a new instance of CueSheet.
+ ///
+ /// The BitReader
+ /// Length of the record
+ /// True if this is the last Metadata block in the chain
+ /// Thrown if error reading from BitReader
+ public CueSheet(BitReader read, int length, bool isLast)
+ : base(isLast)
+ {
+ // Read fields
+ read.ReadByteBlockAlignedNoCrc(mediaCatalogNumber, MediaCatalogNumberLength / 8);
+ leadIn = read.ReadRawUInt64(LeadInLength);
+ isCD = (read.ReadRawUInt32(IsCdLength) != 0);
+ read.SkipBitsNoCrc(ReservedLength);
+ trackCount = read.ReadRawUInt32(TrackCountLength);
+
+ // Read cue tracks
+ if (trackCount > 0)
+ {
+ tracks = new CueTrack[trackCount];
+ for (int i = 0; i < trackCount; i++)
+ tracks[i] = new CueTrack(read);
+ }
+ }
+
+ ///
+ /// Verifies the Cue Sheet.
+ ///
+ /// True for check CD subset
+ /// Thrown if invalid Cue Sheet
+ public void IsLegal(bool checkCdDaSubset)
+ {
+
+ if (checkCdDaSubset)
+ {
+ if (leadIn < 2 * 44100)
+ throw new ValidationException("CD-DA cue sheet must have a lead-in length of at least 2 seconds");
+
+ if (leadIn % 588 != 0)
+ throw new ValidationException("CD-DA cue sheet lead-in length must be evenly divisible by 588 samples");
+ }
+
+ if (trackCount == 0)
+ throw new ValidationException("cue sheet must have at least one track (the lead-out)");
+
+ if (checkCdDaSubset && tracks[trackCount - 1].Number != 170)
+ throw new ValidationException("CD-DA cue sheet must have a lead-out track number 170 (0xAA)");
+
+ for (int i = 0; i < trackCount; i++)
+ {
+ if (tracks[i].Number == 0)
+ throw new ValidationException("cue sheet may not have a track number 0");
+
+ if (checkCdDaSubset)
+ {
+ if (!((tracks[i].Number >= 1 && tracks[i].Number <= 99)
+ || tracks[i].Number == 170))
+ throw new ValidationException("CD-DA cue sheet track number must be 1-99 or 170");
+ }
+
+ if (checkCdDaSubset && tracks[i].Offset % 588 != 0)
+ throw new ValidationException("CD-DA cue sheet track offset must be evenly divisible by 588 samples");
+
+ if (i < trackCount - 1)
+ {
+ if (tracks[i].IndicesCount == 0)
+ throw new ValidationException("cue sheet track must have at least one index point");
+
+ if (tracks[i].Indices[0].Number > 1)
+ throw new ValidationException("cue sheet track's first index number must be 0 or 1");
+ }
+
+ for (int j = 0; j < tracks[i].IndicesCount; j++)
+ {
+ if (checkCdDaSubset && tracks[i].Indices[j].Offset % 588 != 0)
+ throw new ValidationException("CD-DA cue sheet track index offset must be evenly divisible by 588 samples");
+
+ if (j > 0)
+ {
+ if (tracks[i].Indices[j].Number != tracks[i].Indices[j - 1].Number + 1)
+ throw new ValidationException("cue sheet track index numbers must increase by 1");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/CueTrack.cs b/Flac/Flac/Metadata/CueTrack.cs
new file mode 100644
index 0000000..eece785
--- /dev/null
+++ b/Flac/Flac/Metadata/CueTrack.cs
@@ -0,0 +1,85 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// An entry into the cue sheet.
+ ///
+ public class CueTrack
+ {
+ #region Constants
+ private const int OffsetLength = 64;
+ private const int NumberLength = 8;
+ private const int IsrcLength = 12 * 8;
+ private const int TypeLength = 1;
+ private const int PreEmphasisLength = 1;
+ private const int ReservedLength = 6 + 13 * 8;
+ private const int IndicesCountLength = 8;
+ #endregion
+
+ ///
+ /// Track offset in samples, relative to the beginning of the FLAC audio stream.
+ ///
+ public UInt64 Offset { get; protected set; }
+
+ ///
+ /// The track number.
+ ///
+ public byte Number { get; protected set; }
+
+ ///
+ /// Track ISRC. This is a 12-digit alphanumeric code plus a trailing '\0'
+ ///
+ protected byte[] isrc = new byte[13];
+
+ ///
+ /// The track type: 0 for audio, 1 for non-audio.
+ ///
+ protected UInt32 type;
+
+ ///
+ /// The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis.
+ ///
+ protected UInt32 preEmphasis;
+
+ ///
+ /// The number of track index points.
+ ///
+ public byte IndicesCount { get; protected set; }
+
+ ///
+ /// NULL if num_indices == 0, else pointer to array of index points.
+ ///
+ public CueIndex[] Indices { get; protected set; }
+
+ ///
+ /// Creates new instance of CueTrack.
+ ///
+ /// The BitReader
+ /// Thrown if error reading from BitReader
+ public CueTrack(BitReader read)
+ {
+ // Read fields
+ Offset = read.ReadRawUInt64(OffsetLength);
+ Number = (byte)read.ReadRawUInt32(NumberLength);
+ read.ReadByteBlockAlignedNoCrc(isrc, IsrcLength / 8);
+ type = read.ReadRawUInt32(TypeLength);
+ preEmphasis = read.ReadRawUInt32(PreEmphasisLength);
+ read.SkipBitsNoCrc(ReservedLength);
+ IndicesCount = (byte)read.ReadRawUInt32(IndicesCountLength);
+
+ // Read indices
+ if (IndicesCount > 0)
+ {
+ Indices = new CueIndex[IndicesCount];
+
+ for (int i = 0; i < IndicesCount; i++)
+ Indices[i] = new CueIndex(read);
+ }
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/Metadata.cs b/Flac/Flac/Metadata/Metadata.cs
new file mode 100644
index 0000000..0a7d4db
--- /dev/null
+++ b/Flac/Flac/Metadata/Metadata.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// Metadata types.
+ ///
+ public enum MetadataType
+ {
+ StreamInfo = 0,
+ Padding = 1,
+ Application = 2,
+ SeekTable = 3,
+ VorbisComment = 4,
+ CueSheet = 5,
+ Picture = 6,
+ Undefined = 7
+ }
+
+ ///
+ /// Root class for all Metadata subclasses.
+ ///
+ public abstract class Metadata
+ {
+ ///
+ /// Metadata IsLast field length (bits).
+ ///
+ public const int StreamMetadataIsLastLength = 1;
+
+ ///
+ /// Metadata type field length (bits).
+ ///
+ public const int StreamMetadataTypeLength = 7;
+
+ ///
+ /// Metadata length field length (bits).
+ ///
+ public const int StreamMetadataLengthLength = 24;
+
+ ///
+ /// Test if this is the last metadata block.
+ ///
+ public bool IsLast { get; protected set; }
+
+ ///
+ /// Creates a new instance of Metadata class.
+ ///
+ /// True if this is the last metadata block.
+ public Metadata(bool isLast)
+ {
+ IsLast = isLast;
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/Padding.cs b/Flac/Flac/Metadata/Padding.cs
new file mode 100644
index 0000000..6de7d8b
--- /dev/null
+++ b/Flac/Flac/Metadata/Padding.cs
@@ -0,0 +1,30 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// Padding Metadata block.
+ ///
+ public class Padding : Metadata
+ {
+ private int length;
+
+ ///
+ /// Creates a new instance of Padding.
+ ///
+ /// The BitReader
+ /// Length of the record
+ /// True if this is the last Metadata block in the chain
+ /// Thrown if error reading from BitReader
+ public Padding(BitReader read, int length, bool isLast)
+ : base(isLast)
+ {
+ this.length = length;
+ read.ReadByteBlockAlignedNoCrc(null, length);
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/Picture.cs b/Flac/Flac/Metadata/Picture.cs
new file mode 100644
index 0000000..77d0fae
--- /dev/null
+++ b/Flac/Flac/Metadata/Picture.cs
@@ -0,0 +1,95 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// Picture Metadata block.
+ ///
+ public class Picture : Metadata
+ {
+ #region Constants
+ private const int PictureTypeLength = 32;
+ private const int MimeTypeByteCountLength = 32;
+ private const int DescriptionByteCountLength = 32;
+ private const int PicturePixelWidthLength = 32;
+ private const int PicturePixelHeightLength = 32;
+ private const int PictureBitsPerPixelLength = 32;
+ private const int PictureColorCountLength = 32;
+ private const int PictureByteCountLength = 32;
+ #endregion
+
+ private UInt32 pictureType;
+ private string mimeType;
+ private string description;
+ private int picPixelWidth;
+ private int picPixelHeight;
+ private int picBitsPerPixel;
+ private int picColorCount;
+ private byte[] image;
+
+ ///
+ /// Creates a new instance of Picture.
+ ///
+ /// The BitReader
+ /// Length of the record
+ /// True if this is the last Metadata block in the chain
+ /// Thrown if error reading from BitReader
+ public Picture(BitReader read, int length, bool isLast)
+ : base(isLast)
+ {
+ int usedbits = 0;
+
+ // Read picture type
+ pictureType = read.ReadRawUInt32(PictureTypeLength);
+ usedbits += PictureTypeLength;
+
+ // Read mime type length
+ int mimeTypeByteCount = (int)read.ReadRawUInt32(MimeTypeByteCountLength);
+ usedbits += MimeTypeByteCountLength;
+
+ // Read mime type
+ byte[] data = new byte[mimeTypeByteCount];
+ read.ReadByteBlockAlignedNoCrc(data, mimeTypeByteCount);
+ usedbits += mimeTypeByteCount * 8;
+ mimeType = UTF8Encoding.UTF8.GetString(data, 0, mimeTypeByteCount);
+
+ // Description string length
+ int descriptionByteCount = (int)read.ReadRawUInt32(DescriptionByteCountLength);
+ usedbits += DescriptionByteCountLength;
+
+ // Description string
+ data = new byte[descriptionByteCount];
+ read.ReadByteBlockAlignedNoCrc(data, descriptionByteCount);
+ usedbits += descriptionByteCount * 8;
+ description = UTF8Encoding.UTF8.GetString(data, 0, descriptionByteCount);
+
+ // Picture stuff
+ picPixelWidth = (int)read.ReadRawUInt32(PicturePixelWidthLength);
+ picPixelHeight = (int)read.ReadRawUInt32(PicturePixelHeightLength);
+ usedbits += PicturePixelWidthLength + PicturePixelHeightLength;
+
+ picBitsPerPixel = (int)read.ReadRawUInt32(PictureBitsPerPixelLength);
+ usedbits += PictureBitsPerPixelLength;
+
+ picColorCount = (int)read.ReadRawUInt32(PictureColorCountLength);
+ usedbits += PictureColorCountLength;
+
+ // Read data size
+ int picByteCount = (int)read.ReadRawUInt32(PictureByteCountLength);
+ usedbits += PictureByteCountLength;
+
+ // Read data
+ image = new byte[picByteCount];
+ read.ReadByteBlockAlignedNoCrc(image, picByteCount);
+ usedbits += picByteCount * 8;
+
+ // Skip the rest of the block
+ length -= (usedbits / 8);
+ read.ReadByteBlockAlignedNoCrc(null, length);
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/SeekPoint.cs b/Flac/Flac/Metadata/SeekPoint.cs
new file mode 100644
index 0000000..307e68d
--- /dev/null
+++ b/Flac/Flac/Metadata/SeekPoint.cs
@@ -0,0 +1,62 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// An entry into the seek table.
+ ///
+ public class SeekPoint
+ {
+ #region Constants
+ private const int SampleNumberLength = 64;
+ private const int StreamOffsetLength = 64;
+ private const int FrameSamplesLength = 16;
+ #endregion
+
+ ///
+ /// The sample number of the target frame.
+ ///
+ public long SampleNumber { get; private set; }
+
+ ///
+ /// The offset, in bytes, of the target frame with
+ /// respect to beginning of the first frame.
+ ///
+ public long StreamOffset { get; set; }
+
+ ///
+ /// The number of samples in the target frame.
+ ///
+ public int FrameSamples { get; private set; }
+
+ ///
+ /// Creates a new instance of SeekPoint.
+ ///
+ /// The BitReader
+ /// Thrown if error reading from BitReader
+ public SeekPoint(BitReader read)
+ {
+ SampleNumber = (long)read.ReadRawUInt64(SampleNumberLength);
+ StreamOffset = (long)read.ReadRawUInt64(StreamOffsetLength);
+ FrameSamples = (int)read.ReadRawUInt32(FrameSamplesLength);
+ }
+
+ ///
+ /// Creates a new instance of SeekPoint.
+ ///
+ /// The sample number of the target frame
+ /// The offset, in bytes, of the target frame with
+ /// respect to beginning of the first frame
+ /// The number of samples in the target frame
+ public SeekPoint(long sampleNumber, long streamOffset, int frameSamples)
+ {
+ SampleNumber = sampleNumber;
+ StreamOffset = streamOffset;
+ FrameSamples = frameSamples;
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/SeekTable.cs b/Flac/Flac/Metadata/SeekTable.cs
new file mode 100644
index 0000000..32487cb
--- /dev/null
+++ b/Flac/Flac/Metadata/SeekTable.cs
@@ -0,0 +1,117 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// SeekTable metadata block.
+ ///
+ public class SeekTable : Metadata, IEnumerable
+ {
+ #region Constants
+ private const int LengthBytes = 18;
+ #endregion
+
+ private SeekPoint[] points;
+
+ ///
+ /// Gets the seek point count.
+ ///
+ public int Length
+ {
+ get
+ {
+ if (points != null)
+ return points.Length;
+
+ return 0;
+ }
+ }
+
+ ///
+ /// Gets length in bytes (metadata block size).
+ ///
+ public int RawLength
+ {
+ get
+ {
+ if (points != null)
+ return points.Length * LengthBytes;
+
+ return 0;
+ }
+ }
+
+ ///
+ /// Gets iterator for this container
+ ///
+ /// The iterator
+ public IEnumerator GetEnumerator()
+ {
+ foreach (var i in points)
+ yield return i;
+ }
+
+ ///
+ /// Gets iterator for this container
+ ///
+ /// The iterator
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return points.GetEnumerator();
+ }
+
+ ///
+ /// Gets a seek point.
+ ///
+ /// Index of seek point.
+ ///
+ public SeekPoint this[int index]
+ {
+ get
+ {
+ return points[index];
+ }
+ }
+
+
+ ///
+ /// Creates a new instance of SeekTable.
+ ///
+ /// The BitReader
+ /// Length of the record
+ /// True if this is the last Metadata block in the chain
+ /// Thrown if error reading from BitReader
+ public SeekTable(BitReader read, int length, bool isLast)
+ : base(isLast)
+ {
+ // Calculate seek point count
+ int pointCount = length / LengthBytes;
+
+ // Create seek points
+ points = new SeekPoint[pointCount];
+ for (int i = 0; i < points.Length; i++)
+ points[i] = new SeekPoint(read);
+
+ // Skip rest of bytes
+ length -= pointCount * LengthBytes;
+ if (length > 0)
+ read.ReadByteBlockAlignedNoCrc(null, length);
+ }
+
+ ///
+ /// Creates a new instance of SeekTable.
+ ///
+ /// Seek points
+ /// True if this is the last Metadata block in the chain
+ public SeekTable(SeekPoint[] points, bool isLast)
+ : base(isLast)
+ {
+ this.points = points;
+ }
+
+ }
+}
diff --git a/Flac/Flac/Metadata/StreamInfo.cs b/Flac/Flac/Metadata/StreamInfo.cs
new file mode 100644
index 0000000..d1307a6
--- /dev/null
+++ b/Flac/Flac/Metadata/StreamInfo.cs
@@ -0,0 +1,147 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// StreamInfo Metadata block.
+ ///
+ public class StreamInfo : Metadata
+ {
+ #region Constants
+ private const int MinBlockSizeLength = 16; // bits
+ private const int MaxBlockSizeLength = 16; // bits
+ private const int MinFrameSizeLength = 24; // bits
+ private const int MaxFrameSizeLength = 24; // bits
+ private const int SampleRateLength = 20; // bits
+ private const int ChannelsLength = 3; // bits
+ private const int BitsPerSampleLength = 5; // bits
+ private const int TotalSamplesLength = 36; // bits
+ private const int Md5SumLength = 128; // bits
+ #endregion
+
+ private byte[] md5Sum = new byte[16];
+
+ ///
+ /// Gets the MinBlockSize
+ ///
+ public UInt32 MinBlockSize { get; private set; }
+
+ ///
+ /// Gets the MaxBlockSize
+ ///
+ public UInt32 MaxBlockSize { get; private set; }
+
+ ///
+ /// Gets the MinFrameSize
+ ///
+ public UInt32 MinFrameSize { get; private set; }
+
+ ///
+ /// Gets the MaxFrameSize
+ ///
+ public UInt32 MaxFrameSize { get; private set; }
+
+ ///
+ /// Gets the sample rate.
+ ///
+ public UInt32 SampleRate { get; private set; }
+
+ ///
+ /// Gets the number of channels.
+ ///
+ public UInt32 Channels { get; private set; }
+
+ ///
+ /// Gets the number of bits per sample.
+ ///
+ public UInt32 BitsPerSample { get; private set; }
+
+ ///
+ /// Gets or sets the total number of samples.
+ ///
+ public UInt64 TotalSamples { get; set; }
+
+ ///
+ /// Creates a new instance of stream info class.
+ ///
+ /// The BitReader
+ /// Length of the record
+ /// True if this is the last Metadata block in the chain.
+ /// Thrown if error reading from InputBitStream
+ public StreamInfo(BitReader read, int length, bool isLast)
+ : base(isLast)
+ {
+ int usedBits = 0;
+
+ MinBlockSize = read.ReadRawUInt32(MinBlockSizeLength);
+ usedBits += MinBlockSizeLength;
+
+ MaxBlockSize = read.ReadRawUInt32(MaxBlockSizeLength);
+ usedBits += MaxBlockSizeLength;
+
+ MinFrameSize = read.ReadRawUInt32(MinFrameSizeLength);
+ usedBits += MinFrameSizeLength;
+
+ MaxFrameSize = read.ReadRawUInt32(MaxFrameSizeLength);
+ usedBits += MaxFrameSizeLength;
+
+ SampleRate = read.ReadRawUInt32(SampleRateLength);
+ usedBits += SampleRateLength;
+
+ Channels = read.ReadRawUInt32(ChannelsLength) + 1;
+ usedBits += ChannelsLength;
+
+ BitsPerSample = read.ReadRawUInt32(BitsPerSampleLength) + 1;
+ usedBits += BitsPerSampleLength;
+
+ TotalSamples = read.ReadRawUInt64(TotalSamplesLength);
+ usedBits += TotalSamplesLength;
+
+ read.ReadByteBlockAlignedNoCrc(md5Sum, Md5SumLength / 8);
+ usedBits += Md5SumLength;
+
+ // Skip the rest of the block
+ length -= (usedBits / 8);
+ read.ReadByteBlockAlignedNoCrc(null, length);
+ }
+
+ ///
+ /// Gets the metadata block size.
+ ///
+ public int Length
+ {
+ get
+ {
+ int bits = MinBlockSizeLength
+ + MaxBlockSizeLength
+ + MinFrameSizeLength
+ + MaxFrameSizeLength
+ + SampleRateLength
+ + ChannelsLength
+ + BitsPerSampleLength
+ + TotalSamplesLength
+ + Md5SumLength;
+
+ return (bits + 7) / 8;
+ }
+ }
+
+ ///
+ /// Checks for compatible StreamInfo.
+ /// Checks if SampleRate, Channels, and BitsPerSample are equal
+ ///
+ /// The StreamInfo block to check
+ /// True if this and info are compatable
+ public bool Compatible (StreamInfo info)
+ {
+ if (SampleRate != info.SampleRate) return false;
+ if (Channels != info.Channels) return false;
+ if (BitsPerSample != info.BitsPerSample) return false;
+ return true;
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/Unknown.cs b/Flac/Flac/Metadata/Unknown.cs
new file mode 100644
index 0000000..72d8e69
--- /dev/null
+++ b/Flac/Flac/Metadata/Unknown.cs
@@ -0,0 +1,33 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// Unknown metadata block
+ ///
+ public class Unknown : Metadata
+ {
+ private byte[] data;
+
+ ///
+ /// Creates a new instance of Unknown.
+ ///
+ /// The BitReader
+ /// Length of the record
+ /// True if this is the last Metadata block in the chain
+ /// Thrown if error reading from BitReader
+ public Unknown(BitReader read, int length, bool isLast)
+ : base(isLast)
+ {
+ if (length > 0)
+ {
+ data = new byte[length];
+ read.ReadByteBlockAlignedNoCrc(data, length);
+ }
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/ValidationException.cs b/Flac/Flac/Metadata/ValidationException.cs
new file mode 100644
index 0000000..1007be3
--- /dev/null
+++ b/Flac/Flac/Metadata/ValidationException.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// Metadata format validation exception
+ ///
+ public class ValidationException : Exception
+ {
+ ///
+ /// Creates a new instance of bad header exception.
+ ///
+ public ValidationException()
+ : base()
+ {
+ }
+
+ ///
+ /// Creates a new instance of bad header exception with specified message.
+ ///
+ /// The message
+ public ValidationException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Creates a new instance of bad header exception with specified message
+ /// and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The message
+ /// The inner exception
+ public ValidationException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/Flac/Flac/Metadata/VorbisComment.cs b/Flac/Flac/Metadata/VorbisComment.cs
new file mode 100644
index 0000000..f5ed7a3
--- /dev/null
+++ b/Flac/Flac/Metadata/VorbisComment.cs
@@ -0,0 +1,75 @@
+using Flac.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Metadata
+{
+ ///
+ /// Vorbis comment metadata block.
+ ///
+ public class VorbisComment : Metadata, IEnumerable>
+ {
+ private string vendor;
+ public Dictionary Comments { get; private set; }
+
+ ///
+ /// Creates a new instance of VorbisComment.
+ ///
+ /// The BitReader
+ /// Length of the record
+ /// True if this is the last Metadata block in the chain
+ /// Thrown if error reading from BitReader
+ public VorbisComment(BitReader read, int length, bool isLast)
+ : base(isLast)
+ {
+ byte[] data;
+
+ // Read vendor string
+ int vendorLength = (int)read.ReadRawUInt32LittleEndian();
+ data = new byte[vendorLength];
+ read.ReadByteBlockAlignedNoCrc(data, vendorLength);
+
+ vendor = UTF8Encoding.UTF8.GetString(data, 0, vendorLength);
+
+ // Read comments
+ int commentsCount = (int)read.ReadRawUInt32LittleEndian();
+ Comments = new Dictionary(commentsCount);
+
+ for (int i = 0; i < commentsCount; i++)
+ {
+ // Get comment bytes
+ int len = (int)read.ReadRawUInt32LittleEndian();
+ data = new byte[len];
+ read.ReadByteBlockAlignedNoCrc(data, len);
+
+ // Obtain string
+ string str = UTF8Encoding.UTF8.GetString(data, 0, len);
+ int equal = str.IndexOf('=');
+
+ // Add comment
+ if (equal > 0)
+ this.Comments.Add(str.Substring(0, equal), str.Substring(equal));
+ }
+ }
+
+ ///
+ /// Gets iterator for this container
+ ///
+ /// The iterator
+ public IEnumerator> GetEnumerator()
+ {
+ return Comments.GetEnumerator();
+ }
+
+ ///
+ /// Gets iterator for this container
+ ///
+ /// The iterator
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return ((System.Collections.IEnumerable)Comments).GetEnumerator();
+ }
+ }
+}
diff --git a/Flac/Flac/Properties/AssemblyInfo.cs b/Flac/Flac/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7436e1d
--- /dev/null
+++ b/Flac/Flac/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Flac")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Flac")]
+[assembly: AssemblyCopyright("Copyright © 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("bf99ae12-eb9b-46c7-9ebe-1e736bc674f4")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Flac/Flac/Util/CRC16.cs b/Flac/Flac/Util/CRC16.cs
new file mode 100644
index 0000000..461a489
--- /dev/null
+++ b/Flac/Flac/Util/CRC16.cs
@@ -0,0 +1,319 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Util
+{
+ ///
+ /// Utility class to calculate 16-bit CRC.
+ ///
+ public static class CRC16
+ {
+ #region private static UInt16[] Crc16Table
+
+ // CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0
+ private static UInt16[] Crc16Table =
+ new UInt16[] {
+ (UInt16) 0x0000,
+ (UInt16) 0x8005,
+ (UInt16) 0x800f,
+ (UInt16) 0x000a,
+ (UInt16) 0x801b,
+ (UInt16) 0x001e,
+ (UInt16) 0x0014,
+ (UInt16) 0x8011,
+ (UInt16) 0x8033,
+ (UInt16) 0x0036,
+ (UInt16) 0x003c,
+ (UInt16) 0x8039,
+ (UInt16) 0x0028,
+ (UInt16) 0x802d,
+ (UInt16) 0x8027,
+ (UInt16) 0x0022,
+ (UInt16) 0x8063,
+ (UInt16) 0x0066,
+ (UInt16) 0x006c,
+ (UInt16) 0x8069,
+ (UInt16) 0x0078,
+ (UInt16) 0x807d,
+ (UInt16) 0x8077,
+ (UInt16) 0x0072,
+ (UInt16) 0x0050,
+ (UInt16) 0x8055,
+ (UInt16) 0x805f,
+ (UInt16) 0x005a,
+ (UInt16) 0x804b,
+ (UInt16) 0x004e,
+ (UInt16) 0x0044,
+ (UInt16) 0x8041,
+ (UInt16) 0x80c3,
+ (UInt16) 0x00c6,
+ (UInt16) 0x00cc,
+ (UInt16) 0x80c9,
+ (UInt16) 0x00d8,
+ (UInt16) 0x80dd,
+ (UInt16) 0x80d7,
+ (UInt16) 0x00d2,
+ (UInt16) 0x00f0,
+ (UInt16) 0x80f5,
+ (UInt16) 0x80ff,
+ (UInt16) 0x00fa,
+ (UInt16) 0x80eb,
+ (UInt16) 0x00ee,
+ (UInt16) 0x00e4,
+ (UInt16) 0x80e1,
+ (UInt16) 0x00a0,
+ (UInt16) 0x80a5,
+ (UInt16) 0x80af,
+ (UInt16) 0x00aa,
+ (UInt16) 0x80bb,
+ (UInt16) 0x00be,
+ (UInt16) 0x00b4,
+ (UInt16) 0x80b1,
+ (UInt16) 0x8093,
+ (UInt16) 0x0096,
+ (UInt16) 0x009c,
+ (UInt16) 0x8099,
+ (UInt16) 0x0088,
+ (UInt16) 0x808d,
+ (UInt16) 0x8087,
+ (UInt16) 0x0082,
+ (UInt16) 0x8183,
+ (UInt16) 0x0186,
+ (UInt16) 0x018c,
+ (UInt16) 0x8189,
+ (UInt16) 0x0198,
+ (UInt16) 0x819d,
+ (UInt16) 0x8197,
+ (UInt16) 0x0192,
+ (UInt16) 0x01b0,
+ (UInt16) 0x81b5,
+ (UInt16) 0x81bf,
+ (UInt16) 0x01ba,
+ (UInt16) 0x81ab,
+ (UInt16) 0x01ae,
+ (UInt16) 0x01a4,
+ (UInt16) 0x81a1,
+ (UInt16) 0x01e0,
+ (UInt16) 0x81e5,
+ (UInt16) 0x81ef,
+ (UInt16) 0x01ea,
+ (UInt16) 0x81fb,
+ (UInt16) 0x01fe,
+ (UInt16) 0x01f4,
+ (UInt16) 0x81f1,
+ (UInt16) 0x81d3,
+ (UInt16) 0x01d6,
+ (UInt16) 0x01dc,
+ (UInt16) 0x81d9,
+ (UInt16) 0x01c8,
+ (UInt16) 0x81cd,
+ (UInt16) 0x81c7,
+ (UInt16) 0x01c2,
+ (UInt16) 0x0140,
+ (UInt16) 0x8145,
+ (UInt16) 0x814f,
+ (UInt16) 0x014a,
+ (UInt16) 0x815b,
+ (UInt16) 0x015e,
+ (UInt16) 0x0154,
+ (UInt16) 0x8151,
+ (UInt16) 0x8173,
+ (UInt16) 0x0176,
+ (UInt16) 0x017c,
+ (UInt16) 0x8179,
+ (UInt16) 0x0168,
+ (UInt16) 0x816d,
+ (UInt16) 0x8167,
+ (UInt16) 0x0162,
+ (UInt16) 0x8123,
+ (UInt16) 0x0126,
+ (UInt16) 0x012c,
+ (UInt16) 0x8129,
+ (UInt16) 0x0138,
+ (UInt16) 0x813d,
+ (UInt16) 0x8137,
+ (UInt16) 0x0132,
+ (UInt16) 0x0110,
+ (UInt16) 0x8115,
+ (UInt16) 0x811f,
+ (UInt16) 0x011a,
+ (UInt16) 0x810b,
+ (UInt16) 0x010e,
+ (UInt16) 0x0104,
+ (UInt16) 0x8101,
+ (UInt16) 0x8303,
+ (UInt16) 0x0306,
+ (UInt16) 0x030c,
+ (UInt16) 0x8309,
+ (UInt16) 0x0318,
+ (UInt16) 0x831d,
+ (UInt16) 0x8317,
+ (UInt16) 0x0312,
+ (UInt16) 0x0330,
+ (UInt16) 0x8335,
+ (UInt16) 0x833f,
+ (UInt16) 0x033a,
+ (UInt16) 0x832b,
+ (UInt16) 0x032e,
+ (UInt16) 0x0324,
+ (UInt16) 0x8321,
+ (UInt16) 0x0360,
+ (UInt16) 0x8365,
+ (UInt16) 0x836f,
+ (UInt16) 0x036a,
+ (UInt16) 0x837b,
+ (UInt16) 0x037e,
+ (UInt16) 0x0374,
+ (UInt16) 0x8371,
+ (UInt16) 0x8353,
+ (UInt16) 0x0356,
+ (UInt16) 0x035c,
+ (UInt16) 0x8359,
+ (UInt16) 0x0348,
+ (UInt16) 0x834d,
+ (UInt16) 0x8347,
+ (UInt16) 0x0342,
+ (UInt16) 0x03c0,
+ (UInt16) 0x83c5,
+ (UInt16) 0x83cf,
+ (UInt16) 0x03ca,
+ (UInt16) 0x83db,
+ (UInt16) 0x03de,
+ (UInt16) 0x03d4,
+ (UInt16) 0x83d1,
+ (UInt16) 0x83f3,
+ (UInt16) 0x03f6,
+ (UInt16) 0x03fc,
+ (UInt16) 0x83f9,
+ (UInt16) 0x03e8,
+ (UInt16) 0x83ed,
+ (UInt16) 0x83e7,
+ (UInt16) 0x03e2,
+ (UInt16) 0x83a3,
+ (UInt16) 0x03a6,
+ (UInt16) 0x03ac,
+ (UInt16) 0x83a9,
+ (UInt16) 0x03b8,
+ (UInt16) 0x83bd,
+ (UInt16) 0x83b7,
+ (UInt16) 0x03b2,
+ (UInt16) 0x0390,
+ (UInt16) 0x8395,
+ (UInt16) 0x839f,
+ (UInt16) 0x039a,
+ (UInt16) 0x838b,
+ (UInt16) 0x038e,
+ (UInt16) 0x0384,
+ (UInt16) 0x8381,
+ (UInt16) 0x0280,
+ (UInt16) 0x8285,
+ (UInt16) 0x828f,
+ (UInt16) 0x028a,
+ (UInt16) 0x829b,
+ (UInt16) 0x029e,
+ (UInt16) 0x0294,
+ (UInt16) 0x8291,
+ (UInt16) 0x82b3,
+ (UInt16) 0x02b6,
+ (UInt16) 0x02bc,
+ (UInt16) 0x82b9,
+ (UInt16) 0x02a8,
+ (UInt16) 0x82ad,
+ (UInt16) 0x82a7,
+ (UInt16) 0x02a2,
+ (UInt16) 0x82e3,
+ (UInt16) 0x02e6,
+ (UInt16) 0x02ec,
+ (UInt16) 0x82e9,
+ (UInt16) 0x02f8,
+ (UInt16) 0x82fd,
+ (UInt16) 0x82f7,
+ (UInt16) 0x02f2,
+ (UInt16) 0x02d0,
+ (UInt16) 0x82d5,
+ (UInt16) 0x82df,
+ (UInt16) 0x02da,
+ (UInt16) 0x82cb,
+ (UInt16) 0x02ce,
+ (UInt16) 0x02c4,
+ (UInt16) 0x82c1,
+ (UInt16) 0x8243,
+ (UInt16) 0x0246,
+ (UInt16) 0x024c,
+ (UInt16) 0x8249,
+ (UInt16) 0x0258,
+ (UInt16) 0x825d,
+ (UInt16) 0x8257,
+ (UInt16) 0x0252,
+ (UInt16) 0x0270,
+ (UInt16) 0x8275,
+ (UInt16) 0x827f,
+ (UInt16) 0x027a,
+ (UInt16) 0x826b,
+ (UInt16) 0x026e,
+ (UInt16) 0x0264,
+ (UInt16) 0x8261,
+ (UInt16) 0x0220,
+ (UInt16) 0x8225,
+ (UInt16) 0x822f,
+ (UInt16) 0x022a,
+ (UInt16) 0x823b,
+ (UInt16) 0x023e,
+ (UInt16) 0x0234,
+ (UInt16) 0x8231,
+ (UInt16) 0x8213,
+ (UInt16) 0x0216,
+ (UInt16) 0x021c,
+ (UInt16) 0x8219,
+ (UInt16) 0x0208,
+ (UInt16) 0x820d,
+ (UInt16) 0x8207,
+ (UInt16) 0x0202
+ };
+ #endregion
+
+ ///
+ /// Update the CRC with the byte data.
+ ///
+ /// The byte data
+ /// The starting CRC value
+ /// The updated CRC value
+ public static UInt16 Update(byte data, UInt16 crc)
+ {
+ crc = (UInt16)((crc << 8) ^ Crc16Table[((crc >> 8) ^ data) & 0xff]);
+ return crc;
+ }
+
+ ///
+ /// Update the CRC with the byte array data.
+ ///
+ /// The byte array data
+ /// The byte array length
+ /// The starting CRC value
+ /// The updated CRC value
+ public static UInt16 UpdateBlock(byte[] data, int len, UInt16 crc)
+ {
+ for (int i = 0; i < len; i++)
+ crc = (UInt16)((crc << 8) ^ Crc16Table[(crc >> 8) ^ data[i]]);
+ return crc;
+ }
+
+ ///
+ /// Calculate the CRC over a byte array.
+ ///
+ /// The byte data
+ /// The byte array length
+ /// The calculated CRC value
+ public static UInt16 Calculate(byte[] data, int len)
+ {
+ UInt16 crc = 0;
+
+ for (int i = 0; i < len; i++)
+ crc = (UInt16)((crc << 8) ^ Crc16Table[(crc >> 8) ^ data[i]]);
+
+ return crc;
+ }
+ }
+}
diff --git a/Flac/Flac/Util/CRC8.cs b/Flac/Flac/Util/CRC8.cs
new file mode 100644
index 0000000..10f9586
--- /dev/null
+++ b/Flac/Flac/Util/CRC8.cs
@@ -0,0 +1,319 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Flac.Util
+{
+ ///
+ /// Utility class to calculate 8-bit CRC.
+ ///
+ public static class CRC8
+ {
+ #region private static UInt16[] Crc16Table
+
+ // CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0
+ private static byte[] Crc8Table =
+ new byte[] {
+ (byte) 0x00,
+ (byte) 0x07,
+ (byte) 0x0E,
+ (byte) 0x09,
+ (byte) 0x1C,
+ (byte) 0x1B,
+ (byte) 0x12,
+ (byte) 0x15,
+ (byte) 0x38,
+ (byte) 0x3F,
+ (byte) 0x36,
+ (byte) 0x31,
+ (byte) 0x24,
+ (byte) 0x23,
+ (byte) 0x2A,
+ (byte) 0x2D,
+ (byte) 0x70,
+ (byte) 0x77,
+ (byte) 0x7E,
+ (byte) 0x79,
+ (byte) 0x6C,
+ (byte) 0x6B,
+ (byte) 0x62,
+ (byte) 0x65,
+ (byte) 0x48,
+ (byte) 0x4F,
+ (byte) 0x46,
+ (byte) 0x41,
+ (byte) 0x54,
+ (byte) 0x53,
+ (byte) 0x5A,
+ (byte) 0x5D,
+ (byte) 0xE0,
+ (byte) 0xE7,
+ (byte) 0xEE,
+ (byte) 0xE9,
+ (byte) 0xFC,
+ (byte) 0xFB,
+ (byte) 0xF2,
+ (byte) 0xF5,
+ (byte) 0xD8,
+ (byte) 0xDF,
+ (byte) 0xD6,
+ (byte) 0xD1,
+ (byte) 0xC4,
+ (byte) 0xC3,
+ (byte) 0xCA,
+ (byte) 0xCD,
+ (byte) 0x90,
+ (byte) 0x97,
+ (byte) 0x9E,
+ (byte) 0x99,
+ (byte) 0x8C,
+ (byte) 0x8B,
+ (byte) 0x82,
+ (byte) 0x85,
+ (byte) 0xA8,
+ (byte) 0xAF,
+ (byte) 0xA6,
+ (byte) 0xA1,
+ (byte) 0xB4,
+ (byte) 0xB3,
+ (byte) 0xBA,
+ (byte) 0xBD,
+ (byte) 0xC7,
+ (byte) 0xC0,
+ (byte) 0xC9,
+ (byte) 0xCE,
+ (byte) 0xDB,
+ (byte) 0xDC,
+ (byte) 0xD5,
+ (byte) 0xD2,
+ (byte) 0xFF,
+ (byte) 0xF8,
+ (byte) 0xF1,
+ (byte) 0xF6,
+ (byte) 0xE3,
+ (byte) 0xE4,
+ (byte) 0xED,
+ (byte) 0xEA,
+ (byte) 0xB7,
+ (byte) 0xB0,
+ (byte) 0xB9,
+ (byte) 0xBE,
+ (byte) 0xAB,
+ (byte) 0xAC,
+ (byte) 0xA5,
+ (byte) 0xA2,
+ (byte) 0x8F,
+ (byte) 0x88,
+ (byte) 0x81,
+ (byte) 0x86,
+ (byte) 0x93,
+ (byte) 0x94,
+ (byte) 0x9D,
+ (byte) 0x9A,
+ (byte) 0x27,
+ (byte) 0x20,
+ (byte) 0x29,
+ (byte) 0x2E,
+ (byte) 0x3B,
+ (byte) 0x3C,
+ (byte) 0x35,
+ (byte) 0x32,
+ (byte) 0x1F,
+ (byte) 0x18,
+ (byte) 0x11,
+ (byte) 0x16,
+ (byte) 0x03,
+ (byte) 0x04,
+ (byte) 0x0D,
+ (byte) 0x0A,
+ (byte) 0x57,
+ (byte) 0x50,
+ (byte) 0x59,
+ (byte) 0x5E,
+ (byte) 0x4B,
+ (byte) 0x4C,
+ (byte) 0x45,
+ (byte) 0x42,
+ (byte) 0x6F,
+ (byte) 0x68,
+ (byte) 0x61,
+ (byte) 0x66,
+ (byte) 0x73,
+ (byte) 0x74,
+ (byte) 0x7D,
+ (byte) 0x7A,
+ (byte) 0x89,
+ (byte) 0x8E,
+ (byte) 0x87,
+ (byte) 0x80,
+ (byte) 0x95,
+ (byte) 0x92,
+ (byte) 0x9B,
+ (byte) 0x9C,
+ (byte) 0xB1,
+ (byte) 0xB6,
+ (byte) 0xBF,
+ (byte) 0xB8,
+ (byte) 0xAD,
+ (byte) 0xAA,
+ (byte) 0xA3,
+ (byte) 0xA4,
+ (byte) 0xF9,
+ (byte) 0xFE,
+ (byte) 0xF7,
+ (byte) 0xF0,
+ (byte) 0xE5,
+ (byte) 0xE2,
+ (byte) 0xEB,
+ (byte) 0xEC,
+ (byte) 0xC1,
+ (byte) 0xC6,
+ (byte) 0xCF,
+ (byte) 0xC8,
+ (byte) 0xDD,
+ (byte) 0xDA,
+ (byte) 0xD3,
+ (byte) 0xD4,
+ (byte) 0x69,
+ (byte) 0x6E,
+ (byte) 0x67,
+ (byte) 0x60,
+ (byte) 0x75,
+ (byte) 0x72,
+ (byte) 0x7B,
+ (byte) 0x7C,
+ (byte) 0x51,
+ (byte) 0x56,
+ (byte) 0x5F,
+ (byte) 0x58,
+ (byte) 0x4D,
+ (byte) 0x4A,
+ (byte) 0x43,
+ (byte) 0x44,
+ (byte) 0x19,
+ (byte) 0x1E,
+ (byte) 0x17,
+ (byte) 0x10,
+ (byte) 0x05,
+ (byte) 0x02,
+ (byte) 0x0B,
+ (byte) 0x0C,
+ (byte) 0x21,
+ (byte) 0x26,
+ (byte) 0x2F,
+ (byte) 0x28,
+ (byte) 0x3D,
+ (byte) 0x3A,
+ (byte) 0x33,
+ (byte) 0x34,
+ (byte) 0x4E,
+ (byte) 0x49,
+ (byte) 0x40,
+ (byte) 0x47,
+ (byte) 0x52,
+ (byte) 0x55,
+ (byte) 0x5C,
+ (byte) 0x5B,
+ (byte) 0x76,
+ (byte) 0x71,
+ (byte) 0x78,
+ (byte) 0x7F,
+ (byte) 0x6A,
+ (byte) 0x6D,
+ (byte) 0x64,
+ (byte) 0x63,
+ (byte) 0x3E,
+ (byte) 0x39,
+ (byte) 0x30,
+ (byte) 0x37,
+ (byte) 0x22,
+ (byte) 0x25,
+ (byte) 0x2C,
+ (byte) 0x2B,
+ (byte) 0x06,
+ (byte) 0x01,
+ (byte) 0x08,
+ (byte) 0x0F,
+ (byte) 0x1A,
+ (byte) 0x1D,
+ (byte) 0x14,
+ (byte) 0x13,
+ (byte) 0xAE,
+ (byte) 0xA9,
+ (byte) 0xA0,
+ (byte) 0xA7,
+ (byte) 0xB2,
+ (byte) 0xB5,
+ (byte) 0xBC,
+ (byte) 0xBB,
+ (byte) 0x96,
+ (byte) 0x91,
+ (byte) 0x98,
+ (byte) 0x9F,
+ (byte) 0x8A,
+ (byte) 0x8D,
+ (byte) 0x84,
+ (byte) 0x83,
+ (byte) 0xDE,
+ (byte) 0xD9,
+ (byte) 0xD0,
+ (byte) 0xD7,
+ (byte) 0xC2,
+ (byte) 0xC5,
+ (byte) 0xCC,
+ (byte) 0xCB,
+ (byte) 0xE6,
+ (byte) 0xE1,
+ (byte) 0xE8,
+ (byte) 0xEF,
+ (byte) 0xFA,
+ (byte) 0xFD,
+ (byte) 0xF4,
+ (byte) 0xF3
+ };
+ #endregion
+
+ ///
+ /// Update the CRC with the byte data.
+ ///
+ /// The byte data
+ /// The starting CRC value
+ /// The updated CRC value
+ public static byte Update(byte data, byte crc)
+ {
+ return Crc8Table[crc ^ data];
+ }
+
+ ///
+ /// Update the CRC with the byte array data.
+ ///
+ /// The byte array data
+ /// The byte array length
+ /// The starting CRC value
+ /// The updated CRC value
+ public static byte UpdateBlock(byte[] data, int len, byte crc)
+ {
+ for (int i = 0; i < len; i++)
+ crc = Crc8Table[crc ^ data[i]];
+
+ return crc;
+ }
+
+ ///
+ /// Calculate the CRC over a byte array.
+ ///
+ /// The byte data
+ /// The byte array length
+ /// The calculated CRC value
+ public static byte Calculate(byte[] data, int len)
+ {
+ byte crc = 0;
+
+ for (int i = 0; i < len; i++)
+ crc = Crc8Table[crc ^ data[i]];
+
+ return crc;
+ }
+ }
+}
diff --git a/LICENSE b/LICENSE
index d7f1051..4e77a35 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,339 +1,17 @@
-GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+ libFLAC - Free Lossless Audio Codec library
+Copyright (C) 2000,2001,2002,2003 Josh Coalson
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
- Preamble
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- {description}
- Copyright (C) {year} {fullname}
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- {signature of Ty Coon}, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
\ No newline at end of file