/// <exception cref="ArgumentOutOfRangeException">Range specified by <paramref name="start"/> and <paramref name="byteCount"/> falls outside of the bounds of the buffer content.</exception> /// <exception cref="InvalidOperationException">Content is not available, the builder has been linked with another one.</exception> public byte[] ToArray(int start, int byteCount) { BlobUtilities.ValidateRange(Count, start, byteCount); var result = new byte[byteCount]; int chunkStartPosition = 0; int resultOffset = 0; foreach (var chunk in GetChunks()) { int chunkEndPosition = chunkStartPosition + chunk.Length; if (chunkEndPosition > start) { int bytesToCopy = Math.Min(chunk.Length, result.Length - resultOffset); if (bytesToCopy == 0) { break; } Array.Copy(chunk._buffer, Math.Max(start - chunkStartPosition, 0), result, resultOffset, bytesToCopy); resultOffset += bytesToCopy; } chunkStartPosition = chunkEndPosition; } Debug.Assert(resultOffset == result.Length); return(result); }
/// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException">Range specified by <paramref name="start"/> and <paramref name="byteCount"/> falls outside of the bounds of the <paramref name="buffer"/>.</exception> /// <exception cref="InvalidOperationException">Builder is not writable, it has been linked with another one.</exception> public unsafe void WriteBytes(byte[] buffer, int start, int byteCount) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } BlobUtilities.ValidateRange(buffer.Length, start, byteCount); if (!IsHead) { ThrowHeadRequired(); } // an empty array has no element pointer: if (buffer.Length == 0) { return; } fixed(byte *ptr = buffer) { WriteBytesUnchecked(ptr + start, byteCount); } }
/// <exception cref="ArgumentOutOfRangeException">Range specified by <paramref name="start"/> and <paramref name="byteCount"/> falls outside of the bounds of the buffer content.</exception> public byte[] ToArray(int start, int byteCount) { BlobUtilities.ValidateRange(Length, start, byteCount); var result = new byte[byteCount]; Array.Copy(_buffer, _start + start, result, 0, byteCount); return(result); }
private void WriteUTF8(string str, int start, int length, bool allowUnpairedSurrogates, bool prependSize) { fixed(char *strPtr = str) { char *charPtr = strPtr + start; int byteCount = BlobUtilities.GetUTF8ByteCount(charPtr, length); if (prependSize) { WriteCompressedInteger((uint)byteCount); } int startOffset = Advance(byteCount); _buffer.WriteUTF8(startOffset, charPtr, length, byteCount, allowUnpairedSurrogates); } }
/// <summary> /// Fills in stringIndexMap with data from stringIndex and write to stringWriter. /// Releases stringIndex as the stringTable is sealed after this point. /// </summary> private void SerializeStringHeap() { // Sort by suffix and remove stringIndex var sorted = new List <KeyValuePair <string, StringIdx> >(_strings); sorted.Sort(new SuffixSort()); _strings = null; _stringWriter = new BlobBuilder(1024); // Create VirtIdx to Idx map and add entry for empty string _stringIndexToResolvedOffsetMap = new int[sorted.Count + 1]; _stringIndexToResolvedOffsetMap[0] = 0; _stringWriter.WriteByte(0); // Find strings that can be folded string prev = string.Empty; foreach (KeyValuePair <string, StringIdx> entry in sorted) { int position = _stringHeapStartOffset + _stringWriter.Position; // It is important to use ordinal comparison otherwise we'll use the current culture! if (prev.EndsWith(entry.Key, StringComparison.Ordinal) && !BlobUtilities.IsLowSurrogateChar(entry.Key[0])) { // Map over the tail of prev string. Watch for null-terminator of prev string. _stringIndexToResolvedOffsetMap[entry.Value.MapIndex] = position - (BlobUtilities.GetUTF8ByteCount(entry.Key) + 1); } else { _stringIndexToResolvedOffsetMap[entry.Value.MapIndex] = position; _stringWriter.WriteUTF8(entry.Key, allowUnpairedSurrogates: false); _stringWriter.WriteByte(0); } prev = entry.Key; } }
private void WriteUTF8(string str, int start, int length, bool allowUnpairedSurrogates, bool prependSize) { if (!IsHead) { ThrowHeadRequired(); } fixed(char *strPtr = str) { char *currentPtr = strPtr + start; char *nextPtr; // the max size of compressed int is 4B: int byteLimit = FreeBytes - (prependSize ? sizeof(uint) : 0); int bytesToCurrent = BlobUtilities.GetUTF8ByteCount(currentPtr, length, byteLimit, out nextPtr); int charsToCurrent = (int)(nextPtr - currentPtr); int charsToNext = str.Length - charsToCurrent; int bytesToNext = BlobUtilities.GetUTF8ByteCount(nextPtr, charsToNext); if (prependSize) { WriteCompressedInteger((uint)(bytesToCurrent + bytesToNext)); } _buffer.WriteUTF8(Length, currentPtr, charsToCurrent, bytesToCurrent, allowUnpairedSurrogates); AddLength(bytesToCurrent); if (bytesToNext > 0) { Expand(bytesToNext); _buffer.WriteUTF8(0, nextPtr, charsToNext, bytesToNext, allowUnpairedSurrogates); AddLength(bytesToNext); } } }
/// <exception cref="ArgumentOutOfRangeException">Range specified by <paramref name="start"/> and <paramref name="byteCount"/> falls outside of the bounds of the buffer content.</exception> /// <exception cref="InvalidOperationException">Content is not available, the builder has been linked with another one.</exception> public byte[] ToArray(int start, int byteCount) { BlobUtilities.ValidateRange(Count, start, byteCount); var result = new byte[byteCount]; int chunkStart = 0; int bufferStart = start; int bufferEnd = start + byteCount; foreach (var chunk in GetChunks()) { int chunkEnd = chunkStart + chunk.Length; Debug.Assert(bufferStart >= chunkStart); if (chunkEnd > bufferStart) { int bytesToCopy = Math.Min(bufferEnd, chunkEnd) - bufferStart; Debug.Assert(bytesToCopy >= 0); Array.Copy(chunk._buffer, bufferStart - chunkStart, result, bufferStart - start, bytesToCopy); bufferStart += bytesToCopy; if (bufferStart == bufferEnd) { break; } } chunkStart = chunkEnd; } Debug.Assert(bufferStart == bufferEnd); return(result); }