9

I am passing an array of bytes32 to my function. This array can contain numbers or hashes etc. to identify an object. In a new use case I want to pass a URL to this function by splitting the URL into parts converted to bytes32. How can I concatenate the single bytes32 to restore the URL?

I know I can create a bytes array and set bytes at indexes. But I don't know how I can access a specific position in a bytes32.

function bytes2string(bytes32[] data) returns (string) {
    bytes memory r = new bytes(1);
    r[0] = bytes1(data[0]);
    return string(r);
}
eth
  • 85,679
  • 53
  • 285
  • 406
Stefan
  • 181
  • 1
  • 9

2 Answers2

9

Thanks to Piper and Chris I found a working solution for Solidity <= 0.2.1. The reason why the first two log statements return different results is, because uintN is right-aligned and bytesN is left-aligned. Conversion between uintN and bytesN first shortens and then changes alignment. That's why it has to be converted back to bytes32 before converted to byte:

LogBytes1(byte(data)); // prints "s"
LogBytes1(byte(uint(data))); prints "\x00"
LogBytes1(byte(bytes32(uint(data)))); prints "s"

A tested solution to my question is:

function bytes32ArrayToString (bytes32[] data) returns (string) {
    bytes memory bytesString = new bytes(data.length * 32);
    uint urlLength;
    for (uint i=0; i<data.length; i++) {
        for (uint j=0; j<32; j++) {
            byte char = byte(bytes32(uint(data[i]) * 2 ** (8 * j)));
            if (char != 0) {
                bytesString[urlLength] = char;
                urlLength += 1;
            }
        }
    }
    bytes memory bytesStringTrimmed = new bytes(urlLength);
    for (i=0; i<urlLength; i++) {
        bytesStringTrimmed[i] = bytesString[i];
    }
    return string(bytesStringTrimmed);
}
eth
  • 85,679
  • 53
  • 285
  • 406
Stefan
  • 181
  • 1
  • 9
  • I meet some problem when call this function outside the contract, I specify the bytes32[] string like this [7bb8b6ec123302e43ad88384158e2347efcfef19600b821431e8e09504046595,1f57c6ad7358ac73b73730eabb54b1bea7b785df2e4502291ed99b08af625def] but the compiler tell me it's wrong, why? – Wang May 24 '16 at 17:16
7

Solidity <= 0.2.1

You can retrieve the nth byte of any bytesXX type with the following code.

bytes32 v = ...;
byte b = byte(bytes32(uint(v) * 2 ** (8 * n)));

Solidity > 0.2.1

Starting in the next release of solidity you will be able to access them using indices.

bytes32 v = ...;
byte b = v[n];
Piper Merriam
  • 3,592
  • 3
  • 22
  • 34
  • Thanks for your comment Piper. The Solidity <= 0.2.1 solution doesn't work for me, because of an odd Solidity behaviour. Assuming I have a bytes32 containing a bytes representation of string "string", after a uint and byte conversion, the data changed: event LogBytes1(bytes1); LogBytes1(byte(data)); // prints "s" LogBytes1(byte(uint(data))); // prints "\x00" – Stefan Feb 07 '16 at 10:42
  • I've updated my code to include the recasting to bytes32. Not sure if you want to keep this answer or the one from below. – Piper Merriam Feb 14 '16 at 20:46