public static SignatureResult decode(Decoder decoder, Function func, boolean keepcalllist)
			throws DecoderException {
		ArrayList<Integer> res = null;
		ArrayList<Address> calllist = null;
		boolean hasunimpl = false;
		boolean hasbaddata = false;
		if (keepcalllist) {
			calllist = new ArrayList<>();
		}
		int start = decoder.openElement(ELEM_SIGNATURES);
		for (;;) {
			int attribId = decoder.getNextAttributeId();
			if (attribId == 0) {
				break;
			}
			if (attribId == ATTRIB_UNIMPL.id()) {
				hasunimpl = decoder.readBool();
			}
			else if (attribId == ATTRIB_BADDATA.id()) {
				hasbaddata = decoder.readBool();
			}
		}
		res = new ArrayList<>();
		for (;;) {
			int subel = decoder.openElement();
			if (subel == 0) {
				break;
			}
			if (subel == ELEM_SIG.id()) {
				int val = (int) decoder.readUnsignedInteger(ATTRIB_VAL);
				res.add(val);
			}
			else {
				Address addr = AddressXML.decodeFromAttributes(decoder);
				if (keepcalllist) {
					calllist.add(addr);
				}
			}
			decoder.closeElement(subel);
		}
		decoder.closeElement(start);

		SignatureResult sigres = new SignatureResult();
		sigres.calllist = calllist;
		sigres.hasunimplemented = hasunimpl;
		sigres.hasbaddata = hasbaddata;
		sigres.features = new int[res.size()];
		for (int i = 0; i < res.size(); ++i) {
			sigres.features[i] = res.get(i).intValue();
		}
		return sigres;
	}
Decode a sequence of raw feature hashes associated with a specific function from a stream.
The stream may optionally include addresses of called functions.
@param decoder is the stream decoder
@param func is the specific function being described
@param keepcalllist is true if call addresses should be stored in the result object
@return the decoded SignatureResult
@throws DecoderException for problems reading from the stream
Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/signature/SignatureResult.java