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

com.hcl.domino.jna.internal.search.SearchMatchDecoder Maven / Gradle / Ivy

/*
 * ==========================================================================
 * Copyright (C) 2019-2022 HCL America, Inc. ( http://www.hcl.com/ )
 *                            All rights reserved.
 * ==========================================================================
 * Licensed under the  Apache License, Version 2.0  (the "License").  You may
 * not use this file except in compliance with the License.  You may obtain a
 * copy of the License at .
 *
 * Unless  required  by applicable  law or  agreed  to  in writing,  software
 * distributed under the License is distributed on an  "AS IS" BASIS, WITHOUT
 * WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the  specific language  governing permissions  and limitations
 * under the License.
 * ==========================================================================
 */
package com.hcl.domino.jna.internal.search;

import java.text.MessageFormat;
import java.util.EnumSet;
import java.util.Formatter;

import com.hcl.domino.data.Database.DocFlags;
import com.hcl.domino.data.DocumentClass;
import com.hcl.domino.data.DominoDateTime;
import com.hcl.domino.jna.data.JNADominoDateTime;
import com.hcl.domino.jna.internal.NotesOriginatorIdData;
import com.hcl.domino.jna.internal.search.NotesSearch.JNASearchMatch;
import com.hcl.domino.misc.DominoEnumUtil;
import com.hcl.domino.misc.NotesConstants;
import com.sun.jna.Pointer;

/**
 * Utility class to decode the SEARCH_MATCH structure and copy its values
 * into a {@link JNASearchMatch}.
 * 
 * @author Karsten Lehmann
 */
public class SearchMatchDecoder {

	/**
	 * Decodes the SEARCH_MATCH_LARGE structure starting at the specified memory address
	 * 
	 * @param ptr memory pointer
	 * @return object with search match data
	 */
	public static JNASearchMatch decodeSearchMatchLarge(Pointer ptr) {
		int gid_file_innards0 = ptr.getInt(0);
		int gid_file_innards1 = ptr.getInt(4);
		
		int gid_note_innards0 = ptr.getInt(8);
		int gid_note_innards1 = ptr.getInt(12);

		int noteId = ptr.getInt(16);
		
		int oid_file_innards0 = ptr.getInt(20);
		int oid_file_innards1 = ptr.getInt(24);
		
		int oid_note_innards0 = ptr.getInt(28);
		int oid_note_innards1 = ptr.getInt(32);
		int seq = ptr.getInt(36);
		int seqTimeInnards0 = ptr.getInt(40);
		int seqTimeInnards1 = ptr.getInt(44);
		
		short noteClass = ptr.getShort(48);
		byte seRetFlags = ptr.getByte(50);
		byte privileges = ptr.getByte(51);
//		int filler = ptr.getInt(52); //seems to have alignment or to be DWORD instead of WORD
		int summaryLength = ptr.getInt(56);

//		typedef struct {
//			GLOBALINSTANCEID ID;                /* identity of the note within the file */
//			ORIGINATORID OriginatorID;        /* identity of the note in the universe */
//			WORD NoteClass;                                /* class of the note */
//			BYTE SERetFlags;                        /* MUST check for SE_FMATCH! */
//			BYTE Privileges;                        /* note privileges */
//			WORD filler;                                /* to ease mapping to SEARCH_MATCH */
//			DWORD SummaryLength;                /* length of the summary information */
//			                                            /* 58 bytes to here */
//			                                            /* now comes an ITEM_TABLE_LARGE with Summary Info */
//			                                            /* now comes the optional $TUA item value.  It is in host format. */
//			} SEARCH_MATCH_LARGE;
			
		SearchMatchImpl match = new SearchMatchImpl();
		match.setGIDFileInnards(new int[] {gid_file_innards0, gid_file_innards1});
		match.setGIDNoteInnards(new int[] {gid_note_innards0, gid_note_innards1});
		match.setNoteId(noteId);
		match.setOIDFileInnards(new int[] {oid_file_innards0, oid_file_innards1});
		match.setOIDNoteInnards(new int[] {oid_note_innards0, oid_note_innards1});
		match.setSeq(seq);
		match.setSeqTimeInnards(new int[] {seqTimeInnards0, seqTimeInnards1});
		match.setNoteClass(noteClass);
		match.setSeRetFlags(seRetFlags);
		match.setPrivileges(privileges);
		match.setSummaryLength(summaryLength);
		return match;
	}
	
