All Downloads are FREE. Search and download functionalities are using the official Maven repository.

convex.core.data.Blobs Maven / Gradle / Ivy

There is a newer version: 0.7.15
Show newest version
package convex.core.data;

import java.util.Random;

import org.bouncycastle.util.Arrays;

import convex.core.exceptions.BadFormatException;
import convex.core.lang.RT;
import convex.core.util.Utils;

public class Blobs {

	static final int CHUNK_SHIFT = 12;
	
	public static final int MAX_ENCODING_LENGTH = Math.max(Blob.MAX_ENCODING_LENGTH, BlobTree.MAX_ENCODING_SIZE);

	public static  T createRandom(long length) {
		return createRandom(new Random(),length);
	}
	
	@SuppressWarnings("unchecked")
	public static  T createRandom(Random r, long length) {
		if (length <= Blob.CHUNK_LENGTH) return (T) Blob.createRandom(r, length);

		BlobBuilder bb=new BlobBuilder();
		while (length>Blob.CHUNK_LENGTH) {
			bb.append(createRandom(r,Blob.CHUNK_LENGTH));
			length -=Blob.CHUNK_LENGTH;
		}
		bb.append(createRandom(r,length));
		return (T)bb.toBlob();
	}

	/**
	 * Converts any blob to a the correct canonical Blob format
	 * @param a Any Blob
	 * @return Canonical version s a Blob or BlobTree
	 */
	public static ABlob toCanonical(ABlob a) {
		long length = a.count();
		if (length <= Blob.CHUNK_LENGTH) return a.toFlatBlob();
		return BlobTree.create(a);
	}

	/**
	 * Creates a blob from a hex string
	 * @param a Hex String
	 * @return Blob created, or null if String not valid hex
	 */
	public static ABlob fromHex(String a) {
		long slength = a.length();
		if ((slength & 1) != 0) return null;
		Blob fullBlob = Blob.fromHex(a);
		
		long length = slength / 2;
		if (length <= Blob.CHUNK_LENGTH) return fullBlob;
		return BlobTree.create(fullBlob);
	}
	
	/**
	 * Creates a blob from a hex string
	 * @param a Hex String
	 * @return Blob created, or null if String not valid hex
	 */
	public static ABlob fromHex(AString a) {
		return fromHex(a.toString());
	}
	
	/**
	 * Best effort attempt to parse a Blob. Must parse as a Blob of correct length
	 * @param o Object expected to contain a Blob value
	 * @return ABlob value, or null if not parseable
	 */
	public static ABlob parse(Object o) {
		if (o instanceof ABlob) {
			ABlob b= (ABlob)o;
			if (b.isRegularBlob()) return b;
			return null;
		}
		if (o instanceof ACell) o=RT.jvm((ACell)o);
		if (!(o instanceof String)) return null;;
		String s=(String)o;
		return parse(s);
	}
	
	/**
	 * Best effort attempt to parse a Blob. Must parse as a Blob of correct length.
	 * Leading "0x" optional.
	 * @param s String expected to contain a HasBlobh value
	 * @return ABlob value, or null if not parseable
	 */
	public static ABlob parse(String s) {
		if (s==null) return null;
		s=s.trim();
		if (s.startsWith("0x")) s=s.substring(2);
		return fromHex(s);
	}

	/**
	 * Reads a canonical Blob from a Blob source
	 * @param  Type of Blob result
	 * @param source Source blob, containing tag
	 * @param pos position to read from source, assumed to be tag
	 * @return Canonical Blob
	 * @throws BadFormatException if the Blob encoding format is invalid
	 */
	@SuppressWarnings("unchecked")
	public static  T read(Blob source, int pos) throws BadFormatException {
		int sLen = source.length-pos;
		if (sLen < 2) throw new BadFormatException("Trying to read Blob from insufficient source of size " + sLen);
		// read length at position 1 (skipping tag)
		long count = Format.readVLCLong(source.store, source.offset + pos+ 1); // skip pos and tag

		T result = null;
		if (count < 0L) throw new BadFormatException("Negative blob length?");
		if (count > Blob.CHUNK_LENGTH) {
			result = (T) BlobTree.read(count,source, pos);
		} else {
			result = (T) Blob.read(source,pos, count);
		}
		// encoding should be attached from Blob reads
		return result;
	}

	/**
	 * Create a Blob entirely filled with a given value
	 * @param value Byte value to fill with (low 8 bits used)
	 * @param length Length of Blob to create
	 * @return BlobTree filled with given value
	 */
	public static ABlob createFilled(int value, long length) {
		byte fillByte=(byte)value;
		if (length<=Blob.CHUNK_LENGTH) {
			byte[] bs=new byte[Utils.checkedInt(length)];
			Arrays.fill(bs, fillByte);
			return Blob.wrap(bs);
		}
		
		int n=BlobTree.childCount(length);
		long subSize=BlobTree.childSize(length);
		ABlob fullChild=Blobs.createFilled(fillByte,subSize);
		
		ABlob[] children=new ABlob[n];
		for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy