diff --git a/src/net/sourceforge/plantuml/Option.java b/src/net/sourceforge/plantuml/Option.java index 4004bd28e..48874e634 100644 --- a/src/net/sourceforge/plantuml/Option.java +++ b/src/net/sourceforge/plantuml/Option.java @@ -85,6 +85,7 @@ public class Option { private boolean checkMetadata = false; private int stdrpt = 0; private int imageIndex = 0; + private String fileDir; private File outputDir = null; private File outputFile = null; @@ -188,6 +189,12 @@ public class Option { continue; } filename = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg[i]); + } else if (s.equalsIgnoreCase("-filedir")) { + i++; + if (i == arg.length) { + continue; + } + fileDir = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg[i]); } else if (s.startsWith("-o") && s.length() > 3) { s = s.substring(2); outputDir = new File(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(s)); @@ -670,4 +677,7 @@ public class Option { // this.preprocessorOutput = preprocessorOutput; // } + public String getFileDir() { + return fileDir; + } } diff --git a/src/net/sourceforge/plantuml/OptionPrint.java b/src/net/sourceforge/plantuml/OptionPrint.java index ee945cd3a..2af474629 100644 --- a/src/net/sourceforge/plantuml/OptionPrint.java +++ b/src/net/sourceforge/plantuml/OptionPrint.java @@ -153,6 +153,7 @@ public class OptionPrint { System.out.println(" -pipeimageindex N\tTo generate the Nth image with pipe option"); System.out.println(" -stdlib\t\tTo print standard library info"); System.out.println(" -extractstdlib\tTo extract PlantUML Standard Library into stdlib folder"); + System.out.println(" -filedir xxx\tTo behave as if the PlantUML source is in this dir (only affects '-pipe' and PicoWeb 'POST /render')"); System.out.println(" -filename \"example.puml\"\tTo override %filename% variable"); System.out.println(" -preproc\t\tTo output preprocessor text of diagrams"); System.out.println(" -cypher\t\tTo cypher texts of diagrams so that you can share them"); diff --git a/src/net/sourceforge/plantuml/Pipe.java b/src/net/sourceforge/plantuml/Pipe.java index d5413912a..ffe271519 100644 --- a/src/net/sourceforge/plantuml/Pipe.java +++ b/src/net/sourceforge/plantuml/Pipe.java @@ -46,6 +46,7 @@ import net.sourceforge.plantuml.core.Diagram; import net.sourceforge.plantuml.core.DiagramDescription; import net.sourceforge.plantuml.error.PSystemError; import net.sourceforge.plantuml.preproc.Defines; +import net.sourceforge.plantuml.security.SFile; public class Pipe { @@ -78,7 +79,9 @@ public class Pipe { } nb++; final Defines defines = option.getDefaultDefines(); - final SourceStringReader sourceStringReader = new SourceStringReader(defines, source, option.getConfig()); + final SFile newCurrentDir = option.getFileDir() == null ? null : new SFile(option.getFileDir()); + final SourceStringReader sourceStringReader = new SourceStringReader(defines, source, "UTF-8", + option.getConfig(), newCurrentDir); if (option.isComputeurl()) { for (BlockUml s : sourceStringReader.getBlocks()) { ps.println(s.getEncodedUrl()); diff --git a/src/net/sourceforge/plantuml/picoweb/PicoWebServer.java b/src/net/sourceforge/plantuml/picoweb/PicoWebServer.java index 0faec5899..ec4eb733a 100644 --- a/src/net/sourceforge/plantuml/picoweb/PicoWebServer.java +++ b/src/net/sourceforge/plantuml/picoweb/PicoWebServer.java @@ -68,6 +68,7 @@ import net.sourceforge.plantuml.core.ImageData; import net.sourceforge.plantuml.error.PSystemError; import net.sourceforge.plantuml.error.PSystemErrorUtils; import net.sourceforge.plantuml.graphic.QuoteUtils; +import net.sourceforge.plantuml.security.SFile; import net.sourceforge.plantuml.version.Version; public class PicoWebServer implements Runnable { @@ -174,13 +175,20 @@ public class PicoWebServer implements Runnable { } catch (Exception e) { throw new BadRequest400("Error parsing request json: " + e.getMessage(), e); } + + handleRenderRequest(renderRequest, out); + } + + public void handleRenderRequest(RenderRequest renderRequest, BufferedOutputStream out) throws Exception { final Option option = new Option(renderRequest.getOptions()); final String source = renderRequest.getSource().startsWith("@start") ? renderRequest.getSource() : "@startuml\n" + renderRequest.getSource() + "\n@enduml"; - final SourceStringReader ssr = new SourceStringReader(option.getDefaultDefines(), source, option.getConfig()); + final SFile newCurrentDir = option.getFileDir() == null ? null : new SFile(option.getFileDir()); + final SourceStringReader ssr = new SourceStringReader(option.getDefaultDefines(), source, "UTF-8", + option.getConfig(), newCurrentDir); final ByteArrayOutputStream os = new ByteArrayOutputStream(); final Diagram system; final ImageData imageData; @@ -258,4 +266,4 @@ public class PicoWebServer implements Runnable { os.write(s.getBytes("UTF-8")); } -} \ No newline at end of file +} diff --git a/test/net/sourceforge/plantuml/TestFileDirOption.java b/test/net/sourceforge/plantuml/TestFileDirOption.java new file mode 100644 index 000000000..d68165ef6 --- /dev/null +++ b/test/net/sourceforge/plantuml/TestFileDirOption.java @@ -0,0 +1,118 @@ +package net.sourceforge.plantuml; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static net.sourceforge.plantuml.test.TestUtils.writeUtf8File; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.util.Lists.newArrayList; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import net.sourceforge.plantuml.picoweb.PicoWebServer; +import net.sourceforge.plantuml.picoweb.RenderRequest; + +public class TestFileDirOption { + + @TempDir + Path tempDir; + + @BeforeEach + public void beforeEach() throws Exception { + + writeUtf8File(tempDir.resolve("include.iuml"), INCLUDE); + } + + // + // Test Cases + // + + @Test + public void test_picoweb_without_filedir_cannot_find_include() throws Exception { + + final String output = renderViaPicoWeb(); + assertThat(output).contains("cannot include include.iuml"); + } + + @Test + public void test_picoweb_with_filedir_succeeds() throws Exception { + + final String output = renderViaPicoWeb("-filedir", tempDir.toString()); + assertThat(output).contains("included-ok"); + } + + @Test + public void test_pipe_without_filedir_cannot_find_include() throws Exception { + + final String output = renderViaPipe(); + assertThat(output).contains("cannot include include.iuml"); + } + + @Test + public void test_pipe_with_filedir_succeeds() throws Exception { + + final String output = renderViaPipe("-filedir", tempDir.toString()); + assertThat(output).contains("included-ok"); + } + + // + // Test DSL + // + + private static final String[] COMMON_OPTIONS = {"-tutxt"}; + + private static final String DIAGRAM = "" + + "@startuml\n" + + "!include include.iuml\n" + + "a -> b\n" + + "@enduml\n"; + + private static final String INCLUDE = "title included-ok\n"; + + + private String[] optionArray(String... extraOptions) { + + final List list = newArrayList(COMMON_OPTIONS); + Collections.addAll(list, extraOptions); + return list.toArray(new String[0]); + } + + private String renderViaPicoWeb(String... extraOptions) throws Exception { + + final RenderRequest renderRequest = new RenderRequest(optionArray(extraOptions), DIAGRAM); + + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + final PicoWebServer picoWebServer = new PicoWebServer(null); + + picoWebServer.handleRenderRequest(renderRequest, new BufferedOutputStream(baos)); + + final String httpResponse = new String(baos.toByteArray(), UTF_8); + + return httpResponse.substring(httpResponse.indexOf("\n\r\n") + 3); // return just the HTTP body + } + + private String renderViaPipe(String... extraOptions) throws Exception { + + final Option option = new Option(optionArray(extraOptions)); + + final ByteArrayInputStream bais = new ByteArrayInputStream(DIAGRAM.getBytes(UTF_8)); + + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + final Pipe pipe = new Pipe(option, new PrintStream(baos), bais, option.getCharset()); + + pipe.managePipe(ErrorStatus.init()); + + return new String(baos.toByteArray(), UTF_8); + } + +} diff --git a/test/net/sourceforge/plantuml/test/TestUtils.java b/test/net/sourceforge/plantuml/test/TestUtils.java new file mode 100644 index 000000000..2506ddf4a --- /dev/null +++ b/test/net/sourceforge/plantuml/test/TestUtils.java @@ -0,0 +1,16 @@ +package net.sourceforge.plantuml.test; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class TestUtils { + + public static void writeUtf8File(Path path, String string) throws IOException { + + Files.createDirectories(path.getParent()); + Files.write(path, string.getBytes(UTF_8)); + } +}