static uint[] decodeRgbIcon(byte[] payload, CSize size) { // https://devblogs.microsoft.com/oldnewthing/20101019-00/?p=12503 int totalPixels = size.cx * size.cy; int maskLineDwords = (size.cx + 31) / 32; int maskStrideBytes = maskLineDwords * 4; int bytesMask = size.cy * maskStrideBytes; int cbHeader = Marshal.SizeOf <BITMAPINFOHEADER>(); if (payload.Length != (totalPixels * 4) + bytesMask + cbHeader) { throw new ArgumentException("Size doesn't match"); } uint[] result = new uint[totalPixels]; // Copy the RGB values payload.AsSpan() .Slice(cbHeader, totalPixels * 4) .castSpan <uint>() .CopyTo(result.AsSpan()); // Apply the alpha mask, it's 1 bit / pixel. ReadOnlySpan <byte> mask = payload.AsSpan().Slice(cbHeader + totalPixels * 4); applyMask(result.AsSpan(), size, mask, maskStrideBytes); return(result); }
public void InputEndsTooEarlyAndRestartsFromUtf32() { uint[] codepoints1 = TextEncoderTestHelper.GenerateValidUtf32CodePoints(TextEncoderConstants.DataLength); uint[] codepoints2 = TextEncoderTestHelper.GenerateValidUtf32CodePoints(TextEncoderConstants.DataLength); uint[] inputAll = new uint[codepoints1.Length + codepoints2.Length]; Array.Copy(codepoints1, inputAll, codepoints1.Length); Array.Copy(codepoints2, 0, inputAll, codepoints1.Length, codepoints2.Length); ReadOnlySpan <byte> expected = Text.Encoding.Convert(Text.Encoding.UTF32, Text.Encoding.UTF8, MemoryMarshal.AsBytes(inputAll.AsSpan()).ToArray()); Span <byte> output = new byte[expected.Length]; ReadOnlySpan <byte> input = MemoryMarshal.AsBytes(inputAll.AsSpan(0, codepoints1.Length)); input = input.Slice(0, input.Length - 2); // Strip a couple bytes from last good code point Assert.Equal(OperationStatus.NeedMoreData, Encodings.Utf32.ToUtf8(input, output, out int consumed, out int written)); Assert.True(input.Length > consumed, "Consumed too many bytes [first half]"); Assert.NotEqual(expected.Length, written); Assert.True(expected.Slice(0, written).SequenceEqual(output.Slice(0, written)), "Invalid output sequence [first half]"); input = MemoryMarshal.AsBytes(inputAll.AsSpan()).Slice(consumed); expected = expected.Slice(written); Assert.Equal(OperationStatus.Done, Encodings.Utf32.ToUtf8(input, output, out consumed, out written)); Assert.Equal(input.Length, consumed); Assert.Equal(expected.Length, written); Assert.True(expected.SequenceEqual(output.Slice(0, written)), "Invalid output sequence [second half]"); }
public async Task TestLongCompatibility(int length, bool bigTiff) { uint[] refData = new uint[length]; new Random(42).NextBytes(MemoryMarshal.AsBytes(refData.AsSpan())); using Stream stream = await GenerateTiffAsync(bigTiff, async ifd => { await ifd.WriteTagAsync((TiffTag) 0x1234, TiffValueCollection.UnsafeWrap(refData)); }); await using (TiffFileReader reader = await TiffFileReader.OpenAsync(stream, leaveOpen: true)) { TiffImageFileDirectory ifd = await reader.ReadImageFileDirectoryAsync(); TiffFieldReader fieldReader = await reader.CreateFieldReaderAsync(); TiffImageFileDirectoryEntry entry = ifd.FindEntry((TiffTag)0x1234); Assert.Equal((TiffTag)0x1234, entry.Tag); // Byte await TestInvalidConversionAsync <byte>(fieldReader, entry, nameof(fieldReader.ReadByteFieldAsync), refData.Length); // SSbyte await TestInvalidConversionAsync <sbyte>(fieldReader, entry, nameof(fieldReader.ReadSByteFieldAsync), refData.Length); // Short await TestInvalidConversionAsync <ushort>(fieldReader, entry, nameof(fieldReader.ReadShortFieldAsync), refData.Length); // SShort await TestInvalidConversionAsync <short>(fieldReader, entry, nameof(fieldReader.ReadSShortFieldAsync), refData.Length); // Long await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadLongFieldAsync), refData); // SLong await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadSLongFieldAsync), Array.ConvertAll(refData, v => (int)v)); // Float await TestInvalidConversionAsync <float>(fieldReader, entry, nameof(fieldReader.ReadFloatFieldAsync), refData.Length); // Double await TestInvalidConversionAsync <double>(fieldReader, entry, nameof(fieldReader.ReadDoubleFieldAsync), refData.Length); // Rational await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadRationalFieldAsync), Array.ConvertAll(refData, v => new TiffRational(v, 1))); // SRational await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadSRationalFieldAsync), Array.ConvertAll(refData, v => new TiffSRational((int)v, 1))); } }
static Crc() { var tmpTable = new uint[MaxSlice][]; for (uint i = 0; i < MaxSlice; i++) { tmpTable[i] = new uint[256]; } uint crc; for (uint i = 0; i < 256; i++) { crc = i << 24; for (uint j = 0; j < 8; j++) { uint x = crc & (1u << 31); uint shift = x != 0 ? Polynomial : 0; crc = (crc << 1) ^ shift; } tmpTable[0][i] = crc; } for (uint i = 0; i < 256; i++) { for (uint j = 1; j < MaxSlice; j++) { uint x = tmpTable[0][(tmpTable[j - 1][i] >> 24) & 0xFF]; tmpTable[j][i] = x ^ (tmpTable[j - 1][i] << 8); } } // reversing the tables makes the slicing-by-x loop slightly faster // as it can access the table data linearly tmpTable.AsSpan().Reverse(); for (int i = 0; i < MaxSlice; i++) { tmpTable[i].CopyTo(_lookupTable.AsSpan(i * 256, 256)); } }
public void IterationTest(int length) { uint[] array = new uint[length]; array.AsSpan().Fill(uint.MaxValue); using (NativeList <uint> nativeList = new(array)) { for (int i = 0; i < nativeList.Count; i++) { Assert.Equal(uint.MaxValue, nativeList[i]); } for (uint i = 0; i < nativeList.Count; i++) { Assert.Equal(uint.MaxValue, nativeList[i]); } foreach (uint u in nativeList) { Assert.Equal(uint.MaxValue, u); } } }
static void CreateC(ReadOnlySpan <uint> origC, int mod, out ReadOnlySpan <uint> c, out ReadOnlySpan <uint> ic) { var cc = new uint[origC.Length + 1]; origC.CopyTo(cc.AsSpan(1)); cc[0] = (uint)(mod - 1); c = cc; ic = new uint[1] { 1 }; var t = 1; while (t < c.Length) { t = Math.Min(t << 1, c.Length); var current = ConvolutionAnyMod.Convolution(c[..t], ic, mod).AsSpan();
public void SortTest() { const int listLength = 32000; var list = new uint[listLength]; var listStuff = new uint[listLength]; Random random = new Random(); for (int i = 0; i < listLength; i++) { list[i] = (uint) random.Next(0, int.MaxValue); listStuff[i] = 0; } var compareList = new uint[listLength]; Array.Copy(list, compareList, listLength); Array.Sort(compareList); list.AsSpan().Sort(listStuff.AsSpan(), 0, false); list.Should().BeEquivalentTo(compareList); }
/// <summary> /// Create or updates the reflection for this shader /// </summary> /// <param name="effectReflection">the reflection from the hlsl</param> /// <param name="stage">the shader pipeline stage</param> private void CreateReflection(EffectReflection effectReflection, ShaderStage stage) { int currentProgram; GL.GetInteger(GetPName.CurrentProgram, out currentProgram); GL.UseProgram(ProgramId); int uniformBlockCount; GL.GetProgram(ProgramId, ProgramPropertyARB.ActiveUniformBlocks, out uniformBlockCount); var validConstantBuffers = new bool[effectReflection.ConstantBuffers.Count]; for (uint uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) { // TODO: get previous name to find te actual constant buffer in the reflexion GL.GetActiveUniformBlockName(ProgramId, uniformBlockIndex, 1024, out var constantBufferNameLength, out string constantBufferName); var constantBufferDescriptionIndex = effectReflection.ConstantBuffers.FindIndex(x => x.Name == constantBufferName); if (constantBufferDescriptionIndex == -1) { reflectionResult.Error($"Unable to find the constant buffer description [{constantBufferName}]"); return; } var constantBufferIndex = effectReflection.ResourceBindings.FindIndex(x => x.RawName == constantBufferName); if (constantBufferIndex == -1) { reflectionResult.Error($"Unable to find the constant buffer [{constantBufferName}]"); return; } var constantBufferDescription = effectReflection.ConstantBuffers[constantBufferDescriptionIndex]; var constantBuffer = effectReflection.ResourceBindings[constantBufferIndex]; GL.GetActiveUniformBlock(ProgramId, uniformBlockIndex, UniformBlockPName.UniformBlockDataSize, out constantBufferDescription.Size); int uniformCount; GL.GetActiveUniformBlock(ProgramId, uniformBlockIndex, UniformBlockPName.UniformBlockActiveUniforms, out uniformCount); // set the binding GL.UniformBlockBinding(ProgramId, uniformBlockIndex, uniformBlockIndex); // Read uniforms desc var uniformIndices = new uint[uniformCount]; var uniformOffsets = new int[uniformCount]; var uniformTypes = new int[uniformCount]; var uniformNames = new string[uniformCount]; GL.GetActiveUniformBlock(ProgramId, uniformBlockIndex, UniformBlockPName.UniformBlockActiveUniformIndices, MemoryMarshal.Cast <uint, int>(uniformIndices.AsSpan())); GL.GetActiveUniforms(ProgramId, (uint)uniformIndices.Length, uniformIndices, UniformPName.UniformOffset, uniformOffsets); GL.GetActiveUniforms(ProgramId, (uint)uniformIndices.Length, uniformIndices, UniformPName.UniformType, uniformTypes); for (int uniformIndex = 0; uniformIndex < uniformIndices.Length; ++uniformIndex) { uniformNames[uniformIndex] = GL.GetActiveUniform(ProgramId, uniformIndices[uniformIndex], out var uniformSize, out var uniformType); } // Reoder by offset var indexMapping = uniformIndices.Select((x, i) => new UniformMergeInfo { Offset = uniformOffsets[i], Type = (UniformType)uniformTypes[i], Name = uniformNames[i], NextOffset = 0 }).OrderBy(x => x.Offset).ToArray(); indexMapping.Last().NextOffset = constantBufferDescription.Size; // Fill next offsets for (int i = 1; i < indexMapping.Length; ++i) { indexMapping[i - 1].NextOffset = indexMapping[i].Offset; } // Group arrays/structures into one variable (std140 layout is enough for offset determinism inside arrays/structures) indexMapping = indexMapping.GroupBy(x => { // Use only first part of name (ignore structure/array part) var name = x.Name; if (name.Contains(".")) { name = name.Substring(0, name.IndexOf('.')); } if (name.Contains("[")) { name = name.Substring(0, name.IndexOf('[')); } return(name); }) .Select(x => { var result = x.First(); result.NextOffset = x.Last().NextOffset; // Check weither it's an array or a struct int dotIndex = result.Name.IndexOf('.'); int arrayIndex = result.Name.IndexOf('['); if (x.Count() > 1 && arrayIndex == -1 && dotIndex == -1) { throw new InvalidOperationException(); } // TODO: Type processing result.Name = x.Key; return(result); }).ToArray(); foreach (var variableIndexGroup in indexMapping) { var variableIndex = -1; for (var tentativeIndex = 0; tentativeIndex < constantBufferDescription.Members.Length; ++tentativeIndex) { if (constantBufferDescription.Members[tentativeIndex].RawName == variableIndexGroup.Name) { variableIndex = tentativeIndex; break; } } if (variableIndex == -1) { reflectionResult.Error($"Unable to find uniform [{variableIndexGroup.Name}] in constant buffer [{constantBufferName}]"); continue; } var variable = constantBufferDescription.Members[variableIndex]; variable.Type.Type = GetTypeFromActiveUniformType(variableIndexGroup.Type); variable.Offset = variableIndexGroup.Offset; variable.Size = variableIndexGroup.NextOffset - variableIndexGroup.Offset; constantBufferDescription.Members[variableIndex] = variable; } constantBufferDescription.Type = ConstantBufferType.ConstantBuffer; constantBuffer.SlotCount = 1; // constant buffers are not arrays constantBuffer.SlotStart = (int)uniformBlockIndex; constantBuffer.Stage = stage; // store the new values validConstantBuffers[constantBufferDescriptionIndex] = true; effectReflection.ConstantBuffers[constantBufferDescriptionIndex] = constantBufferDescription; effectReflection.ResourceBindings[constantBufferIndex] = constantBuffer; } //#endif // Remove unecessary cbuffer and resource bindings // Register textures, samplers, etc... //TODO: (?) non texture/buffer uniform outside of a block { // Register "NoSampler", required by HLSL=>GLSL translation to support HLSL such as texture.Load(). var noSampler = new EffectResourceBindingDescription { KeyInfo = { KeyName = "NoSampler" }, RawName = "NoSampler", Class = EffectParameterClass.Sampler, SlotStart = -1, SlotCount = 1 }; Reflection.ResourceBindings.Add(noSampler); int activeUniformCount; GL.GetProgram(ProgramId, ProgramPropertyARB.ActiveUniforms, out activeUniformCount); #if !STRIDE_GRAPHICS_API_OPENGLES var uniformTypes = new int[activeUniformCount]; var uniformIndices = new uint[activeUniformCount]; for (uint i = 0; i < uniformIndices.Length; ++i) { uniformIndices[i] = i; } GL.GetActiveUniforms(ProgramId, (uint)activeUniformCount, uniformIndices, UniformPName.UniformType, uniformTypes); #endif int textureUnitCount = 0; const int sbCapacity = 128; var sb = new StringBuilder(sbCapacity); for (uint activeUniformIndex = 0; activeUniformIndex < activeUniformCount; ++activeUniformIndex) { var uniformName = GL.GetActiveUniform(ProgramId, activeUniformIndex, out var uniformCount, out var uniformType); #if STRIDE_GRAPHICS_API_OPENGLES //this is a special OpenglES case , it is declared as built in uniform, and the driver will take care of it, we just need to ignore it here if (uniformName.StartsWith("gl_DepthRange")) { continue; } #endif switch (uniformType) { case UniformType.Sampler1D: case UniformType.Sampler1DShadow: case UniformType.IntSampler1D: case UniformType.UnsignedIntSampler1D: case UniformType.SamplerBuffer: case UniformType.UnsignedIntSamplerBuffer: case UniformType.IntSamplerBuffer: case UniformType.Sampler2D: case UniformType.Sampler2DShadow: case UniformType.Sampler3D: // TODO: remove Texture3D that is not available in OpenGL ES 2 case UniformType.SamplerCube: case UniformType.IntSampler2D: case UniformType.IntSampler3D: case UniformType.IntSamplerCube: case UniformType.UnsignedIntSampler2D: case UniformType.UnsignedIntSampler3D: case UniformType.UnsignedIntSamplerCube: var uniformIndex = GL.GetUniformLocation(ProgramId, uniformName); // Temporary way to scan which texture and sampler created this texture_sampler variable (to fix with new HLSL2GLSL converter) var startIndex = -1; var textureReflectionIndex = -1; var samplerReflectionIndex = -1; do { int middlePart = uniformName.IndexOf('_', startIndex + 1); var textureName = middlePart != -1 ? uniformName.Substring(0, middlePart) : uniformName; var samplerName = middlePart != -1 ? uniformName.Substring(middlePart + 1) : null; textureReflectionIndex = effectReflection.ResourceBindings.FindIndex(x => x.RawName == textureName); samplerReflectionIndex = effectReflection.ResourceBindings.FindIndex(x => x.RawName == samplerName); if (textureReflectionIndex != -1 && samplerReflectionIndex != -1) { break; } startIndex = middlePart; } while (startIndex != -1); if (startIndex == -1 || textureReflectionIndex == -1 || samplerReflectionIndex == -1) { reflectionResult.Error($"Unable to find sampler and texture corresponding to [{uniformName}]"); continue; // Error } var textureReflection = effectReflection.ResourceBindings[textureReflectionIndex]; var samplerReflection = effectReflection.ResourceBindings[samplerReflectionIndex]; // Contrary to Direct3D, samplers and textures are part of the same object in OpenGL // Since we are exposing the Direct3D representation, a single sampler parameter key can be used for several textures, a single texture can be used with several samplers. // When such a case is detected, we need to duplicate the resource binding. textureReflectionIndex = GetReflexionIndex(textureReflection, textureReflectionIndex, effectReflection.ResourceBindings); samplerReflectionIndex = GetReflexionIndex(samplerReflection, samplerReflectionIndex, effectReflection.ResourceBindings); // Update texture uniform mapping GL.Uniform1(uniformIndex, textureUnitCount); textureReflection.Stage = stage; //textureReflection.Param.RawName = uniformName; textureReflection.Type = GetTypeFromActiveUniformType(uniformType); textureReflection.Class = EffectParameterClass.ShaderResourceView; textureReflection.SlotStart = textureUnitCount; textureReflection.SlotCount = 1; // TODO: texture arrays samplerReflection.Stage = stage; samplerReflection.Class = EffectParameterClass.Sampler; samplerReflection.SlotStart = textureUnitCount; samplerReflection.SlotCount = 1; // TODO: texture arrays effectReflection.ResourceBindings[textureReflectionIndex] = textureReflection; effectReflection.ResourceBindings[samplerReflectionIndex] = samplerReflection; Textures.Add(new Texture(textureUnitCount)); textureUnitCount++; break; } } // Remove any optimized resource binding effectReflection.ResourceBindings.RemoveAll(x => x.SlotStart == -1); effectReflection.ConstantBuffers = effectReflection.ConstantBuffers.Where((cb, i) => validConstantBuffers[i]).ToList(); } GL.UseProgram((uint)currentProgram); }
public static bool Save(string filename, int w, int h, byte[] data) { const byte iComponentCount = 3; using var outStream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); if (!outStream.CanWrite) { return(false); } using var binaryWriter = new BinaryWriter(outStream); // write BMP-Header binaryWriter.Write("BM".AsSpan()); // all BMP-Files start with "BM" var header = new uint[3]; var rowPad = 4 - (w * 8 * iComponentCount % 32 / 8); if (rowPad == 4) { rowPad = 0; } header[0] = (uint)(54 + (w * h * iComponentCount) + (rowPad * h)); // filesize = 54 (header) + sizeX * sizeY * numChannels header[1] = 0; // reserved = 0 (4 Bytes) header[2] = 54; // File offset to Raster Data binaryWriter.Write(MemoryMarshal.AsBytes(header.AsSpan())); // write BMP-Info-Header var infoHeader = new uint[10]; infoHeader[0] = 40; // size of info header infoHeader[1] = (uint)w; // Bitmap Width infoHeader[2] = (uint)h; //uint32_t(-(int32_t)h); // Bitmap Height (negative to flip image) infoHeader[3] = (uint)(1 + (65536 * 8 * iComponentCount)); // first 2 bytes=Number of Planes (=1) next 2 bytes=BPP infoHeader[4] = 0; // compression (0 = none) infoHeader[5] = 0; // compressed file size (0 if no compression) infoHeader[6] = 11810; // horizontal resolution: Pixels/meter (11810 = 300 dpi) infoHeader[7] = 11810; // vertical resolution: Pixels/meter (11810 = 300 dpi) infoHeader[8] = 0; // Number of actually used colors infoHeader[9] = 0; // Number of important colors 0 = all binaryWriter.Write(MemoryMarshal.AsBytes(infoHeader.AsSpan())); // data in BMP is stored BGR, so convert scalar BGR var pData = new byte[iComponentCount * w * h]; uint i = 0; for (uint y = 0; y < h; ++y) { for (uint x = 0; x < w; ++x) { var r = data[(4 * (x + (y * w))) + 0]; var g = data[(4 * (x + (y * w))) + 1]; var b = data[(4 * (x + (y * w))) + 2]; var a = data[(4 * (x + (y * w))) + 3]; pData[i++] = b; pData[i++] = g; pData[i++] = r; if (iComponentCount == 4) { pData[i++] = a; } } } // write data (pad if necessary) if (rowPad == 0) { binaryWriter.Write(pData); } else { var zeroes = new[] { byte.MinValue, byte.MinValue, byte.MinValue, byte.MinValue, byte.MinValue, byte.MinValue, byte.MinValue, byte.MinValue, byte.MinValue }; for (var l = 0; l < h; l++) { var seq = new ReadOnlySequence <byte>(pData).Slice(iComponentCount * l * w, iComponentCount * w); foreach (var item in seq) { binaryWriter.Write(item.Span); } binaryWriter.Write(zeroes.AsSpan()[..rowPad]);
static uint[] decodeMonochromeIcon(byte[] payload, CSize size) { int totalPixels = size.cx * size.cy; int maskLineDwords = (size.cx + 31) / 32; int maskStrideBytes = maskLineDwords * 4; int bytesMask = size.cy * maskStrideBytes; int cbHeader = Marshal.SizeOf <BITMAPINFOHEADER>(); // 8 is the color table, immediately after the header if (payload.Length != cbHeader + (bytesMask * 2) + 8) { throw new ArgumentException("Size doesn't match"); } uint[] result = new uint[totalPixels]; Span <uint> colorTable = stackalloc uint[2]; payload.AsSpan() .Slice(cbHeader, 8) .castSpan <uint>() .CopyTo(colorTable); ReadOnlySpan <byte> bitmap = payload.AsSpan() .Slice(cbHeader + 8, bytesMask); if (0 == (size.cx % 8)) { if (0 == (size.cx % 32)) { // No padding whatsoever int destOffset = 0; for (int i = 0; i < bitmap.Length; i++, destOffset += 8) { decodeMonochrome(result, colorTable, destOffset, bitmap[i]); } } else { // There is padding, but it's whole count of bytes int maskBytesPerLine = size.cx / 8; int sourceOffset = 0; int destOffset = 0; for (int y = 0; y < size.cy; y++, sourceOffset += maskStrideBytes) { for (int x = 0; x < maskBytesPerLine; x++, destOffset += 8) { decodeMonochrome(result, colorTable, destOffset, bitmap[sourceOffset + x]); } } } } else { // There is padding, and the last few pixels have less than 8 payload bits per line. throw new NotImplementedException("The library only supports cursors with width being a multiple of 8px"); } // Apply the alpha mask, it's 1 bit / pixel. ReadOnlySpan <byte> mask = payload.AsSpan().Slice(cbHeader + 8 + bytesMask, bytesMask); applyMask(result.AsSpan(), size, mask, maskStrideBytes); return(result); }
//[InlineData(TextEncoderTestHelper.SupportedEncoding.FromUtf32)] // Open issue: https://github.com/dotnet/corefxlab/issues/1513 public void InputBufferEndsTooEarlyAndRestart(TextEncoderTestHelper.SupportedEncoding from) { string inputString1 = TextEncoderTestHelper.GenerateValidStringEndsWithHighStartsWithLow(TextEncoderConstants.DataLength, false); string inputString2 = inputString1 + TextEncoderTestHelper.GenerateValidStringEndsWithHighStartsWithLow(TextEncoderConstants.DataLength, true); byte[] inputUtf8Bytes1 = TextEncoderTestHelper.GenerateValidUtf8BytesEndsWithHighStartsWithLow(TextEncoderConstants.DataLength, false); byte[] tempForUtf8Bytes2 = TextEncoderTestHelper.GenerateValidUtf8BytesEndsWithHighStartsWithLow(TextEncoderConstants.DataLength, true); byte[] inputUtf8Bytes2 = new byte[inputUtf8Bytes1.Length + tempForUtf8Bytes2.Length]; Array.Copy(inputUtf8Bytes1, inputUtf8Bytes2, inputUtf8Bytes1.Length); Array.Copy(tempForUtf8Bytes2, 0, inputUtf8Bytes2, inputUtf8Bytes1.Length, tempForUtf8Bytes2.Length); uint[] inputUtf32Bytes1 = TextEncoderTestHelper.GenerateValidUtf32EndsWithHighStartsWithLow(TextEncoderConstants.DataLength, false); uint[] tempForUtf32Bytes2 = TextEncoderTestHelper.GenerateValidUtf32EndsWithHighStartsWithLow(TextEncoderConstants.DataLength, true); uint[] inputUtf32Bytes2 = new uint[inputUtf32Bytes1.Length + tempForUtf32Bytes2.Length]; Array.Copy(inputUtf32Bytes1, inputUtf32Bytes2, inputUtf32Bytes1.Length); Array.Copy(tempForUtf32Bytes2, 0, inputUtf32Bytes2, inputUtf32Bytes1.Length, tempForUtf32Bytes2.Length); byte[] uint32Bytes1 = TextEncoderTestHelper.GenerateValidBytesUtf32EndsWithHighStartsWithLow(TextEncoderConstants.DataLength, false); byte[] tempUint32Bytes = TextEncoderTestHelper.GenerateValidBytesUtf32EndsWithHighStartsWithLow(TextEncoderConstants.DataLength, true); byte[] uint32Bytes2 = new byte[uint32Bytes1.Length + tempUint32Bytes.Length]; Array.Copy(uint32Bytes1, uint32Bytes2, uint32Bytes1.Length); Array.Copy(tempUint32Bytes, 0, uint32Bytes2, uint32Bytes1.Length, tempUint32Bytes.Length); byte[] expectedBytes; Span <byte> encodedBytes; int charactersConsumed1; int charactersConsumed2; int bytesWritten1; int bytesWritten2; switch (from) { case TextEncoderTestHelper.SupportedEncoding.FromUtf8: expectedBytes = Text.Encoding.Convert(testEncoder, testEncoder, inputUtf8Bytes2); ReadOnlySpan <byte> firstUtf8 = inputUtf8Bytes1; ReadOnlySpan <byte> secondUtf8 = inputUtf8Bytes2; encodedBytes = new Span <byte>(new byte[expectedBytes.Length]); Assert.False(utf8.TryEncode(firstUtf8, encodedBytes, out charactersConsumed1, out bytesWritten1)); Assert.True(utf8.TryEncode(secondUtf8.Slice(charactersConsumed1), encodedBytes.Slice(bytesWritten1), out charactersConsumed2, out bytesWritten2)); break; case TextEncoderTestHelper.SupportedEncoding.FromUtf16: byte[] inputStringUtf16 = testEncoderUnicode.GetBytes(inputString2); expectedBytes = Text.Encoding.Convert(testEncoderUnicode, testEncoder, inputStringUtf16); ReadOnlySpan <char> firstUtf16 = inputString1.AsSpan(); ReadOnlySpan <char> secondUtf16 = inputString2.AsSpan(); encodedBytes = new Span <byte>(new byte[expectedBytes.Length]); Assert.False(utf8.TryEncode(firstUtf16, encodedBytes, out charactersConsumed1, out bytesWritten1)); Assert.True(utf8.TryEncode(secondUtf16.Slice(charactersConsumed1), encodedBytes.Slice(bytesWritten1), out charactersConsumed2, out bytesWritten2)); break; case TextEncoderTestHelper.SupportedEncoding.FromString: // Open issue: https://github.com/dotnet/corefxlab/issues/1515 /*inputStringUtf16 = testEncoderUnicode.GetBytes(inputString2); * expectedBytes = Text.Encoding.Convert(testEncoderUnicode, testEncoder, inputStringUtf16); * string firstInputStr = inputString1; * string secondInputStr = inputString2; * encodedBytes = new Span<byte>(new byte[expectedBytes.Length]); * Assert.False(utf8.TryEncode(firstInputStr, encodedBytes, out bytesWritten1)); * Assert.True(utf8.TryEncode(secondInputStr.Substring(charactersConsumed1), encodedBytes.Slice(bytesWritten1), out bytesWritten1));*/ return; case TextEncoderTestHelper.SupportedEncoding.FromUtf32: default: expectedBytes = Text.Encoding.Convert(testEncoderUtf32, testEncoder, uint32Bytes2); ReadOnlySpan <uint> firstInput = inputUtf32Bytes1.AsSpan(); ReadOnlySpan <uint> secondInput = inputUtf32Bytes2.AsSpan(); encodedBytes = new Span <byte>(new byte[TextEncoderTestHelper.GetUtf8ByteCount(inputUtf32Bytes2)]); Assert.False(utf8.TryEncode(firstInput, encodedBytes, out charactersConsumed1, out bytesWritten1)); Assert.True(utf8.TryEncode(secondInput.Slice(charactersConsumed1), encodedBytes.Slice(bytesWritten1), out charactersConsumed2, out bytesWritten2)); break; } Assert.Equal(TextEncoderConstants.DataLength * 2, charactersConsumed1 + charactersConsumed2); Assert.Equal(expectedBytes.Length, bytesWritten1 + bytesWritten2); Assert.True(expectedBytes.AsSpan().SequenceEqual(encodedBytes)); }