aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
diff options
context:
space:
mode:
Diffstat (limited to 'packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol')
-rw-r--r--packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol195
1 files changed, 142 insertions, 53 deletions
diff --git a/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol b/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
index df2221c93..10d7ce41a 100644
--- a/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
+++ b/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
@@ -18,31 +18,36 @@
pragma solidity ^0.4.24;
-contract LibBytes {
+import "../LibMem/LibMem.sol";
+
+contract LibBytes is
+ LibMem
+{
// Revert reasons
- string constant GT_ZERO_LENGTH_REQUIRED = "Length must be greater than 0.";
- string constant GTE_4_LENGTH_REQUIRED = "Length must be greater than or equal to 4.";
- string constant GTE_20_LENGTH_REQUIRED = "Length must be greater than or equal to 20.";
- string constant GTE_32_LENGTH_REQUIRED = "Length must be greater than or equal to 32.";
- string constant INDEX_OUT_OF_BOUNDS = "Specified array index is out of bounds.";
+ string constant GREATER_THAN_ZERO_LENGTH_REQUIRED = "GREATER_THAN_ZERO_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED";
/// @dev Pops the last byte off of a byte array by modifying its length.
/// @param b Byte array that will be modified.
/// @return The byte that was popped off.
- function popByte(bytes memory b)
+ function popLastByte(bytes memory b)
internal
pure
returns (bytes1 result)
{
require(
b.length > 0,
- GT_ZERO_LENGTH_REQUIRED
+ GREATER_THAN_ZERO_LENGTH_REQUIRED
);
// Store last byte.
result = b[b.length - 1];
-
+
assembly {
// Decrement length of byte array.
let newLen := sub(mload(b), 1)
@@ -54,14 +59,14 @@ contract LibBytes {
/// @dev Pops the last 20 bytes off of a byte array by modifying its length.
/// @param b Byte array that will be modified.
/// @return The 20 byte address that was popped off.
- function popAddress(bytes memory b)
+ function popLast20Bytes(bytes memory b)
internal
pure
returns (address result)
{
require(
b.length >= 20,
- GTE_20_LENGTH_REQUIRED
+ GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
);
// Store last 20 bytes.
@@ -75,41 +80,6 @@ contract LibBytes {
return result;
}
- /// @dev Tests equality of two byte arrays.
- /// @param lhs First byte array to compare.
- /// @param rhs Second byte array to compare.
- /// @return True if arrays are the same. False otherwise.
- function areBytesEqual(
- bytes memory lhs,
- bytes memory rhs
- )
- internal
- pure
- returns (bool equal)
- {
- assembly {
- // Get the number of words occupied by <lhs>
- let lenFullWords := div(add(mload(lhs), 0x1F), 0x20)
-
- // Add 1 to the number of words, to account for the length field
- lenFullWords := add(lenFullWords, 0x1)
-
- // Test equality word-by-word.
- // Terminates early if there is a mismatch.
- for {let i := 0} lt(i, lenFullWords) {i := add(i, 1)} {
- let lhsWord := mload(add(lhs, mul(i, 0x20)))
- let rhsWord := mload(add(rhs, mul(i, 0x20)))
- equal := eq(lhsWord, rhsWord)
- if eq(equal, 0) {
- // Break
- i := lenFullWords
- }
- }
- }
-
- return equal;
- }
-
/// @dev Reads an address from a position in a byte array.
/// @param b Byte array containing an address.
/// @param index Index in byte array of address.
@@ -124,8 +94,8 @@ contract LibBytes {
{
require(
b.length >= index + 20, // 20 is length of address
- GTE_20_LENGTH_REQUIRED
- );
+ GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
+ );
// Add offset to index:
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
@@ -156,8 +126,8 @@ contract LibBytes {
{
require(
b.length >= index + 20, // 20 is length of address
- GTE_20_LENGTH_REQUIRED
- );
+ GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
+ );
// Add offset to index:
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
@@ -195,7 +165,7 @@ contract LibBytes {
{
require(
b.length >= index + 32,
- GTE_32_LENGTH_REQUIRED
+ GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED
);
// Arrays are prefixed by a 256 bit length parameter
@@ -222,7 +192,7 @@ contract LibBytes {
{
require(
b.length >= index + 32,
- GTE_32_LENGTH_REQUIRED
+ GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED
);
// Arrays are prefixed by a 256 bit length parameter
@@ -274,11 +244,130 @@ contract LibBytes {
{
require(
b.length >= 4,
- GTE_4_LENGTH_REQUIRED
+ GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED
);
assembly {
result := mload(add(b, 32))
}
return result;
}
+
+ /// @dev Reads nested bytes from a specific position.
+ /// @param b Byte array containing nested bytes.
+ /// @param index Index of nested bytes.
+ /// @return result Nested bytes.
+ function readBytes(
+ bytes memory b,
+ uint256 index
+ )
+ internal
+ pure
+ returns (bytes memory result)
+ {
+ // Read length of nested bytes
+ uint256 nestedBytesLength = readUint256(b, index);
+ index += 32;
+
+ // Assert length of <b> is valid, given
+ // length of nested bytes
+ require(
+ b.length >= index + nestedBytesLength,
+ GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED
+ );
+
+ // Allocate memory and copy value to result
+ result = new bytes(nestedBytesLength);
+ memCopy(
+ getMemAddress(result) + 32, // +32 skips array length
+ getMemAddress(b) + index + 32,
+ nestedBytesLength
+ );
+
+ return result;
+ }
+
+ /// @dev Inserts bytes at a specific position in a byte array.
+ /// @param b Byte array to insert <input> into.
+ /// @param index Index in byte array of <input>.
+ /// @param input bytes to insert.
+ function writeBytes(
+ bytes memory b,
+ uint256 index,
+ bytes memory input
+ )
+ internal
+ pure
+ {
+ // Assert length of <b> is valid, given
+ // length of input
+ require(
+ b.length >= index + 32 /* 32 bytes to store length */ + input.length,
+ GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED
+ );
+
+ // Copy <input> into <b>
+ memCopy(
+ getMemAddress(b) + 32 + index, // +32 to skip length of <b>
+ getMemAddress(input), // includes length of <input>
+ input.length + 32 // +32 bytes to store <input> length
+ );
+ }
+
+ /// @dev Tests equality of two byte arrays.
+ /// @param lhs First byte array to compare.
+ /// @param rhs Second byte array to compare.
+ /// @return True if arrays are the same. False otherwise.
+ function areBytesEqual(
+ bytes memory lhs,
+ bytes memory rhs
+ )
+ internal
+ pure
+ returns (bool equal)
+ {
+ assembly {
+ // Get the number of words occupied by <lhs>
+ let lenFullWords := div(add(mload(lhs), 0x1F), 0x20)
+
+ // Add 1 to the number of words, to account for the length field
+ lenFullWords := add(lenFullWords, 0x1)
+
+ // Test equality word-by-word.
+ // Terminates early if there is a mismatch.
+ for {let i := 0} lt(i, lenFullWords) {i := add(i, 1)} {
+ let lhsWord := mload(add(lhs, mul(i, 0x20)))
+ let rhsWord := mload(add(rhs, mul(i, 0x20)))
+ equal := eq(lhsWord, rhsWord)
+ if eq(equal, 0) {
+ // Break
+ i := lenFullWords
+ }
+ }
+ }
+
+ return equal;
+ }
+
+ /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.
+ /// @param dest Byte array that will be overwritten with source bytes.
+ /// @param source Byte array to copy onto dest bytes.
+ function deepCopyBytes(
+ bytes memory dest,
+ bytes memory source
+ )
+ internal
+ pure
+ {
+ uint256 sourceLen = source.length;
+ // Dest length must be >= source length, or some bytes would not be copied.
+ require(
+ dest.length >= sourceLen,
+ GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED
+ );
+ memCopy(
+ getMemAddress(dest) + 32, // +32 to skip length of <dest>
+ getMemAddress(source) + 32, // +32 to skip length of <source>
+ sourceLen
+ );
+ }
}