	/**
	 * Decodes the SEARCH_MATCH structure starting at the specified memory address
	 * 
	 * @param ptr memory pointer
	 * @return object with search match data
	 */
	public static JNASearchMatch decodeSearchMatch(Pointer ptr) {
		int gid_file_innards0 = ptr.getInt(0);
		int gid_file_innards1 = ptr.getInt(4);
		
		int gid_note_innards0 = ptr.getInt(8);
		int gid_note_innards1 = ptr.getInt(12);
		
		int noteId = ptr.getInt(16);
		
		int oid_file_innards0 = ptr.getInt(20);
		int oid_file_innards1 = ptr.getInt(24);
		
		int oid_note_innards0 = ptr.getInt(28);
		int oid_note_innards1 = ptr.getInt(32);
		int seq = ptr.getInt(36);
		int seqTimeInnards0 = ptr.getInt(40);
		int seqTimeInnards1 = ptr.getInt(44);
		
		short noteClass = ptr.getShort(48);
		byte seRetFlags = ptr.getByte(50);
		byte privileges = ptr.getByte(51);
		short summaryLength = ptr.getShort(52);
		
		SearchMatchImpl match = new SearchMatchImpl();
		match.setGIDFileInnards(new int[] {gid_file_innards0, gid_file_innards1});
		match.setGIDNoteInnards(new int[] {gid_note_innards0, gid_note_innards1});
		match.setNoteId(noteId);
		match.setOIDFileInnards(new int[] {oid_file_innards0, oid_file_innards1});
		match.setOIDNoteInnards(new int[] {oid_note_innards0, oid_note_innards1});
		match.setSeq(seq);
		match.setSeqTimeInnards(new int[] {seqTimeInnards0, seqTimeInnards1});
		match.setNoteClass(noteClass);
		match.setSeRetFlags(seRetFlags);
		match.setPrivileges(privileges);
		match.setSummaryLength((int) (summaryLength & 0xffff));
		return match;
	}
	
	public static class SearchMatchImpl implements NotesSearch.JNASearchMatch {
		//global instance id
		private int[] gid_file_innards;
		private int[] gid_note_innards;
		private int noteId;
		
		//originator id
		private int[] oid_file_innards;
		private int[] oid_note_innards;
		private int seq;
		private int[] seqTimeInnards;
		
		//other data
		private short noteClass;
		private byte seRetFlags;
		private byte privileges;
		private int summaryLength;
		
		private JNADominoDateTime m_dbCreated;
		private JNADominoDateTime m_nodeModified;
		private JNADominoDateTime m_seqTime;
		private NotesOriginatorIdData m_oidData;
		
		private EnumSet noteClassAsEnum;
		private EnumSet m_flagsAsEnum;
		private String m_unid;
		
		@Override
		public int[] getGIDFileInnards() {
			return gid_file_innards;
		}
		
		void setGIDFileInnards(int[] gid_file_innards) {
			this.gid_file_innards = gid_file_innards;
		}
		
		@Override
		public int[] getGIDNoteInnards() {
			return gid_note_innards;
		}
		
		void setGIDNoteInnards(int[] gid_note_innards) {
			this.gid_note_innards = gid_note_innards;
		}
		
		@Override
		public int getNoteID() {
			return noteId;
		}
		
		void setNoteId(int noteId) {
			this.noteId = noteId;
		}
		
		@Override
		public int[] getOIDFileInnards() {
			return oid_file_innards;
		}
		
		void setOIDFileInnards(int[] oid_file_innards) {
			this.oid_file_innards = oid_file_innards;
		}
		
		@Override
		public int[] getOIDNoteInnards() {
			return oid_note_innards;
		}
		
		void setOIDNoteInnards(int[] oid_note_innards) {
			this.oid_note_innards = oid_note_innards;
		}
		
		@Override
		public int getSequenceNumber() {
			return seq;
		}
		
		void setSeq(int seq) {
			this.seq = seq;
		}
		
		@Override
		public int[] getSeqTimeInnards() {
			return seqTimeInnards;
		}
		
		void setSeqTimeInnards(int[] seqTimeInnards) {
			this.seqTimeInnards = seqTimeInnards;
		}
		
		@Override
		public EnumSet getDocumentClass() {
			if (noteClassAsEnum==null) {
				noteClassAsEnum = DominoEnumUtil.valuesOf(DocumentClass.class, noteClass);
			}
			return noteClassAsEnum;
		}
		
		void setNoteClass(short noteClass) {
			this.noteClass = noteClass;
		}
		
		void setSeRetFlags(byte seRetFlags) {
			this.seRetFlags = seRetFlags;
		}
		
		void setPrivileges(byte privileges) {
			this.privileges = privileges;
		}
		
