Skip to content

Commit

Permalink
Hold onto values and decode/encode them only when needed.
Browse files Browse the repository at this point in the history
  • Loading branch information
NZSmartie committed Dec 19, 2017
1 parent 0e7219a commit 7e0bc60
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 55 deletions.
128 changes: 73 additions & 55 deletions src/CoAPNet/Options/BlockWise.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,98 +21,116 @@ public class BlockBase : CoapOption

public BlockBase(int optionNumber, int blockNumber, int blockSize, bool more) : this(optionNumber)
{
SetStuff(blockNumber, SupportedBlockSizes.First(b => b.Item2 == blockSize).Item1, more);
BlockNumber = blockNumber;
BlockSize = blockSize;
IsMoreFollowing = more;
}

internal BlockBase(int optionNumber)
:base (optionNumber, 0, 3, false, OptionType.UInt)
{ }

private int _blockSize = 1024;

public int BlockSize
{
get
{
var n = 0;
if (_length == 1)
n = (int)(ValueUInt & 0xE0) >> 5;
if (_length == 2)
n = (int)(ValueUInt & 0xE000) >> 13;
if (_length == 3)
n = (int)(ValueUInt & 0xE00000) >> 21;

return SupportedBlockSizes.First(b => b.Item1 == n).Item2;
}
get => _blockSize;
set
{
SetStuff(BlockNumber, SupportedBlockSizes.First(b => b.Item2 == value).Item1, IsMoreFollowing);
if (!SupportedBlockSizes.Any(b => b.Item2 == value))
throw new ArgumentOutOfRangeException();
_blockSize = value;
}
}

public bool IsMoreFollowing
{
get
{
if (_length == 0)
return false;
if (_length == 1)
return (ValueUInt & 0x10) != 0;
if (_length == 2)
return (ValueUInt & 0x1000) != 0;
else if (_length == 3)
return (ValueUInt & 0x100000) != 0;
throw new ArgumentOutOfRangeException();
}
set
{
SetStuff(BlockNumber, BlockSize, value);
}
}
public bool IsMoreFollowing { get; set; }

private int _blockNumber = 0;

public int BlockNumber
{
get
{
if (_length == 0)
return 0;
if (_length == 1)
return (int)(ValueUInt & 0x0F);
if (_length == 2)
return (int)(ValueUInt & 0x0FFF);
else if (_length == 3)
return (int)(ValueUInt & 0x0FFFFF);
throw new ArgumentOutOfRangeException();
}
get => _blockNumber;
set
{
if (value < 0)
throw new ArgumentOutOfRangeException("Can not be less than 0");
if (value > 0x0FFFFF)
throw new ArgumentOutOfRangeException("Can not be larger than 1,048,575 (2^20 - 1)");

SetStuff(value, BlockSize, IsMoreFollowing);
_blockNumber = value;
}
}

public override int Length
{
get
{
if (BlockNumber == 0 && BlockSize == 16 && IsMoreFollowing == false)
return 0;
if (BlockNumber <= 0x0F)
return 1;
if (BlockNumber <= 0x0FFF)
return 2;
if (BlockNumber <= 0x0FFFFF)
return 3;
throw new InvalidOperationException();
}
}

internal void SetStuff(int number, int size, bool more)
public override void FromBytes(byte[] data)
{
var last = ((size & 0x07) << 5) | (more ? 0x10 : 0x00);
base.FromBytes(data);
uint last;

if (number <= 0x0F)
if (data.Length == 0)
{
ValueUInt = (uint)(last | (number & 0x0F)) & 0xFF;
BlockNumber = 0;
last = 0;
}
else if (number <= 0x0FFF)
else if (data.Length == 1)
{
ValueUInt = (uint)((last << 8) | (number & 0x0FFF)) & 0xFFFF;
BlockNumber = (int)ValueUInt & 0x0F;
last = (ValueUInt & 0xF0) >> 4;
}
else if (number <= 0x0FFFFF)
else if (data.Length == 2)
{
ValueUInt = (uint)((last << 16) | (number & 0x0FFFFF)) & 0xFFFFFF;
BlockNumber = (int)ValueUInt & 0x0FFF;
last = (ValueUInt & 0xF000) >> 12;
}
else if (data.Length == 3)
{
BlockNumber = (int)ValueUInt & 0x0FFFFF;
last = (ValueUInt & 0xF00000) >> 20;
}
else
{
throw new InvalidOperationException();
throw new CoapOptionException($"Invalid length ({data.Length}) of Block1/Block2 option");
}

IsMoreFollowing = (last & 0x01) > 0;
var szx = (int)((last >> 1));
BlockSize = SupportedBlockSizes.First(b => b.Item1 == szx).Item2;
}

public override byte[] GetBytes()
{
var szx = SupportedBlockSizes.First(b => b.Item2 == BlockSize).Item1;
var last = (byte)((szx & 0x07) << 5) | (IsMoreFollowing ? 0x10 : 0x00);

if (BlockNumber <= 0x0F)
{
ValueUInt = (uint)(last | (BlockNumber & 0x0F));
}
else if (BlockNumber <= 0x0FFF)
{
ValueUInt = (uint)((last << 8) | (BlockNumber & 0x0FFF));
}
else if (BlockNumber <= 0x0FFFFF)
{
ValueUInt = (uint)((last << 16) | (BlockNumber & 0x0FFFFF));
}

return base.GetBytes();
}
}

Expand Down
5 changes: 5 additions & 0 deletions tests/CoAPNet.Tests/CoapOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -446,12 +446,17 @@ public void TestOptionInvalidCastException()
Assert.Throws<InvalidCastException>(() => option.FromBytes(new byte[]{0x12}));
}

[Category("[RFC7959] Section 2.2"), Category("Blocks")]
[TestCase(0, 16, false, new byte[] { })]
[TestCase(1, 16, false, new byte[] { 0x01 })]
[TestCase(2, 32, false, new byte[] { 0x22 })]
[TestCase(3, 64, true, new byte[] { 0x53 })]
[TestCase(4095, 128, true, new byte[] { 0x7F, 0xFF })]
[TestCase(1048575, 256, true, new byte[] { 0x9F, 0xFF, 0xFF})]
[TestCase(15, 16, true, new byte[] { 0x1F })]
[TestCase(16, 16, true, new byte[] { 0x10, 0x10 })]
[TestCase(39, 16, false, new byte[] { 0, 39 })]
[TestCase(79, 16, false, new byte[] { 0, 79 })]
public void TestBlockOption(int blockNumber, int blockSize, bool more, byte[] expected)
{
var optionToBytes = new Options.Block1(blockNumber, blockSize, more);
Expand Down

0 comments on commit 7e0bc60

Please sign in to comment.