/// <summary> /// 对给定的字符串进行编码。 /// </summary> /// <param name="value"></param> /// <param name="huffman"></param> /// <returns></returns> public static byte[] Encode(string value, HuffmanStrategy huffman) { var asciiSize = Encoding.ASCII.GetByteCount(value); var estimatedHeaderLength = IntEncoder.RequiredBytes(asciiSize, 0, 7); var estimatedBufferSize = estimatedHeaderLength + asciiSize; while (true) { var buf = new byte[estimatedBufferSize + 16]; var size = EncodeInto( new ArraySegment <byte>(buf), value, asciiSize, huffman); if (size != -1) { if (size == buf.Length) { return(buf); } var newBuf = new byte[size]; Array.Copy(buf, 0, newBuf, 0, size); return(newBuf); } else { estimatedBufferSize = (estimatedBufferSize + 2) * 2; } } }
public Result EncodeInto( ArraySegment <byte> buf, IEnumerable <HeaderField> headers) { var nrEncodedHeaders = 0; var offset = buf.Offset; var count = buf.Count; var tableUpdatesOk = true; if (_tableSizeUpdateMinValue != -1 && _tableSizeUpdateMinValue != _tableSizeUpdateFinalValue) { var used = IntEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, offset, count), this._tableSizeUpdateMinValue, 0x20, 5); if (used == -1) { tableUpdatesOk = false; } else { offset += used; count -= used; _tableSizeUpdateMinValue = -1; } } if (_tableSizeUpdateFinalValue != -1) { var used = IntEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, offset, count), this._tableSizeUpdateFinalValue, 0x20, 5); if (used == -1) { tableUpdatesOk = false; } else { offset += used; count -= used; _tableSizeUpdateMinValue = -1; _tableSizeUpdateFinalValue = -1; } } if (!tableUpdatesOk) { return(new Result { UsedBytes = 0, FieldCount = 0, }); } foreach (var header in headers) { bool fullMatch; var idx = _headerTable.GetBestMatchingIndex(header, out fullMatch); var nameMatch = idx != -1; var tempOffset = offset; if (fullMatch) { var used = IntEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, tempOffset, count), idx, 0x80, 7); if (used == -1) { break; } tempOffset += used; count -= used; } else { var nameLen = StringEncoder.GetByteLength(header.Name); var valLen = StringEncoder.GetByteLength(header.Value); var addToIndex = false; var neverIndex = false; if (header.Sensitive) { neverIndex = true; } else { if (this.DynamicTableSize >= 32 + nameLen + valLen) { addToIndex = true; } } if (addToIndex) { if (nameMatch) { var used = IntEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, tempOffset, count), idx, 0x40, 6); if (used == -1) { break; } tempOffset += used; count -= used; } else { if (count < 1) { break; } buf.Array[tempOffset] = 0x40; tempOffset += 1; count -= 1; var used = StringEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, tempOffset, count), header.Name, nameLen, this._huffmanStrategy); if (used == -1) { break; } tempOffset += used; count -= used; } this._headerTable.Insert(header.Name, nameLen, header.Value, valLen); } else if (!neverIndex) { if (nameMatch) { var used = IntEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, tempOffset, count), idx, 0x00, 4); if (used == -1) { break; } tempOffset += used; count -= used; } else { if (count < 1) { break; } buf.Array[tempOffset] = 0x00; tempOffset += 1; count -= 1; var used = StringEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, tempOffset, count), header.Name, nameLen, this._huffmanStrategy); if (used == -1) { break; } tempOffset += used; count -= used; } } else { if (nameMatch) { var used = IntEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, offset, count), idx, 0x10, 4); if (used == -1) { break; } tempOffset += used; count -= used; } else { if (count < 1) { break; } buf.Array[tempOffset] = 0x10; tempOffset += 1; count -= 1; var used = StringEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, tempOffset, count), header.Name, nameLen, this._huffmanStrategy); if (used == -1) { break; } tempOffset += used; count -= used; } } var usedForValue = StringEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, tempOffset, count), header.Value, valLen, this._huffmanStrategy); if (usedForValue == -1) { break; } tempOffset += usedForValue; count -= usedForValue; } offset = tempOffset; nrEncodedHeaders++; } return(new Result { UsedBytes = offset - buf.Offset, FieldCount = nrEncodedHeaders, }); }
/// <summary> /// 将给定的字符串编码到目标缓冲区中 /// </summary> /// <param name="buf"></param> /// <param name="value"></param> /// <param name="valueByteLen"></param> /// <param name="huffman"></param> /// <returns></returns> public static int EncodeInto( ArraySegment <byte> buf, string value, int valueByteLen, HuffmanStrategy huffman) { var offset = buf.Offset; var free = buf.Count; if (free < 1 + valueByteLen) { return(-1); } var encodedByteLen = valueByteLen; var requiredHuffmanBytes = 0; var useHuffman = huffman == HuffmanStrategy.Always; byte[] huffmanInputBuf = null; if (huffman == HuffmanStrategy.Always || huffman == HuffmanStrategy.IfSmaller) { huffmanInputBuf = Encoding.ASCII.GetBytes(value); requiredHuffmanBytes = Huffman.EncodedLength( new ArraySegment <byte>(huffmanInputBuf)); if (huffman == HuffmanStrategy.IfSmaller && requiredHuffmanBytes < encodedByteLen) { useHuffman = true; } } if (useHuffman) { encodedByteLen = requiredHuffmanBytes; } var prefixContent = useHuffman ? (byte)0x80 : (byte)0; var used = IntEncoder.EncodeInto( new ArraySegment <byte>(buf.Array, offset, free), encodedByteLen, prefixContent, 7); if (used == -1) { return(-1); } offset += used; free -= used; if (useHuffman) { if (free < requiredHuffmanBytes) { return(-1); } used = Huffman.EncodeInto( new ArraySegment <byte>(buf.Array, offset, free), new ArraySegment <byte>(huffmanInputBuf)); if (used == -1) { return(-1); } offset += used; } else { if (free < valueByteLen) { return(-1); } used = Encoding.ASCII.GetBytes( value, 0, value.Length, buf.Array, offset); offset += used; } return(offset - buf.Offset); }