contract CompressedCaller {

    function compressedCall(
        address target,
        uint256 totalLength,
        bytes memory zipped
    )
        public
        payable
        returns (bytes memory result)
    {
        (bytes memory data, uint decompressedLength) = decompress(totalLength, zipped);
        require(decompressedLength == totalLength, "Uncompress error");

        bool success;
        (success, result) = target.call.value(msg.value)(data);
        require(success, "Decompressed call failed");
    }

    function decompress(
        uint256 totalLength,
        bytes memory zipped
    )
        public
        pure
        returns (
            bytes memory data,
            uint256 index
        )
    {
        data = new bytes(totalLength);

        for (uint i = 0; i < zipped.length; i++) {

            uint len = uint(uint8(zipped[i]) & 0x7F);

            if ((zipped[i] & 0x80) == 0) {
                memcpy(data, index, zipped, i + 1, len);
                i += len;
            }

            index += len;
        }
    }

    //
    // Modified version of:
    // https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol#L45
    //
    function memcpy(
        bytes memory destMem,
        uint dest,
        bytes memory srcMem,
        uint src,
        uint len
    )
        private
        pure
    {
        uint mask = 256 ** (32 - len % 32) - 1;

        assembly {
            dest := add(add(destMem, 32), dest)
            src := add(add(srcMem, 32), src)

            // Copy word-length chunks while possible
            for { } gt(len, 31) { len := sub(len, 32) } { // (!<) is the same as (>=)
                mstore(dest, mload(src))
                dest := add(dest, 32)
                src := add(src, 32)
            }

            // Copy remaining bytes
            let srcPart := and(mload(src), not(mask))
            let destPart := and(mload(dest), mask)
            mstore(dest, or(destPart, srcPart))
        }
    }
}
function memcpy(
        bytes memory destMem,
        uint dest,
        bytes memory srcMem,
        uint src,
        uint len
    )
        private
        pure
    {
        uint mask = 256 ** (32 - len % 32) - 1;

        assembly {
            dest := add(add(destMem, 32), dest)
            src := add(add(srcMem, 32), src)

            // Copy word-length chunks while possible
            for { } gt(len, 31) { len := sub(len, 32) } { // (!<) is the same as (>=)
                mstore(dest, mload(src))
                dest := add(dest, 32)
                src := add(src, 32)
            }

            // Copy remaining bytes
            let srcPart := and(mload(src), not(mask))
            let destPart := and(mload(dest), mask)
            mstore(dest, or(destPart, srcPart))
        }
    }
//
// Modified version of:
// https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol#L45
//