Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
This C# example demonstrates the use of callbacks to manage stream I/O.
using System;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using JawsMako;
namespace StreamingExamples
{
static class Program
{
static void Main(string[] args)
{
using var mako = IJawsMako.create();
IJawsMako.enableAllFeatures(mako);
using var input = IPDFInput.create(mako);
using var output = IXPSOutput.create(mako);
var directoryInfo = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory;
if (directoryInfo == null) return;
var testFileFolder = Path.Combine(directoryInfo.FullName, @"..\..\..\..\..\TestFiles\");
using var inputFileStream = File.OpenRead(testFileFolder + "BeerLabels.pdf");
using var outputFileStream = File.OpenWrite(testFileFolder + "Out.xps");
using var outputStream = new StreamWriter(outputFileStream);
// Either use the random access stream.
using var inputStream = new RandomAccessStreamReader(inputFileStream);
using var assembly = input.open(IInputStream.createFromRAUserFunc(mako, inputStream.GetLength(), inputStream.getCallbackFunc(), inputStream.getPriv()));
// Or the sequential stream.
//using var inputStream = new StreamReader(inputFileStream);
//using var assembly = input.open(IInputStream.createFromUserReadFunc(mako, inputStream.getCallbackFunc(), inputStream.getPriv()));
// Then write out to a stream.
output.writeAssembly(assembly, IOutputStream.createFromUserWriteFunc(mako, outputStream.getCallbackFunc(), outputStream.getPriv()));
}
}
public class StreamWriter : IUserStreamWriteCallback
{
private readonly Stream m_stream;
public StreamWriter(Stream stream)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
if (!stream.CanWrite)
throw new InvalidOperationException("Cannot create stream writer with non-writing stream.");
m_stream = stream;
}
// The main write routine. As Mako may write data simultaneously from different threads under some circumstances, it is important
// to have appropriate locking. We add an attribute to ensure that this thread safe.
[MethodImpl(MethodImplOptions.Synchronized)]
public override int userWrite(byte[] buffer, uint length)
{
m_stream.Write(buffer, 0, (int)length);
return 0;
}
}
public class StreamReader : IUserStreamReadCallback
{
private readonly Stream m_stream;
public StreamReader(Stream stream)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
if (!stream.CanRead)
throw new InvalidOperationException("Cannot create a read callback for a non-reading stream.");
m_stream = stream;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public override int userRead(byte[] buffer, uint length, out uint lengthRead, out uint endOfFile)
{
endOfFile = 0;
lengthRead = (uint)m_stream.Read(buffer, 0, (int)length);
if (lengthRead == 0 || lengthRead < length)
endOfFile = 1;
return 0;
}
}
public class RandomAccessStreamReader : IRAUserReadCallback
{
private readonly Stream m_stream;
public RandomAccessStreamReader(Stream stream)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
if (!stream.CanRead)
throw new InvalidOperationException("Cannot create a read callback for a non-reading stream.");
if (!stream.CanSeek)
throw new InvalidOperationException("Cannot create a read callback for a non-seekable stream.");
m_stream = stream;
}
public long GetLength()
{
try
{
return m_stream.Seek(0, SeekOrigin.End);
}
finally
{
m_stream.Seek(0, SeekOrigin.Begin);
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
public override int userRARead(byte[] buffer, int length, int offset)
{
m_stream.Seek(offset, SeekOrigin.Begin);
m_stream.Read(buffer, 0, length);
return 0;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment