/// <summary> /// Generates and computes signatures for a given stream and stores the signature /// files in the provided working directory. /// </summary> /// <param name="source">Source stream to process</param> /// <returns>A collection of signature objects</returns> public SignatureCollection GenerateSignatures(Stream source, string BaseName) { int hr = 0; // Compute the appropriate recursion depth for // this stream if the depth is not provided. if (recursionDepth < MSRDC.MINIMUM_DEPTH) { hr = rdcLibrary.ComputeDefaultRecursionDepth(source.Length, out this.recursionDepth); if (hr != 0) { throw new RdcException("Failed to compute the recursion depth.", hr); } if (recursionDepth < MSRDC.MINIMUM_DEPTH) { recursionDepth = (int)MSRDC.MINIMUM_DEPTH; } } // Initalize our signature collection. For this // sample we will create a unique file in the // working directory for each recursion level. SignatureCollection signatures = InitializeAndPrepareSignatures(BaseName); // Array of pointers to generation parameters IRdcGeneratorParameters[] generatorParameters = new IRdcGeneratorParameters[recursionDepth]; for (int i = 0; i < recursionDepth; i++) { hr = rdcLibrary.CreateGeneratorParameters( GeneratorParametersType.FilterMax, (uint)i + 1, out generatorParameters[i]); if (hr != 0) { throw new RdcException("Failed to create the generator parameters.", hr); } IRdcGeneratorFilterMaxParameters maxParams = (IRdcGeneratorFilterMaxParameters)generatorParameters[i]; // Set the default properties maxParams.SetHashWindowSize(i == 0 ? MSRDC.DEFAULT_HASHWINDOWSIZE_1 : MSRDC.DEFAULT_HASHWINDOWSIZE_N); maxParams.SetHorizonSize(i == 0 ? MSRDC.DEFAULT_HORIZONSIZE_1 : MSRDC.DEFAULT_HORIZONSIZE_N); } // Create our RdcGenerator IRdcGenerator rdcGenerator = null; hr = rdcLibrary.CreateGenerator((uint)recursionDepth, generatorParameters, out rdcGenerator); if (hr != 0) { throw new RdcException("Failed to create the RdcGenerator.", hr); } // Enable similarity rdcSimGenerator = (IRdcSimilarityGenerator)rdcGenerator; rdcSimGenerator.EnableSimilarity(); // Create our output buffers IntPtr[] outputBuffers = new IntPtr[recursionDepth]; RdcBufferPointer[] outputPointer = new RdcBufferPointer[recursionDepth]; IntPtr[] outputPointers = new IntPtr[recursionDepth]; for (int i = 0; i < recursionDepth; i++) { outputBuffers[i] = Marshal.AllocCoTaskMem((int)outputBufferSize); outputPointer[i].size = outputBufferSize; outputPointer[i].data = outputBuffers[i]; outputPointer[i].used = 0; // Marshal the managed structure to a native // pointer and add it to our array. outputPointers[i] = Marshal.AllocCoTaskMem(Marshal.SizeOf(outputPointer[i])); Marshal.StructureToPtr(outputPointer[i], outputPointers[i], false); } // Create and allocate memory for our input buffer. IntPtr inputBuffer = Marshal.AllocCoTaskMem((int)inputBufferSize + 16); RdcBufferPointer inputPointer = new RdcBufferPointer(); inputPointer.size = 0; inputPointer.used = 0; inputPointer.data = inputBuffer; long totalBytesRead = 0; bool eof = false; bool eofOutput = false; while (hr == 0 && !eofOutput) { if (inputPointer.size == inputPointer.used && !eof) { if (eof) { inputPointer.size = 0; inputPointer.used = 0; } else { // When the input buffer is completely empty // refill it. int bytesRead = 0; try { bytesRead = IntPtrCopy(source, inputBuffer, 0, (int)inputBufferSize); } catch (Exception ex) { // TODO: Cleanup throw new RdcException("Failed to read from the source stream.", ex); } totalBytesRead += bytesRead; inputPointer.size = (uint)bytesRead; inputPointer.used = 0; if (bytesRead < inputBufferSize) { eof = true; } } } RdcError rdcErrorCode = RdcError.NoError; //Force garbage collection. GC.Collect(); // Wait for all finalizers to complete before continuing. // Without this call to GC.WaitForPendingFinalizers, // the worker loop below might execute at the same time // as the finalizers. // With this call, the worker loop executes only after // all finalizers have been called. GC.WaitForPendingFinalizers(); hr = rdcGenerator.Process( eof, ref eofOutput, ref inputPointer, (uint)recursionDepth, outputPointers, out rdcErrorCode); if (hr != 0 || rdcErrorCode != RdcError.NoError) { throw new RdcException("RdcGenerator failed to process the signature block.", rdcErrorCode); } RdcBufferTranslate(outputPointers, outputPointer); for (int i = 0; i < recursionDepth; i++) { int bytesWritten = 0; // Write the signature block to the file. bytesWritten = IntPtrCopy( outputBuffers[i], signatures[i].InnerStream, 0, (int)outputPointer[i].used); signatures[i].InnerStream.Flush(); signatures[i].Length += bytesWritten; if (outputPointer[i].used != bytesWritten) { throw new RdcException("Failed to write to the signature file."); } outputPointer[i].used = 0; } RdcBufferTranslate(outputPointer, outputPointers); } Marshal.ReleaseComObject(rdcGenerator); rdcGenerator = null; if (inputBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(inputBuffer); } // To make it easier on the consuming application, // reverse the order of the signatures in our collection. signatures.Reverse(); return(signatures); }
public RdcException(string message, int hr, RdcError? rdcError = null) : base(String.Format("{0} hr: {1} rdcError: {2}", message, hr, rdcError)) { }
/// <summary> /// Builds a comparator and perform the RDC comparison logic against the provided signatures to generate a needs list. /// </summary> /// <param name="seedSignature">Seed signature to compare</param> /// <param name="sourceSignature">Source signature to compare</param> /// <returns>RDC Needs list</returns> public ArrayList CreateNeedsList(SignatureInfo seedSignature, SignatureInfo sourceSignature) { int hr = 0; IRdcFileReader fileReader = (IRdcFileReader) new RdcFileReader(seedSignature.InnerStream); IRdcComparator comparator; GC.Collect(); GC.WaitForPendingFinalizers(); hr = rdcLibrary.CreateComparator(fileReader, 1000000, out comparator); // Create and allocate memory for our input buffer. IntPtr inputBuffer = Marshal.AllocCoTaskMem((int)inputBufferSize + 16); RdcBufferPointer inputPointer = new RdcBufferPointer(); inputPointer.size = 0; inputPointer.used = 0; inputPointer.data = inputBuffer; ArrayList needsList = new ArrayList(); IntPtr outputBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(RdcNeed)) * 256); RdcNeedPointer outputPointer = new RdcNeedPointer(); long totalBytesRead = 0; bool eof = false; bool eofOutput = false; while (hr == 0 && !eofOutput) { if (inputPointer.size == inputPointer.used && !eof) { // Fill our input buffer with the signature // data from the source. // When the input buffer is completely empty // refill it. int bytesRead = 0; try { bytesRead = IntPtrCopy(sourceSignature.InnerStream, inputBuffer, 0, (int)inputBufferSize); } catch (Exception ex) { // TODO: Cleanup throw new RdcException("Failed to read from the source stream.", ex); } totalBytesRead += bytesRead; inputPointer.size = (uint)bytesRead; inputPointer.used = 0; if (bytesRead < inputBufferSize) { eof = true; } } // Initialize our output needs array outputPointer.size = 256; outputPointer.used = 0; outputPointer.data = outputBuffer; RdcError error = RdcError.NoError; // Perform the signature comparison. // This function may not produce needs output every time. // Also, it may not use all available input each time either. // You may call it with any number of input bytes // and output needs array entries. Obviously, it is more // efficient to give it reasonably sized buffers for each. // This sample waits until Process() consumes an entire input // buffer before reading more data from the source signatures file. // Continue calling this function until it sets "eofOutput" to true. hr = comparator.Process( eof, ref eofOutput, ref inputPointer, ref outputPointer, out error); if (hr != 0) { throw new RdcException("Failed to process the signature block!"); } if (error != RdcError.NoError) { throw new RdcException("Failed!"); } // Convert the stream to a Needs array. RdcNeed[] needs = GetRdcNeedList(outputPointer); foreach (RdcNeed need in needs) { // assign the needs to our arraylist. needsList.Add(need); } } if (hr != 0) { throw new RdcException("Failed!"); } // Free our resources if (outputBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(outputBuffer); } if (inputBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(inputBuffer); } return(needsList); }