		@Override
		public int getSummaryLength() {
			return summaryLength;
		}
		
		void setSummaryLength(int summaryLength) {
			this.summaryLength = summaryLength;
		}

		private static EnumSet toDocFlags(byte flagsAsByte) {
			EnumSet flags = EnumSet.noneOf(DocFlags.class);
			boolean isTruncated = (flagsAsByte & NotesConstants.SE_FTRUNCATED) == NotesConstants.SE_FTRUNCATED;
			if (isTruncated) {
				flags.add(DocFlags.Truncated);
			}
			boolean isNoAccess = (flagsAsByte & NotesConstants.SE_FNOACCESS) == NotesConstants.SE_FNOACCESS;
			if (isNoAccess) {
				flags.add(DocFlags.NoAccess);
			}
			boolean isTruncatedAttachment = (flagsAsByte & NotesConstants.SE_FTRUNCATT) == NotesConstants.SE_FTRUNCATT;
			if (isTruncatedAttachment) {
				flags.add(DocFlags.TruncatedAttachments);
			}
			boolean isNoPurgeStatus = (flagsAsByte & NotesConstants.SE_FNOPURGE) == NotesConstants.SE_FNOPURGE;
			if (isNoPurgeStatus) {
				flags.add(DocFlags.NoPurgeStatus);
			}
			boolean isPurged = (flagsAsByte & NotesConstants.SE_FPURGED) == NotesConstants.SE_FPURGED;
			if (isPurged) {
				flags.add(DocFlags.Purged);
			}
			boolean isMatch = (flagsAsByte & NotesConstants.SE_FMATCH) == NotesConstants.SE_FMATCH;
			if (isMatch) {
				flags.add(DocFlags.Match);
			} else {
				flags.add(DocFlags.NoMatch);
			}
			boolean isSoftDeleted = (flagsAsByte & NotesConstants.SE_FSOFTDELETED) == NotesConstants.SE_FSOFTDELETED;
			if (isSoftDeleted) {
				flags.add(DocFlags.SoftDeleted);
			}
			
			return flags;
		}
		
		@Override
		public EnumSet getFlags() {
			if (m_flagsAsEnum==null) {
				m_flagsAsEnum = toDocFlags(this.seRetFlags);
			}
			return m_flagsAsEnum;
		}

		@Override
		public boolean matchesFormula() {
			//use flags byte directly, quicker than creating the EnumSet first
			return ((this.seRetFlags & NotesConstants.SE_FMATCH) == NotesConstants.SE_FMATCH);
		}
		
		@Override
		public boolean isLargeSummary() {
			return ((this.seRetFlags & NotesConstants.SE_FLARGESUMMARY) == NotesConstants.SE_FLARGESUMMARY);
		}
		
		@Override
		public JNADominoDateTime getSequenceTime() {
			if (m_seqTime==null) {
				m_seqTime = new JNADominoDateTime(getSeqTimeInnards());
			}
			return m_seqTime;
		}

		@Override
		public NotesOriginatorIdData getOIDData() {
			if (m_oidData==null) {
				m_oidData = new NotesOriginatorIdData(getUNID(), getSequenceNumber(), getSeqTimeInnards());
			}
			return m_oidData;
		}

		@Override
		public String getUNID() {
			if (m_unid==null) {
				Formatter formatter = new Formatter();
				formatter.format("%08x", this.oid_file_innards[1]); //$NON-NLS-1$
				formatter.format("%08x", this.oid_file_innards[0]); //$NON-NLS-1$
				
				formatter.format("%08x", this.oid_note_innards[1]); //$NON-NLS-1$
				formatter.format("%08x", this.oid_note_innards[0]); //$NON-NLS-1$
				
				m_unid = formatter.toString().toUpperCase();
				formatter.close();
			}
			return m_unid;
		}

		@Override
		public DominoDateTime getDbCreated() {
			if (m_dbCreated==null) {
				m_dbCreated = new JNADominoDateTime(getGIDFileInnards());
			}
			return m_dbCreated;
		}

		@Override
		public DominoDateTime getLastModified() {
			if (m_nodeModified==null) {
				m_nodeModified = new JNADominoDateTime(getGIDNoteInnards());
			}
			return m_nodeModified;
		}
		
		@Override
		public String toString() {
			return MessageFormat.format(
				"SearchMatch [unid={0}, seq={1}, seqtime={2}, noteid={3}, class={4},flags={5}, modified={6}]", //$NON-NLS-1$
				getUNID(), getSequenceNumber(), getSequenceTime(), getNoteID(), getDocumentClass(), getFlags(), getLastModified()
			);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy