forked from Qortal-Forker/qortal
		
	Added support for Pirate Chain transaction lookups and deserialization, necessary for HTLC status checks.
This commit is contained in:
		@@ -47,7 +47,10 @@ public abstract class BitcoinyBlockchainProvider {
 | 
				
			|||||||
	/** Returns list of transaction hashes (and heights) for address represented by <tt>scriptPubKey</tt>, optionally including unconfirmed transactions. */
 | 
						/** Returns list of transaction hashes (and heights) for address represented by <tt>scriptPubKey</tt>, optionally including unconfirmed transactions. */
 | 
				
			||||||
	public abstract List<TransactionHash> getAddressTransactions(byte[] scriptPubKey, boolean includeUnconfirmed) throws ForeignBlockchainException;
 | 
						public abstract List<TransactionHash> getAddressTransactions(byte[] scriptPubKey, boolean includeUnconfirmed) throws ForeignBlockchainException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Returns list of unspent transaction outputs for address, optionally including unconfirmed transactions. */
 | 
						/** Returns list of BitcoinyTransaction objects for <tt>address</tt>, optionally including unconfirmed transactions. */
 | 
				
			||||||
 | 
						public abstract List<BitcoinyTransaction> getAddressBitcoinyTransactions(String address, boolean includeUnconfirmed) throws ForeignBlockchainException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Returns list of unspent transaction outputs for <tt>address</tt>, optionally including unconfirmed transactions. */
 | 
				
			||||||
	public abstract List<UnspentOutput> getUnspentOutputs(String address, boolean includeUnconfirmed) throws ForeignBlockchainException;
 | 
						public abstract List<UnspentOutput> getUnspentOutputs(String address, boolean includeUnconfirmed) throws ForeignBlockchainException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Returns list of unspent transaction outputs for address represented by <tt>scriptPubKey</tt>, optionally including unconfirmed transactions. */
 | 
						/** Returns list of unspent transaction outputs for address represented by <tt>scriptPubKey</tt>, optionally including unconfirmed transactions. */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package org.qortal.crosschain;
 | 
					package org.qortal.crosschain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Comparator;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.stream.Collectors;
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -10,8 +11,13 @@ import javax.xml.bind.annotation.XmlTransient;
 | 
				
			|||||||
@XmlAccessorType(XmlAccessType.FIELD)
 | 
					@XmlAccessorType(XmlAccessType.FIELD)
 | 
				
			||||||
public class BitcoinyTransaction {
 | 
					public class BitcoinyTransaction {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static final Comparator<BitcoinyTransaction> CONFIRMED_FIRST = (a, b) -> Boolean.compare(a.height != 0, b.height != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public final String txHash;
 | 
						public final String txHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@XmlTransient
 | 
				
			||||||
 | 
						public Integer height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@XmlTransient
 | 
						@XmlTransient
 | 
				
			||||||
	public final int size;
 | 
						public final int size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,6 +119,10 @@ public class BitcoinyTransaction {
 | 
				
			|||||||
		this.totalAmount = outputs.stream().map(output -> output.value).reduce(0L, Long::sum);
 | 
							this.totalAmount = outputs.stream().map(output -> output.value).reduce(0L, Long::sum);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public int getHeight() {
 | 
				
			||||||
 | 
							return this.height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public String toString() {
 | 
						public String toString() {
 | 
				
			||||||
		return String.format("txHash %s, size %d, locktime %d, timestamp %d\n"
 | 
							return String.format("txHash %s, size %d, locktime %d, timestamp %d\n"
 | 
				
			||||||
				+ "\tinputs: [%s]\n"
 | 
									+ "\tinputs: [%s]\n"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -533,6 +533,12 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
 | 
				
			|||||||
		return transactionHashes;
 | 
							return transactionHashes;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public List<BitcoinyTransaction> getAddressBitcoinyTransactions(String address, boolean includeUnconfirmed) throws ForeignBlockchainException {
 | 
				
			||||||
 | 
							// FUTURE: implement this if needed. For now we use getAddressTransactions() + getTransaction()
 | 
				
			||||||
 | 
							throw new ForeignBlockchainException("getAddressBitcoinyTransactions not yet implemented for ElectrumX");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Broadcasts raw transaction to network.
 | 
						 * Broadcasts raw transaction to network.
 | 
				
			||||||
	 * <p>
 | 
						 * <p>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package org.qortal.crosschain;
 | 
					package org.qortal.crosschain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cash.z.wallet.sdk.rpc.CompactFormats;
 | 
					import cash.z.wallet.sdk.rpc.CompactFormats;
 | 
				
			||||||
 | 
					import com.google.common.hash.HashCode;
 | 
				
			||||||
import com.rust.litewalletjni.LiteWalletJni;
 | 
					import com.rust.litewalletjni.LiteWalletJni;
 | 
				
			||||||
import org.bitcoinj.core.Coin;
 | 
					import org.bitcoinj.core.Coin;
 | 
				
			||||||
import org.bitcoinj.core.Context;
 | 
					import org.bitcoinj.core.Context;
 | 
				
			||||||
@@ -8,7 +9,6 @@ import org.bitcoinj.core.NetworkParameters;
 | 
				
			|||||||
import org.json.JSONArray;
 | 
					import org.json.JSONArray;
 | 
				
			||||||
import org.json.JSONException;
 | 
					import org.json.JSONException;
 | 
				
			||||||
import org.json.JSONObject;
 | 
					import org.json.JSONObject;
 | 
				
			||||||
import org.libdohj.params.LitecoinMainNetParams;
 | 
					 | 
				
			||||||
import org.libdohj.params.LitecoinRegTestParams;
 | 
					import org.libdohj.params.LitecoinRegTestParams;
 | 
				
			||||||
import org.libdohj.params.LitecoinTestNet3Params;
 | 
					import org.libdohj.params.LitecoinTestNet3Params;
 | 
				
			||||||
import org.libdohj.params.PirateChainMainNetParams;
 | 
					import org.libdohj.params.PirateChainMainNetParams;
 | 
				
			||||||
@@ -17,12 +17,18 @@ import org.qortal.controller.PirateChainWalletController;
 | 
				
			|||||||
import org.qortal.crosschain.PirateLightClient.Server;
 | 
					import org.qortal.crosschain.PirateLightClient.Server;
 | 
				
			||||||
import org.qortal.crosschain.PirateLightClient.Server.ConnectionType;
 | 
					import org.qortal.crosschain.PirateLightClient.Server.ConnectionType;
 | 
				
			||||||
import org.qortal.settings.Settings;
 | 
					import org.qortal.settings.Settings;
 | 
				
			||||||
 | 
					import org.qortal.transform.TransformationException;
 | 
				
			||||||
 | 
					import org.qortal.utils.BitTwiddling;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class PirateChain extends Bitcoiny {
 | 
					public class PirateChain extends Bitcoiny {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static final String CURRENCY_CODE = "ARRR";
 | 
						public static final String CURRENCY_CODE = "ARRR";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static final int DEFAULT_BIRTHDAY = 1900000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final Coin DEFAULT_FEE_PER_KB = Coin.valueOf(10000); // 0.0001 ARRR per 1000 bytes
 | 
						private static final Coin DEFAULT_FEE_PER_KB = Coin.valueOf(10000); // 0.0001 ARRR per 1000 bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final long MINIMUM_ORDER_AMOUNT = 50000000; // 0.5 ARRR minimum order, to avoid dust errors // TODO: may need calibration
 | 
						private static final long MINIMUM_ORDER_AMOUNT = 50000000; // 0.5 ARRR minimum order, to avoid dust errors // TODO: may need calibration
 | 
				
			||||||
@@ -343,4 +349,92 @@ public class PirateChain extends Bitcoiny {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static BitcoinyTransaction deserializeRawTransaction(String rawTransactionHex) throws TransformationException {
 | 
				
			||||||
 | 
							byte[] rawTransactionData = HashCode.fromString(rawTransactionHex).asBytes();
 | 
				
			||||||
 | 
							ByteBuffer byteBuffer = ByteBuffer.wrap(rawTransactionData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Header
 | 
				
			||||||
 | 
							int header = BitTwiddling.readU32(byteBuffer);
 | 
				
			||||||
 | 
							boolean overwintered = ((header >> 31 & 0xff) == 255);
 | 
				
			||||||
 | 
							int version = header & 0x7FFFFFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Version group ID
 | 
				
			||||||
 | 
							int versionGroupId = 0;
 | 
				
			||||||
 | 
							if (overwintered) {
 | 
				
			||||||
 | 
								versionGroupId = BitTwiddling.readU32(byteBuffer);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							boolean isOverwinterV3 = overwintered && versionGroupId == 0x03C48270 && version == 3;
 | 
				
			||||||
 | 
							boolean isSaplingV4 = overwintered && versionGroupId == 0x892F2085 && version == 4;
 | 
				
			||||||
 | 
							if (overwintered && !(isOverwinterV3 || isSaplingV4)) {
 | 
				
			||||||
 | 
								throw new TransformationException("Unknown transaction format");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Inputs
 | 
				
			||||||
 | 
							List<BitcoinyTransaction.Input> inputs = new ArrayList<>();
 | 
				
			||||||
 | 
							int vinCount = BitTwiddling.readU8(byteBuffer);
 | 
				
			||||||
 | 
							for (int i=0; i<vinCount; i++) {
 | 
				
			||||||
 | 
								// Outpoint hash
 | 
				
			||||||
 | 
								byte[] outpointHashBytes = new byte[32];
 | 
				
			||||||
 | 
								byteBuffer.get(outpointHashBytes);
 | 
				
			||||||
 | 
								String outpointHash = HashCode.fromBytes(outpointHashBytes).toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// vout
 | 
				
			||||||
 | 
								int vout = BitTwiddling.readU32(byteBuffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// scriptSig
 | 
				
			||||||
 | 
								int scriptSigLength = BitTwiddling.readU8(byteBuffer);
 | 
				
			||||||
 | 
								byte[] scriptSigBytes = new byte[scriptSigLength];
 | 
				
			||||||
 | 
								byteBuffer.get(scriptSigBytes);
 | 
				
			||||||
 | 
								String scriptSig = HashCode.fromBytes(scriptSigBytes).toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int sequence = BitTwiddling.readU32(byteBuffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								BitcoinyTransaction.Input input = new BitcoinyTransaction.Input(scriptSig, sequence, outpointHash, vout);
 | 
				
			||||||
 | 
								inputs.add(input);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Outputs
 | 
				
			||||||
 | 
							List<BitcoinyTransaction.Output> outputs = new ArrayList<>();
 | 
				
			||||||
 | 
							int voutCount = BitTwiddling.readU8(byteBuffer);
 | 
				
			||||||
 | 
							for (int i=0; i<voutCount; i++) {
 | 
				
			||||||
 | 
								// Amount
 | 
				
			||||||
 | 
								byte[] amountBytes = new byte[8];
 | 
				
			||||||
 | 
								byteBuffer.get(amountBytes);
 | 
				
			||||||
 | 
								long amount = BitTwiddling.longFromLEBytes(amountBytes, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Script pubkey
 | 
				
			||||||
 | 
								int scriptPubkeySize = BitTwiddling.readU8(byteBuffer);
 | 
				
			||||||
 | 
								byte[] scriptPubkeyBytes = new byte[scriptPubkeySize];
 | 
				
			||||||
 | 
								byteBuffer.get(scriptPubkeyBytes);
 | 
				
			||||||
 | 
								String scriptPubKey = HashCode.fromBytes(scriptPubkeyBytes).toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								outputs.add(new BitcoinyTransaction.Output(scriptPubKey, amount, null));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Locktime
 | 
				
			||||||
 | 
							byte[] locktimeBytes = new byte[4];
 | 
				
			||||||
 | 
							byteBuffer.get(locktimeBytes);
 | 
				
			||||||
 | 
							int locktime = BitTwiddling.intFromLEBytes(locktimeBytes, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Expiry height
 | 
				
			||||||
 | 
							int expiryHeight = 0;
 | 
				
			||||||
 | 
							if (isOverwinterV3 || isSaplingV4) {
 | 
				
			||||||
 | 
								byte[] expiryHeightBytes = new byte[4];
 | 
				
			||||||
 | 
								byteBuffer.get(expiryHeightBytes);
 | 
				
			||||||
 | 
								expiryHeight = BitTwiddling.intFromLEBytes(expiryHeightBytes, 0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							String txHash = null; // Not present in raw transaction data
 | 
				
			||||||
 | 
							int size = 0; // Not present in raw transaction data
 | 
				
			||||||
 | 
							Integer timestamp = null; // Not present in raw transaction data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Note: this is incomplete, as sapling spend info is not yet parsed. We don't need it for our
 | 
				
			||||||
 | 
							// current trade bot implementation, but it could be added in the future, for completeness.
 | 
				
			||||||
 | 
							// See link below for reference:
 | 
				
			||||||
 | 
							// https://github.com/PirateNetwork/librustzcash/blob/2981c4d2860f7cd73282fed885daac0323ff0280/zcash_primitives/src/transaction/mod.rs#L197
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new BitcoinyTransaction(txHash, size, locktime, timestamp, inputs, outputs);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ package org.qortal.crosschain;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import cash.z.wallet.sdk.rpc.CompactFormats.*;
 | 
					import cash.z.wallet.sdk.rpc.CompactFormats.*;
 | 
				
			||||||
import cash.z.wallet.sdk.rpc.CompactTxStreamerGrpc;
 | 
					import cash.z.wallet.sdk.rpc.CompactTxStreamerGrpc;
 | 
				
			||||||
 | 
					import cash.z.wallet.sdk.rpc.Service;
 | 
				
			||||||
import cash.z.wallet.sdk.rpc.Service.*;
 | 
					import cash.z.wallet.sdk.rpc.Service.*;
 | 
				
			||||||
import com.google.common.hash.HashCode;
 | 
					import com.google.common.hash.HashCode;
 | 
				
			||||||
import com.google.protobuf.ByteString;
 | 
					import com.google.protobuf.ByteString;
 | 
				
			||||||
@@ -13,11 +14,14 @@ import org.json.simple.JSONArray;
 | 
				
			|||||||
import org.json.simple.JSONObject;
 | 
					import org.json.simple.JSONObject;
 | 
				
			||||||
import org.json.simple.parser.JSONParser;
 | 
					import org.json.simple.parser.JSONParser;
 | 
				
			||||||
import org.json.simple.parser.ParseException;
 | 
					import org.json.simple.parser.ParseException;
 | 
				
			||||||
 | 
					import org.qortal.transform.TransformationException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.math.BigDecimal;
 | 
					import java.math.BigDecimal;
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.regex.Pattern;
 | 
					import java.util.regex.Pattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.qortal.crosschain.PirateChain.DEFAULT_BIRTHDAY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Pirate Chain network support for querying Bitcoiny-related info like block headers, transaction outputs, etc. */
 | 
					/** Pirate Chain network support for querying Bitcoiny-related info like block headers, transaction outputs, etc. */
 | 
				
			||||||
public class PirateLightClient extends BitcoinyBlockchainProvider {
 | 
					public class PirateLightClient extends BitcoinyBlockchainProvider {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -469,6 +473,47 @@ public class PirateLightClient extends BitcoinyBlockchainProvider {
 | 
				
			|||||||
		throw new ForeignBlockchainException("getAddressTransactions not yet implemented for Pirate Chain");
 | 
							throw new ForeignBlockchainException("getAddressTransactions not yet implemented for Pirate Chain");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public List<BitcoinyTransaction> getAddressBitcoinyTransactions(String address, boolean includeUnconfirmed) throws ForeignBlockchainException {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								// Firstly we need to get the latest block
 | 
				
			||||||
 | 
								BlockID endBlock = this.getCompactTxStreamerStub().getLatestBlock(null);
 | 
				
			||||||
 | 
								BlockID startBlock = BlockID.newBuilder().setHeight(DEFAULT_BIRTHDAY).build();
 | 
				
			||||||
 | 
								BlockRange blockRange = BlockRange.newBuilder().setStart(startBlock).setEnd(endBlock).build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								TransparentAddressBlockFilter blockFilter = TransparentAddressBlockFilter.newBuilder()
 | 
				
			||||||
 | 
										.setAddress(address)
 | 
				
			||||||
 | 
										.setRange(blockRange)
 | 
				
			||||||
 | 
										.build();
 | 
				
			||||||
 | 
								Iterator<Service.RawTransaction> transactionIterator = this.getCompactTxStreamerStub().getTaddressTxids(blockFilter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Map from Iterator to List
 | 
				
			||||||
 | 
								List<RawTransaction> rawTransactions = new ArrayList<>();
 | 
				
			||||||
 | 
								transactionIterator.forEachRemaining(rawTransactions::add);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								List<BitcoinyTransaction> transactions = new ArrayList<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (RawTransaction rawTransaction : rawTransactions) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Long height = rawTransaction.getHeight();
 | 
				
			||||||
 | 
									if (!includeUnconfirmed && (height == null || height == 0))
 | 
				
			||||||
 | 
										// We only want confirmed transactions
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									byte[] transactionData = rawTransaction.getData().toByteArray();
 | 
				
			||||||
 | 
									String transactionDataHex = HashCode.fromBytes(transactionData).toString();
 | 
				
			||||||
 | 
									BitcoinyTransaction bitcoinyTransaction = PirateChain.deserializeRawTransaction(transactionDataHex);
 | 
				
			||||||
 | 
									bitcoinyTransaction.height = height.intValue();
 | 
				
			||||||
 | 
									transactions.add(bitcoinyTransaction);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return transactions;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							catch (RuntimeException | TransformationException e) {
 | 
				
			||||||
 | 
								throw new ForeignBlockchainException(String.format("Unable to get transactions for address %s: %s", address, e.getMessage()));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Broadcasts raw transaction to network.
 | 
						 * Broadcasts raw transaction to network.
 | 
				
			||||||
	 * <p>
 | 
						 * <p>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
package org.qortal.utils;
 | 
					package org.qortal.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class BitTwiddling {
 | 
					public class BitTwiddling {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -48,4 +50,25 @@ public class BitTwiddling {
 | 
				
			|||||||
				| (bytes[start + 4] & 0xffL) << 24 | (bytes[start + 5] & 0xffL) << 16 | (bytes[start + 6] & 0xffL) << 8 | (bytes[start + 7] & 0xffL);
 | 
									| (bytes[start + 4] & 0xffL) << 24 | (bytes[start + 5] & 0xffL) << 16 | (bytes[start + 6] & 0xffL) << 8 | (bytes[start + 7] & 0xffL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Convert little-endian bytes to long */
 | 
				
			||||||
 | 
						public static long longFromLEBytes(byte[] bytes, int start) {
 | 
				
			||||||
 | 
							return (bytes[start] & 0xffL) | (bytes[start + 1] & 0xffL) << 8 | (bytes[start + 2] & 0xffL) << 16 | (bytes[start + 3] & 0xffL) << 24
 | 
				
			||||||
 | 
									| (bytes[start + 4] & 0xffL) << 32 | (bytes[start + 5] & 0xffL) << 40 | (bytes[start + 6] & 0xffL) << 48 | (bytes[start + 7] & 0xffL) << 56;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Read 8-bit unsigned integer from byte buffer */
 | 
				
			||||||
 | 
						public static int readU8(ByteBuffer byteBuffer) {
 | 
				
			||||||
 | 
							byte[] sizeBytes = new byte[1];
 | 
				
			||||||
 | 
							byteBuffer.get(sizeBytes);
 | 
				
			||||||
 | 
							return sizeBytes[0] & 0xff;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Read 32-bit unsigned integer from byte buffer */
 | 
				
			||||||
 | 
						public static int readU32(ByteBuffer byteBuffer) {
 | 
				
			||||||
 | 
							byte[] bytes = new byte[4];
 | 
				
			||||||
 | 
							byteBuffer.get(bytes);
 | 
				
			||||||
 | 
							return BitTwiddling.intFromLEBytes(bytes, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Reference in New Issue
	
	Block a user