diff --git a/domino-jna/src/main/java/com/mindoo/domino/jna/internal/NotesConstants.java b/domino-jna/src/main/java/com/mindoo/domino/jna/internal/NotesConstants.java index eedde141..c127d83e 100755 --- a/domino-jna/src/main/java/com/mindoo/domino/jna/internal/NotesConstants.java +++ b/domino-jna/src/main/java/com/mindoo/domino/jna/internal/NotesConstants.java @@ -3879,6 +3879,59 @@ compatibility, outputs it to disk at Save() time public short CDRESOURCE_CLASS_PORTFOLIO = 21; public short CDRESOURCE_CLASS_OUTLINE = 22; + /** Obsolete - Use class _VIEW or _FOLDER and flag _SIMPLE */ + public short CDRESOURCE_CLASS_SIMPLEVIEW = 23; + /** design link only */ + public short CDRESOURCE_CLASS_SUBFORM = 24; + /** design link only */ + public short CDRESOURCE_CLASS_SHARED_FLD = 25; + /** design link only */ + public short CDRESOURCE_CLASS_SCRIPTLIB = 26; + /** design link only */ + public short CDRESOURCE_CLASS_DBSCRIPT = 27; + /** design link only */ + public short CDRESOURCE_CLASS_SHARED_ACTIONS = 28; + /** design link only */ + public short CDRESOURCE_CLASS_WEBSERVICE = 29; + /** design link only */ + public short CDRESOURCE_CLASS_DATA_CONNECTION = 30; + public short CDRESOURCE_CLASS_SHARED_APPLET = 31; + public short CDRESOURCE_CLASS_EMBEDDED_VIEW = 32; + public short CDRESOURCE_CLASS_STYLE_SHEET = 33; + /** a file with the html flag, too */ + public short CDRESOURCE_CLASS_HTMLFILE = 34; + /** a file that's a JSP */ + public short CDRESOURCE_CLASS_JSP = 35; + public short CDRESOURCE_CLASS_SHAREDCOL = 36; + public short CDRESOURCE_CLASS_DB2ACCESSVIEW = 37; + /** LI 3925.04 */ + public short CDRESOURCE_CLASS_COMPAPP = 38; + /** LI 3925.05 */ + public short CDRESOURCE_CLASS_COMPDEF = 39; + /** LI 3261.05 */ + public short CDRESOURCE_CLASS_MAILSETTINGS = 40; + /** LI 3261.05 */ + public short CDRESOURCE_CLASS_CSSETTINGS = 41; + /** LI 3261.05 */ + public short CDRESOURCE_CLASS_FORM_PREMIUM = 42; + public short CDRESOURCE_MAX_CLASS = CDRESOURCE_CLASS_FORM_PREMIUM; + /** design link only */ + public short CDRESOURCE_CLASS_XSPPAGES = 43; + /** design link only */ + public short CDRESOURCE_CLASS_XSPCCS = 44; + /** design link only */ + public short CDRESOURCE_CLASS_STYLEKITS = 45; + /** design link only */ + public short CDRESOURCE_CLASS_WSCONSUMERS = 46; + /** design link only */ + public short CDRESOURCE_CLASS_COMPONENT = 47; + /** design link only */ + public short CDRESOURCE_CLASS_JAVAFILES = 48; + /** design link only */ + public short CDRESOURCE_CLASS_JAVAJARS = 49; + /** design link only */ + public short CDRESOURCE_CLASS_CUSTOMELTS = 50; + public short KFM_access_GetIDFHFlags = 51; /** File is password protected */ diff --git a/domino-jna/src/main/java/com/mindoo/domino/jna/richtext/RichTextUtils.java b/domino-jna/src/main/java/com/mindoo/domino/jna/richtext/RichTextUtils.java index ca09bf28..d6a632cd 100644 --- a/domino-jna/src/main/java/com/mindoo/domino/jna/richtext/RichTextUtils.java +++ b/domino-jna/src/main/java/com/mindoo/domino/jna/richtext/RichTextUtils.java @@ -12,10 +12,16 @@ import com.mindoo.domino.jna.NotesNote; import com.mindoo.domino.jna.constants.CDRecordType; import com.mindoo.domino.jna.internal.FieldPropAdaptable; +import com.mindoo.domino.jna.internal.FormulaDecompiler; import com.mindoo.domino.jna.internal.NotesConstants; +import com.mindoo.domino.jna.internal.structs.NotesTimeDateStruct; +import com.mindoo.domino.jna.internal.structs.compoundtext.NotesCDResourceStruct; +import com.mindoo.domino.jna.internal.structs.compoundtext.NotesCdHotspotBeginStruct; import com.mindoo.domino.jna.richtext.IRichTextNavigator.RichTextNavPosition; import com.mindoo.domino.jna.utils.NotesStringUtils; +import com.mindoo.domino.jna.utils.Pair; import com.sun.jna.Memory; +import com.sun.jna.Pointer; /** * Collection of useful methods to process richtext CD records @@ -186,7 +192,6 @@ public static LinkedHashSet collectAttachmentNames(IRichTextNavigator rt // } CDBEGINRECORD; Memory beginDataBuf = rtNav.getCurrentRecordData(); - int version = beginDataBuf.getShort(0); int signature = beginDataBuf.share(2).getShort(0); if (signature == NotesConstants.SIG_CD_V4HOTSPOTBEGIN) { @@ -226,4 +231,199 @@ public static LinkedHashSet collectAttachmentNames(IRichTextNavigator rt return attNames; } + + /** + * Traverses the richtext CD records (of a design element's $body item) + * and collects all contained named subforms (those not computed via formula) + * with the replica id of their database. Restores the + * current {@link RichTextNavPosition} in the richtext item if not + * null. + * + * @param rtNav richtext navigator + * @return pairs of [replicaid, named subform], replicaid is "0000000000000000" for the local DB + */ + public static List> collectNamedSubforms(IRichTextNavigator rtNav) { + List> subforms = new ArrayList<>(); + + if (rtNav==null) { + return subforms; + } + + RichTextNavPosition oldPos = rtNav.getCurrentRecordPosition(); + + if (rtNav.gotoFirst()) { + boolean inBeginEnd = false; + + do { + if (CDRecordType.BEGIN.getConstant() == rtNav.getCurrentRecordTypeAsShort()) { + inBeginEnd = true; + } + else if (CDRecordType.END.getConstant() == rtNav.getCurrentRecordTypeAsShort()) { + inBeginEnd = false; + } + else if (CDRecordType.HREF2.getConstant() == rtNav.getCurrentRecordTypeAsShort()) { + if (inBeginEnd) { + //found record of type SIG_CD_HREF2 + Memory href2RecordWithHeader = rtNav.getCurrentRecordDataWithHeader(); + + NotesCDResourceStruct cdResourceStruct = NotesCDResourceStruct.newInstance(href2RecordWithHeader); + cdResourceStruct.read(); + + //search for additional CD records V4HOTSPOTBEGIN / V4HOTSPOTEND + + RichTextNavPosition fieldPos = rtNav.getCurrentRecordPosition(); + + boolean hotspotBeginFound = false; + boolean hotspotEndFound = false; + + if (rtNav.gotoNext()) { + do { + // check if we have reached the end of the field block + if (CDRecordType.V4HOTSPOTBEGIN.getConstant() == rtNav.getCurrentRecordTypeAsShort()) { + Memory v4HotspotbeginRecordWithHeader = rtNav.getCurrentRecordDataWithHeader(); + + NotesCdHotspotBeginStruct v4HotspotBegin = NotesCdHotspotBeginStruct.newInstance(v4HotspotbeginRecordWithHeader); + v4HotspotBegin.read(); + + if (v4HotspotBegin.Type == NotesConstants.HOTSPOTREC_TYPE_SUBFORM) { + hotspotBeginFound = true; + } + } + else if (CDRecordType.V4HOTSPOTEND.getConstant() == rtNav.getCurrentRecordTypeAsShort()) { + hotspotEndFound = true; + } + } + while (rtNav.gotoNext()); + } + + rtNav.restoreCurrentRecordPosition(fieldPos); + + if (hotspotBeginFound && hotspotEndFound) { +// typedef struct { +// WSIG Header; +// DWORD Flags; /* one of CDRESOURCE_FLAGS_xxx */ +// WORD Type; /* one of CDRESOURCE_TYPE_xxx */ +// WORD ResourceClass; /* one of CDRESOURCE_CLASS_xxx */ +// WORD Length1; /* meaning depends on Type */ +// WORD ServerHintLength; /* length of the server hint */ +// WORD FileHintLength; /* length of the file hint */ +// BYTE Reserved[8]; + /* Variable length follows: + * String of size ServerHintLength: hint as to resource's server + * String of size FileHintLength: hint as to resource's file + * - if CDRESOURCE_TYPE_URL : + * string of size Length1 - the URL. + * - if CDRESOURCE_TYPE_NOTELINK: + * if CDRESOURCE_FLAGS_NOTELINKINLINE is NOT set in Flags: + * WORD LinkID - index into $Links + * string of size Length1 - the anchor name (optional) + * if CDRESOURCE_FLAGS_NOTELINKINLINE is set in Flags: + * NOTELINK NoteLink + * string of size Length1 - the anchor name (optional) + * - if CDRESOURCE_TYPE_NAMEDELEMENT : + * TIMEDATE ReplicaID (zero if current db) + * string of size Length1 - the name of element + */ +// } CDRESOURCE; + + if (cdResourceStruct.Type == NotesConstants.CDRESOURCE_TYPE_NAMEDELEMENT) { + if (cdResourceStruct.ResourceClass == NotesConstants.CDRESOURCE_CLASS_SUBFORM) { + NotesTimeDateStruct replicaId = NotesTimeDateStruct.newInstance( + href2RecordWithHeader + .share(cdResourceStruct.size())); + replicaId.read(); + String replicaIdStr = NotesStringUtils.innardsToReplicaId(replicaId.Innards); + + String subformName = NotesStringUtils.fromLMBCS( + href2RecordWithHeader + .share(cdResourceStruct.size() + NotesConstants.timeDateSize), // => TIMEDATE is replica id + cdResourceStruct.Length1); + subforms.add(new Pair<>(replicaIdStr, subformName)); + } + } + } + } + } + } + while (rtNav.gotoNext()); + } + + if (oldPos!=null) { + rtNav.restoreCurrentRecordPosition(oldPos); + } + + return subforms; + } + + /** + * Traverses the richtext CD records (of a design element's $body item) + * and collects all formulas computing the name of a subform. Restores the + * current {@link RichTextNavPosition} in the richtext item if not + * null. + * + * @param rtNav richtext navigator + * @return subforms formulas + */ + public static List collectSubformFormulas(IRichTextNavigator rtNav) { + List subforms = new ArrayList(); + + if (rtNav==null) { + return subforms; + } + + RichTextNavPosition oldPos = rtNav.getCurrentRecordPosition(); + + if (rtNav.gotoFirst()) { + boolean inBeginEnd = false; + + do { + if (CDRecordType.BEGIN.getConstant() == rtNav.getCurrentRecordTypeAsShort()) { + inBeginEnd = true; + } + else if (CDRecordType.END.getConstant() == rtNav.getCurrentRecordTypeAsShort()) { + inBeginEnd = false; + } + else if (CDRecordType.V4HOTSPOTBEGIN.getConstant() == rtNav.getCurrentRecordTypeAsShort()) { + if (inBeginEnd) { +// [V4HOTSPOTBEGIN] +// Record type: 65453 (V4HOTSPOTBEGIN) +// Total length: 76 +// Header length: 4 +// Data length: 72 +// +// [ad ff 4c 00 0e 00 18 00] [..L.....] +// [00 00 40 00 40 00 00 00] [..@.@...] +// [32 00 05 00 01 00 78 00] [2.....x.] +// [01 00 00 00 0a 02 af 00] [........] +// [1e 00 12 00 01 00 08 00] [........] +// [53 75 62 66 6f 72 6d 32] [Subform2] +// [ae 00 0c 00 01 00 00 00] [........] +// [ae 00 04 00 b5 03 03 00] [........] +// [07 00 0c 00 05 00 09 30] [.......0] +// [53 30 45 00 ] [S0E. ] + + Memory v4HotspotbeginRecordWithHeader = rtNav.getCurrentRecordDataWithHeader(); + + NotesCdHotspotBeginStruct v4HotspotBegin = NotesCdHotspotBeginStruct.newInstance(v4HotspotbeginRecordWithHeader); + v4HotspotBegin.read(); + + if (v4HotspotBegin.Type == NotesConstants.HOTSPOTREC_TYPE_SUBFORM) { + if ((v4HotspotBegin.Flags & NotesConstants.HOTSPOTREC_RUNFLAG_FORMULA) == NotesConstants.HOTSPOTREC_RUNFLAG_FORMULA) { + Pointer compiledFormulaPtr = v4HotspotbeginRecordWithHeader.share(12); + String formula = FormulaDecompiler.decompileFormula(compiledFormulaPtr); + subforms.add(formula); + } + } + } + } + } + while (rtNav.gotoNext()); + } + + if (oldPos!=null) { + rtNav.restoreCurrentRecordPosition(oldPos); + } + + return subforms; + } }