001package Torello.CSS; 002 003import Torello.Java.Additional.ByRef; 004 005import java.util.Vector; 006import java.util.function.Consumer; 007 008@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="CSS_TOK") 009public class Hash extends Identifier 010 implements CharSequence, java.io.Serializable, Comparable<CharSequence> 011{ 012 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 013 protected static final long serialVersionUID = 1; 014 015 016 // ******************************************************************************************** 017 // ******************************************************************************************** 018 // Public & Final Fields 019 // ******************************************************************************************** 020 // ******************************************************************************************** 021 022 023 public final boolean isID; 024 025 026 // ******************************************************************************************** 027 // ******************************************************************************************** 028 // Private Constructor, API "is" and "if" Methods 029 // ******************************************************************************************** 030 // ******************************************************************************************** 031 032 033 private Hash( 034 final int[] css, 035 final int sPos, 036 final int ePos, 037 final String identifier, 038 final boolean isID 039 ) 040 { 041 super(css, sPos, ePos, identifier); 042 this.isID = isID; 043 } 044 045 @Override 046 public final boolean isHash() { return true; } 047 048 @Override 049 public final Hash ifHash() { return this; } 050 051 052 // ******************************************************************************************** 053 // ******************************************************************************************** 054 // User's Constructor: a static "build" method 055 // ******************************************************************************************** 056 // ******************************************************************************************** 057 058 059 /** 060 * <EMBED CLASS=defs DATA-TOK=Hash DATA-P=hashIdentifier> 061 * <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_DESC> 062 * @param hashIdentifier <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_PARAM> 063 * @return <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_RET> 064 * @throws TokenizeException <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_TOK_EX> 065 */ 066 @SuppressWarnings("unchecked") 067 public static Hash build(final String hashIdentifier) 068 { return (Hash) CSSToken.build(hashIdentifier, INPUT_CHECKER, Hash::consume); } 069 070 private static final CSSToken.InputChecker INPUT_CHECKER = (int[] css) -> 071 { 072 if (css.length < 2) throw new TokenizeException(Hash.class); 073 074 if (! Hash.is(css, 0)) throw new TokenizeException 075 ("String-text beginning does not constitute a valid CSS Hash-Token"); 076 }; 077 078 079 // ******************************************************************************************** 080 // ******************************************************************************************** 081 // Tokenizer's "is" Method(s) 082 // ******************************************************************************************** 083 // ******************************************************************************************** 084 085 086 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 087 // Copied from: 088 // https://drafts.csswg.org/css-syntax-3/#consume-token 089 // March 27th, 2024 090 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 091 // U+0023 NUMBER SIGN (#) 092 // 093 // ** If the next input code point is an ident code point or the next two input code points are 094 // a valid escape, then [TRUE] 095 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 096 097 static boolean is(int[] css, final int sPos) 098 { 099 if (css[sPos] != '#') return false; 100 101 final int pos = sPos + 1; 102 103 if (pos >= css.length) return false; 104 105 if (Identifier.isIdentCodePoint(css[pos])) return true; 106 107 if ((pos + 1) >= css.length) return false; 108 109 return CSSUtil.isValidEscape(css, pos); 110 } 111 112 113 // ******************************************************************************************** 114 // ******************************************************************************************** 115 // CONSUME 116 // ******************************************************************************************** 117 // ******************************************************************************************** 118 119 120 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 121 // Copied from: 122 // https://drafts.csswg.org/css-syntax-3/#consume-token 123 // March 27th, 2024 124 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 125 // Create a <hash-token>. 126 // 127 // ** If the next 3 input code points would start an ident sequence, set the <hash-token>’s 128 // type flag to "id". 129 // ** Consume an ident sequence, and set the <hash-token>’s value to the returned string. 130 // ** Return the <hash-token>. 131 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 132 133 static void consume( // When invoked from 'CSSTokenizer' 134 final int[] css, // C, int[] css 135 final ByRef<Integer> POS, // P, array-pos loop-variable 136 final Consumer<CSSToken> returnParsedToken // T, Vector<CSSToken>.add 137 ) 138 { 139 final boolean isID = Identifier.startsIdentSequence(css, POS.f + 1); 140 final ByRef<String> identifier = new ByRef<String>(); 141 142 final int ePos = Identifier.consumeIdentSequence(css, POS.f + 1, identifier); 143 144 returnParsedToken.accept(new Hash(css, POS.f, ePos, identifier.f, isID)); 145 146 POS.f = ePos; 147 } 148}