blob: 46191997a1de23143a7909eea220cf9a2511a7b3 [file]
/*
* 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
*
* https://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.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace Avro.File
{
/// <summary>
/// Base class for Avro-supported compression codecs for data files. Note that Codec objects may
/// maintain internal state (e.g. buffers) and are not thread safe.
/// </summary>
public abstract class Codec
{
/// <summary>
/// Compress data using implemented codec.
/// </summary>
/// <param name="uncompressedData">The uncompressed data.</param>
/// <returns>
/// byte array.
/// </returns>
public abstract byte[] Compress(byte[] uncompressedData);
/// <summary>
/// Compress data using implemented codec.
/// </summary>
/// <param name="inputStream">The stream which contains the data to be compressed.</param>
/// <param name="outputStream">A reusable stream which will hold the compressed data. That stream should be empty.</param>
public abstract void Compress(MemoryStream inputStream, MemoryStream outputStream);
/// <summary>
/// Decompress data using implemented codec.
/// </summary>
/// <param name="compressedData">The buffer holding data to decompress.</param>
/// <returns>A byte array holding the decompressed data.</returns>
[Obsolete]
public virtual byte[] Decompress(byte[] compressedData)
{
return Decompress(compressedData, compressedData.Length);
}
/// <summary>
/// Decompress data using implemented codec
/// </summary>
/// <param name="compressedData">The buffer holding data to decompress.</param>
/// <param name="length">The actual length of bytes to decompress from the buffer.</param>
/// <returns>A byte array holding the decompressed data.</returns>
public abstract byte[] Decompress(byte[] compressedData, int length);
/// <summary>
/// Name of this codec type.
/// </summary>
/// <returns>The codec name.</returns>
public abstract string GetName();
/// <summary>
/// Codecs must implement an equals() method.
/// </summary>
/// <param name="other">The <see cref="object" /> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="object" /> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public abstract override bool Equals(object other);
/// <summary>
/// Codecs must implement a HashCode() method that is
/// consistent with Equals.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public abstract override int GetHashCode();
/// <summary>
/// Codec types.
/// </summary>
public enum Type
{
/// <summary>
/// Codec type that implements the "deflate" compression algorithm.
/// </summary>
Deflate,
/// <summary>
/// Codec that does not perform any compression.
/// </summary>
Null,
/// <summary>
/// Codec type that implements the "Snappy" compression algorithm.
/// </summary>
Snappy,
/// <summary>
/// Codec type that implements the "BZip2" compression algorithm.
/// </summary>
BZip2,
/// <summary>
/// Codec type that implements the "XZ" compression algorithm.
/// </summary>
XZ,
/// <summary>
/// Codec type that implements the "Zstandard" compression algorithm.
/// </summary>
Zstandard
}
/// <summary>
/// Represents a function capable of resolving a codec string
/// with a matching codec implementation a reader can use to decompress data.
/// </summary>
/// <param name="codecMetaString">The codec string</param>
public delegate Codec CodecResolver(string codecMetaString);
/// <summary>
/// The codec resolvers
/// </summary>
private static readonly List<CodecResolver> _codecResolvers = new List<CodecResolver>();
/// <summary>
/// Registers a function that will attempt to resolve a codec identifying string
/// with a matching codec implementation when reading compressed Avro data.
/// </summary>
/// <param name="resolver">A function that is able to find a codec implementation for a given codec string</param>
public static void RegisterResolver(CodecResolver resolver)
{
_codecResolvers.Add(resolver);
}
/// <summary>
/// Factory method to return child codec instance based on Codec.Type.
/// </summary>
/// <param name="codecType">Type of the codec.</param>
/// <returns>
/// Codec based on type.
/// </returns>
public static Codec CreateCodec(Type codecType)
{
switch (codecType)
{
case Type.Deflate:
return new DeflateCodec();
case Type.Null:
return new NullCodec();
case Type.Snappy:
case Type.BZip2:
case Type.XZ:
case Type.Zstandard:
{
// Create codec dynamically from "Avro.File.CODECNAME" assembly
Assembly assembly = Assembly.Load($"Avro.File.{codecType}");
return assembly.CreateInstance($"Avro.File.{codecType}.{codecType}Codec") as Codec;
}
}
throw new AvroRuntimeException($"Unrecognized codec: {codecType}");
}
/// <summary>
/// Factory method to return child codec instance based on string type.
/// </summary>
/// <param name="codecType">Type of the codec.</param>
/// <returns>Codec based on type.</returns>
public static Codec CreateCodecFromString(string codecType)
{
if (codecType == null)
{
// If codec is absent, it is assumed to be "null"
// https://avro.apache.org/docs/current/spec.html
return CreateCodec(Type.Null);
}
foreach (var resolver in _codecResolvers)
{
var candidateCodec = resolver(codecType);
if (candidateCodec != null)
{
return candidateCodec;
}
}
switch (codecType)
{
case DataFileConstants.DeflateCodec:
return CreateCodec(Type.Deflate);
case DataFileConstants.NullCodec:
return CreateCodec(Type.Null);
case DataFileConstants.SnappyCodec:
return CreateCodec(Type.Snappy);
case DataFileConstants.BZip2Codec:
return CreateCodec(Type.BZip2);
case DataFileConstants.XZCodec:
return CreateCodec(Type.XZ);
case DataFileConstants.ZstandardCodec:
return CreateCodec(Type.Zstandard);
}
throw new AvroRuntimeException($"Unrecognized codec: {codecType}");
}
/// <summary>
/// Returns name of codec.
/// </summary>
/// <returns>
/// A <see cref="string" /> that represents this instance.
/// </returns>
public override string ToString()
{
return GetName();
}
}
}