@@ -69,29 +69,28 @@ public class PreprocessorContext {
6969 List .of ("java" , "txt" , "htm" , "html" );
7070 public static final List <String > DEFAULT_EXCLUDED_EXTENSIONS = singletonList ("xml" );
7171 public static final Charset DEFAULT_CHARSET = StandardCharsets .UTF_8 ;
72-
72+ private static final List <AbstractDirectiveHandler > directiveHandlers =
73+ AbstractDirectiveHandler .findAllDirectives ();
7374 private final Map <String , Value > globalVarTable = new HashMap <>();
7475 private final Map <String , Value > localVarTable = new HashMap <>();
7576 private final Map <String , SpecialVariableProcessor > mapVariableNameToSpecialVarProcessor =
7677 new HashMap <>();
7778 private final Map <String , Object > sharedResources = new HashMap <>();
7879 private final List <File > configFiles = new ArrayList <>();
79-
8080 @ Setter (AccessLevel .NONE )
8181 private final boolean cloned ;
8282 @ Setter (AccessLevel .NONE )
8383 private final TextFileDataContainer currentInCloneSource ;
8484 private final List <SourceFolder > sources = new ArrayList <>();
8585 private final File baseDir ;
8686 private final Collection <File > activatedConfigFiles ;
87-
8887 @ Setter (AccessLevel .NONE )
8988 @ Getter (AccessLevel .NONE )
9089 private final Collection <FileInfoContainer > preprocessedResources ;
91-
9290 @ Setter (AccessLevel .NONE )
9391 @ Getter (AccessLevel .NONE )
9492 private final AtomicReference <PreprocessingState > preprocessingState = new AtomicReference <>();
93+ private final List <CommentTextProcessor > commentTextProcessors ;
9594 private String eol = GetUtils
9695 .ensureNonNull (System .getProperty ("jcp.line.separator" , System .getProperty ("line.separator" )),
9796 "\n " );
@@ -116,8 +115,6 @@ public class PreprocessorContext {
116115 @ Setter (AccessLevel .NONE )
117116 private PreprocessorLogger preprocessorLogger = new SystemOutLogger ();
118117 private List <String > excludeFolders = new ArrayList <>();
119- private static final List <AbstractDirectiveHandler > directiveHandlers = AbstractDirectiveHandler .findAllDirectives ();
120- private final List <CommentTextProcessor > commentTextProcessors ;
121118
122119 /**
123120 * Constructor
@@ -135,7 +132,7 @@ public PreprocessorContext(final File baseDir) {
135132 this .currentInCloneSource = null ;
136133 this .commentTextProcessors = new ArrayList <>();
137134 this .preprocessingState
138- .set (new PreprocessingState (this , this .sourceEncoding , this .targetEncoding ));
135+ .set (new PreprocessingState (this , this .sourceEncoding , this .targetEncoding ));
139136 }
140137
141138 /**
@@ -200,6 +197,52 @@ public PreprocessorContext(final PreprocessorContext context) {
200197 this .currentInCloneSource = context .getPreprocessingState ().peekFile ();
201198 }
202199
200+ private static String makeStackView (
201+ final TextFileDataContainer cloneSource ,
202+ final boolean cloned ,
203+ final List <TextFileDataContainer > list
204+ ) {
205+ if (list == null || list .isEmpty ()) {
206+ return "" ;
207+ }
208+ final StringBuilder builder = new StringBuilder ();
209+ int tab = 5 ;
210+
211+ builder .append (" " .repeat (tab ));
212+
213+ builder .append ('{' );
214+ if (cloned ) {
215+ builder .append (cloneSource == null ? "*No src info" :
216+ "*" + cloneSource .getFile ().getName () + ':' + cloneSource .getNextStringIndex ());
217+ } else {
218+ builder .append ("File chain" );
219+ }
220+ builder .append ('}' );
221+ tab += 5 ;
222+
223+ int fileIndex = 1 ;
224+ for (int i = list .size () - 1 ; i >= 0 ; i --) {
225+ final TextFileDataContainer cur = list .get (i );
226+ builder .append ('\n' );
227+ builder .append (" " .repeat (Math .max (0 , tab )));
228+ builder .append ("└>" );
229+ builder .append (fileIndex ++).append (". " );
230+ builder .append (cur .getFile ().getName ()).append (':' ).append (cur .getLastReadStringIndex () + 1 );
231+ tab += 3 ;
232+ }
233+
234+ return builder .toString ();
235+ }
236+
237+ private static Charset decodeCharset (final String charsetName ) {
238+ final String normalized = charsetName .trim ();
239+ if (Charset .isSupported (normalized )) {
240+ return Charset .forName (normalized );
241+ } else {
242+ throw new IllegalArgumentException ("Unsupported charset: " + charsetName );
243+ }
244+ }
245+
203246 /**
204247 * Add comment text processor.
205248 *
@@ -222,6 +265,7 @@ public void removeCommentTextProcessor(final CommentTextProcessor commentTextPro
222265
223266 /**
224267 * Get all directive handlers allowed for processing.
268+ *
225269 * @return list of direction handlers for the context
226270 * @since 7.0.6
227271 */
@@ -268,52 +312,6 @@ public void fireNotificationStop(final Throwable error) {
268312 .values ().forEach (x -> x .onContextStopped (this , error ));
269313 }
270314
271- private static String makeStackView (
272- final TextFileDataContainer cloneSource ,
273- final boolean cloned ,
274- final List <TextFileDataContainer > list
275- ) {
276- if (list == null || list .isEmpty ()) {
277- return "" ;
278- }
279- final StringBuilder builder = new StringBuilder ();
280- int tab = 5 ;
281-
282- builder .append (" " .repeat (tab ));
283-
284- builder .append ('{' );
285- if (cloned ) {
286- builder .append (cloneSource == null ? "*No src info" :
287- "*" + cloneSource .getFile ().getName () + ':' + cloneSource .getNextStringIndex ());
288- } else {
289- builder .append ("File chain" );
290- }
291- builder .append ('}' );
292- tab += 5 ;
293-
294- int fileIndex = 1 ;
295- for (int i = list .size () - 1 ; i >= 0 ; i --) {
296- final TextFileDataContainer cur = list .get (i );
297- builder .append ('\n' );
298- builder .append (" " .repeat (Math .max (0 , tab )));
299- builder .append ("└>" );
300- builder .append (fileIndex ++).append (". " );
301- builder .append (cur .getFile ().getName ()).append (':' ).append (cur .getLastReadStringIndex () + 1 );
302- tab += 3 ;
303- }
304-
305- return builder .toString ();
306- }
307-
308- private static Charset decodeCharset (final String charsetName ) {
309- final String normalized = charsetName .trim ();
310- if (Charset .isSupported (normalized )) {
311- return Charset .forName (normalized );
312- } else {
313- throw new IllegalArgumentException ("Unsupported charset: " + charsetName );
314- }
315- }
316-
317315 /**
318316 * Find all files which have been used during preprocess, it includes configs, source files, copied files,
319317 * generated files, included files and binary files used by functions. Excluded files are not added if
@@ -841,13 +839,40 @@ public File createDestinationFileForPath(final String path) {
841839 }
842840
843841 /**
844- * Finds file in source folders, the file can be found only inside source folders and external placement is disabled for security purposes.
842+ * Ensure that the file is in the project folder hierarchy.
843+ *
844+ * @param file the file to be checked
845+ * @return true if there is no info about hierarchy or the file in the hierarchy, false if the file is outbounds
846+ * @since 7.2.1
847+ */
848+ public boolean isFileInBaseDir (final File file ) {
849+ final String normalizedPath =
850+ FilenameUtils .normalizeNoEndSeparator (file .getAbsolutePath ());
851+ return normalizedPath .startsWith (
852+ FilenameUtils .normalizeNoEndSeparator (this .baseDir .getAbsolutePath ()));
853+ }
854+
855+ /**
856+ * It finds file among source folders, the file can be found only among source folders and
857+ * any outside place is disabled for security purposes.
845858 *
846859 * @param path the file path to find, it must not be null and must be existing file
847- * @return detected file object for the path, must not be null
848- * @throws IOException if it is impossible to find a file for the path
860+ * @return found existing file object for the path, must not be null
849861 */
850- public File findFileInSources (final String path ) throws IOException {
862+ public File findFileInSources (final String path ) {
863+ return this .findFileInSources (path , true );
864+ }
865+
866+ /**
867+ * It finds file among source folders, the file can be found only among source folders and
868+ * any outside place is disabled for security purposes.
869+ *
870+ * @param path the file path to find, it must not be null and must be existing file
871+ * @param mustExist if true then the file must exist, false otherwise
872+ * @return created file object for the path
873+ * @since 7.2.1
874+ */
875+ public File findFileInSources (final String path , final boolean mustExist ) {
851876 if (path == null ) {
852877 throw makeException ("File path is null" , null );
853878 }
@@ -890,7 +915,7 @@ public File findFileInSources(final String path) throws IOException {
890915 final List <File > setOfFoundFiles = new ArrayList <>();
891916 getSources ().stream ().map ((root ) -> new File (root .getAsFile (), path ))
892917 .filter ((variant ) -> (variant .exists () && variant .isFile ())).forEachOrdered (
893- setOfFoundFiles ::add );
918+ setOfFoundFiles ::add );
894919
895920 if (setOfFoundFiles .size () == 1 ) {
896921 result = setOfFoundFiles .get (0 );
@@ -904,7 +929,7 @@ public File findFileInSources(final String path) throws IOException {
904929 if (result == null ) {
905930 throw makeException ("Can't find file for path '" + path +
906931 "' among source files registered for preprocessing." , null );
907- } else if (!result .isFile ()) {
932+ } else if (mustExist && !result .isFile ()) {
908933 throw makeException ("File '" + PreprocessorUtils .getFilePath (result ) +
909934 "' is either not found or not a file" , null );
910935 }
0 commit comments