/** * Source Code first verified at https://etherscan.io on Wednesday, April 3, 2019 (UTC) */ pragma solidity ^0.5.2 <0.6.0; contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * @notice Renouncing to ownership will leave the contract without an owner. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } library RLP { uint constant DATA_SHORT_START = 0x80; uint constant DATA_LONG_START = 0xB8; uint constant LIST_SHORT_START = 0xC0; uint constant LIST_LONG_START = 0xF8; uint constant DATA_LONG_OFFSET = 0xB7; uint constant LIST_LONG_OFFSET = 0xF7; struct RLPItem { uint _unsafe_memPtr; // Pointer to the RLP-encoded bytes. uint _unsafe_length; // Number of bytes. This is the full length of the string. } struct Iterator { RLPItem _unsafe_item; // Item that's being iterated over. uint _unsafe_nextPtr; // Position of the next item in the list. } /* Iterator */ function next(Iterator memory self) internal pure returns (RLPItem memory subItem) { if(hasNext(self)) { uint256 ptr = self._unsafe_nextPtr; uint256 itemLength = _itemLength(ptr); subItem._unsafe_memPtr = ptr; subItem._unsafe_length = itemLength; self._unsafe_nextPtr = ptr + itemLength; } else revert(); } function next(Iterator memory self, bool strict) internal pure returns (RLPItem memory subItem) { subItem = next(self); if(strict && !_validate(subItem)) revert(); return subItem; } function hasNext( Iterator memory self ) internal pure returns (bool) { RLP.RLPItem memory item = self._unsafe_item; return self._unsafe_nextPtr < item._unsafe_memPtr + item._unsafe_length; } /* RLPItem */ /// @dev Creates an RLPItem from an array of RLP encoded bytes. /// @param self The RLP encoded bytes. /// @return An RLPItem function toRLPItem(bytes memory self) internal pure returns (RLPItem memory) { uint len = self.length; if (len == 0) { return RLPItem(0, 0); } uint memPtr; assembly { memPtr := add(self, 0x20) } return RLPItem(memPtr, len); } /// @dev Creates an RLPItem from an array of RLP encoded bytes. /// @param self The RLP encoded bytes. /// @param strict Will throw if the data is not RLP encoded. /// @return An RLPItem function toRLPItem(bytes memory self, bool strict) internal pure returns (RLPItem memory) { RLP.RLPItem memory item = toRLPItem(self); if(strict) { uint len = self.length; if(_payloadOffset(item) > len) revert(); if(_itemLength(item._unsafe_memPtr) != len) revert(); if(!_validate(item)) revert(); } return item; } /// @dev Check if the RLP item is null. /// @param self The RLP item. /// @return 'true' if the item is null. function isNull(RLPItem memory self) internal pure returns (bool ret) { return self._unsafe_length == 0; } /// @dev Check if the RLP item is a list. /// @param self The RLP item. /// @return 'true' if the item is a list. function isList(RLPItem memory self) internal pure returns (bool ret) { if (self._unsafe_length == 0) return false; uint memPtr = self._unsafe_memPtr; assembly { ret := iszero(lt(byte(0, mload(memPtr)), 0xC0)) } } /// @dev Check if the RLP item is data. /// @param self The RLP item. /// @return 'true' if the item is data. function isData(RLPItem memory self) internal pure returns (bool ret) { if (self._unsafe_length == 0) return false; uint memPtr = self._unsafe_memPtr; assembly { ret := lt(byte(0, mload(memPtr)), 0xC0) } } /// @dev Check if the RLP item is empty (string or list). /// @param self The RLP item. /// @return 'true' if the item is null. function isEmpty(RLPItem memory self) internal pure returns (bool ret) { if(isNull(self)) return false; uint b0; uint memPtr = self._unsafe_memPtr; assembly { b0 := byte(0, mload(memPtr)) } return (b0 == DATA_SHORT_START || b0 == LIST_SHORT_START); } /// @dev Get the number of items in an RLP encoded list. /// @param self The RLP item. /// @return The number of items. function items(RLPItem memory self) internal pure returns (uint) { if (!isList(self)) return 0; uint b0; uint memPtr = self._unsafe_memPtr; assembly { b0 := byte(0, mload(memPtr)) } uint pos = memPtr + _payloadOffset(self); uint last = memPtr + self._unsafe_length - 1; uint itms; while(pos <= last) { pos += _itemLength(pos); itms++; } return itms; } /// @dev Create an iterator. /// @param self The RLP item. /// @return An 'Iterator' over the item. function iterator(RLPItem memory self) internal pure returns (Iterator memory it) { require(isList(self)); uint ptr = self._unsafe_memPtr + _payloadOffset(self); it._unsafe_item = self; it._unsafe_nextPtr = ptr; } /// @dev Return the RLP encoded bytes. /// @param self The RLPItem. /// @return The bytes. function toBytes(RLPItem memory self) internal pure returns (bytes memory bts) { uint256 len = self._unsafe_length; if (len == 0) return bts; bts = new bytes(len); _copyToBytes(self._unsafe_memPtr, bts, len); // // uint256 len = self._unsafe_length; // // if (len == 0) { // return bts; // } else if (len == 1) { // bts = new bytes(len); // _copyToBytes(self._unsafe_memPtr, bts, len); // return bts; // } // // bts = new bytes(len-_payloadOffset(self)); // uint start = self._unsafe_memPtr + _payloadOffset(self); // _copyToBytes(start, bts, len-_payloadOffset(self)); } /// @dev Decode an RLPItem into bytes. This will not work if the /// RLPItem is a list. /// @param self The RLPItem. /// @return The decoded string. function toData(RLPItem memory self) internal pure returns (bytes memory bts) { require(isData(self)); (uint256 rStartPos, uint256 len) = _decode(self); bts = new bytes(len); _copyToBytes(rStartPos, bts, len); } /// @dev Get the list of sub-items from an RLP encoded list. /// Warning: This is inefficient, as it requires that the list is read twice. /// @param self The RLP item. /// @return Array of RLPItems. function toList(RLPItem memory self) internal pure returns (RLPItem[] memory list) { require(isList(self)); uint256 numItems = items(self); list = new RLPItem[](numItems); RLP.Iterator memory it = iterator(self); uint idx; while(hasNext(it)) { list[idx] = next(it); idx++; } } /// @dev Decode an RLPItem into an ascii string. This will not work if the /// RLPItem is a list. /// @param self The RLPItem. /// @return The decoded string. function toAscii(RLPItem memory self) internal pure returns (string memory str) { require(isData(self)); (uint256 rStartPos, uint256 len) = _decode(self); bytes memory bts = new bytes(len); _copyToBytes(rStartPos, bts, len); str = string(bts); } /// @dev Decode an RLPItem into a uint. This will not work if the /// RLPItem is a list. /// @param self The RLPItem. /// @return The decoded string. function toUint(RLPItem memory self) internal pure returns (uint data) { require(isData(self)); (uint256 rStartPos, uint256 len) = _decode(self); require(len <= 32); assembly { data := div(mload(rStartPos), exp(256, sub(32, len))) } } /// @dev Decode an RLPItem into a boolean. This will not work if the /// RLPItem is a list. /// @param self The RLPItem. /// @return The decoded string. function toBool(RLPItem memory self) internal pure returns (bool data) { require(isData(self)); (uint256 rStartPos, uint256 len) = _decode(self); require(len == 1); uint temp; assembly { temp := byte(0, mload(rStartPos)) } require(temp == 1 || temp == 0); return temp == 1 ? true : false; } /// @dev Decode an RLPItem into a byte. This will not work if the /// RLPItem is a list. /// @param self The RLPItem. /// @return The decoded string. function toByte(RLPItem memory self) internal pure returns (byte data) { require(isData(self)); (uint256 rStartPos, uint256 len) = _decode(self); require(len == 1); byte temp; assembly { temp := byte(0, mload(rStartPos)) } return temp; } /// @dev Decode an RLPItem into an int. This will not work if the /// RLPItem is a list. /// @param self The RLPItem. /// @return The decoded string. function toInt(RLPItem memory self) internal pure returns (int data) { return int(toUint(self)); } /// @dev Decode an RLPItem into a bytes32. This will not work if the /// RLPItem is a list. /// @param self The RLPItem. /// @return The decoded string. function toBytes32(RLPItem memory self) internal pure returns (bytes32 data) { return bytes32(toUint(self)); } /// @dev Decode an RLPItem into an address. This will not work if the /// RLPItem is a list. /// @param self The RLPItem. /// @return The decoded string. function toAddress(RLPItem memory self) internal pure returns (address data) { (, uint256 len) = _decode(self); require(len <= 20); return address(toUint(self)); } // Get the payload offset. function _payloadOffset(RLPItem memory self) private pure returns (uint) { if(self._unsafe_length == 0) return 0; uint b0; uint memPtr = self._unsafe_memPtr; assembly { b0 := byte(0, mload(memPtr)) } if(b0 < DATA_SHORT_START) return 0; if(b0 < DATA_LONG_START || (b0 >= LIST_SHORT_START && b0 < LIST_LONG_START)) return 1; if(b0 < LIST_SHORT_START) return b0 - DATA_LONG_OFFSET + 1; return b0 - LIST_LONG_OFFSET + 1; } // Get the full length of an RLP item. function _itemLength(uint memPtr) private pure returns (uint len) { uint b0; assembly { b0 := byte(0, mload(memPtr)) } if (b0 < DATA_SHORT_START) len = 1; else if (b0 < DATA_LONG_START) len = b0 - DATA_SHORT_START + 1; else if (b0 < LIST_SHORT_START) { assembly { let bLen := sub(b0, 0xB7) // bytes length (DATA_LONG_OFFSET) let dLen := div(mload(add(memPtr, 1)), exp(256, sub(32, bLen))) // data length len := add(1, add(bLen, dLen)) // total length } } else if (b0 < LIST_LONG_START) { len = b0 - LIST_SHORT_START + 1; } else { assembly { let bLen := sub(b0, 0xF7) // bytes length (LIST_LONG_OFFSET) let dLen := div(mload(add(memPtr, 1)), exp(256, sub(32, bLen))) // data length len := add(1, add(bLen, dLen)) // total length } } } // Get start position and length of the data. function _decode(RLPItem memory self) private pure returns (uint memPtr, uint len) { require(isData(self)); uint b0; uint start = self._unsafe_memPtr; assembly { b0 := byte(0, mload(start)) } if (b0 < DATA_SHORT_START) { memPtr = start; len = 1; return (memPtr, len); } if (b0 < DATA_LONG_START) { len = self._unsafe_length - 1; memPtr = start + 1; } else { uint bLen; assembly { bLen := sub(b0, 0xB7) // DATA_LONG_OFFSET } len = self._unsafe_length - 1 - bLen; memPtr = start + bLen + 1; } return (memPtr, len); } // Assumes that enough memory has been allocated to store in target. function _copyToBytes( uint btsPtr, bytes memory tgt, uint btsLen) private pure { // Exploiting the fact that 'tgt' was the last thing to be allocated, // we can write entire words, and just overwrite any excess. assembly { { let words := div(add(btsLen, 31), 32) let rOffset := btsPtr let wOffset := add(tgt, 0x20) for { let i := 0 } lt(i, words) { i := add(i, 1) } { let offset := mul(i, 0x20) mstore(add(wOffset, offset), mload(add(rOffset, offset))) } mstore(add(tgt, add(0x20, mload(tgt))), 0) } } } // Check that an RLP item is valid. function _validate(RLPItem memory self) private pure returns (bool ret) { // Check that RLP is well-formed. uint b0; uint b1; uint memPtr = self._unsafe_memPtr; assembly { b0 := byte(0, mload(memPtr)) b1 := byte(1, mload(memPtr)) } if(b0 == DATA_SHORT_START + 1 && b1 < DATA_SHORT_START) return false; return true; } } library Object { using RLP for bytes; using RLP for bytes[]; using RLP for RLP.RLPItem; using RLP for RLP.Iterator; struct Data { uint sura; uint ayat; bytes text; } function createData(bytes memory dataBytes) internal pure returns (Data memory) { RLP.RLPItem[] memory dataList = dataBytes.toRLPItem().toList(); return Data({ sura: dataList[0].toUint(), ayat: dataList[1].toUint(), text: dataList[2].toBytes() }); } } contract Storage is Ownable { using Object for bytes; using RLP for bytes; using RLP for bytes[]; using RLP for RLP.RLPItem; using RLP for RLP.Iterator; struct coord { uint sura; uint ayat; } // @dev Mapping ayat's hash with its text. mapping(bytes32 => bytes) public content; mapping(uint => mapping(uint => bytes32)) public coordinates; mapping(bytes32 => coord[]) public all_coordinates; /** @dev Adds content. * @param text Ayat text. * @param sura Sura number. * @param ayat Ayat number. */ function add_content( bytes memory text, uint sura, uint ayat ) public onlyOwner { bytes32 hash = keccak256(text); if (coordinates[sura][ayat] != 0x0000000000000000000000000000000000000000000000000000000000000000) { return; } coordinates[sura][ayat] = hash; all_coordinates[hash].push(coord({sura:sura, ayat: ayat})); content[hash] = text; } /** @dev Adds packed data. * @param data RLP packed objects. */ function add_data(bytes memory data) public onlyOwner { RLP.RLPItem[] memory list = data.toRLPItem().toList(); for (uint index = 0; index < list.length; index++) { RLP.RLPItem[] memory item = list[index].toList(); uint sura = item[0].toUint(); uint ayat = item[1].toUint(); bytes memory text = item[2].toData(); add_content(text, sura, ayat); } } /** @dev Gets ayat text by hash. * @param ayat_hash Ayat keccak256 hash of compressed text (gzip). * @return Ayat compressed text. */ function get_ayat_text_by_hash( bytes32 ayat_hash ) public view returns (bytes memory text) { text = content[ayat_hash]; } /** @dev Gets ayat text by coordinates. * @param sura Sura number. * @param ayat Ayat number. * @return Ayat compressed text. */ function get_ayat_text_by_coordinates( uint sura, uint ayat ) public view returns (bytes memory text) { bytes32 hash = coordinates[sura][ayat]; text = content[hash]; } /** @dev Gets number of ayats by hash. * @param hash Ayat keccak256 hash of compressed text (gzip). * @return Ayats number. */ function get_ayats_length( bytes32 hash ) public view returns (uint) { return all_coordinates[hash].length; } /** @dev Gets an ayat's number and a sura number by a hash and a index in an array. * @param hash Ayat keccak256 hash of compressed text (gzip). * @param index Ayat index. Ayat text is not unique in the Quran, so this may be several options. */ function get_ayat_coordinates_by_index( bytes32 hash, uint index ) public view returns (uint sura, uint ayat) { coord memory data = all_coordinates[hash][index]; sura = data.sura; ayat = data.ayat; } /** @dev Verifying the text of an ayat. * @param text Ayat compressed text (gzip). * @return bool */ function check_ayat_text( bytes memory text ) public view returns(bool) { bytes32 hash = keccak256(text); bytes memory ayat_data = content[hash]; return ayat_data.length != 0; } }