
001package org.hl7.fhir.r5.renderers; 002 003import java.io.IOException; 004import java.nio.charset.StandardCharsets; 005import java.util.ArrayList; 006import java.util.Base64; 007import java.util.List; 008import java.util.Map; 009 010import org.hl7.fhir.r5.elementmodel.Element; 011import org.hl7.fhir.r5.model.Binary; 012import org.hl7.fhir.utilities.FileUtilities; 013import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 014import org.hl7.fhir.utilities.Utilities; 015import org.hl7.fhir.utilities.xhtml.NodeType; 016import org.hl7.fhir.utilities.xhtml.XhtmlComposer; 017import org.hl7.fhir.utilities.xhtml.XhtmlNode; 018 019@MarkedToMoveToAdjunctPackage 020public class BinaryRenderer { 021 022 private String folder; 023 private List<String> filenames = new ArrayList<String>(); 024 private Map<String, String> scriptMappings; 025 026 public BinaryRenderer(String folder, Map<String, String> scriptMappings) { 027 super(); 028 this.folder = folder; 029 this.scriptMappings = scriptMappings; 030 } 031 032 public String getFolder() { 033 return folder; 034 } 035 036 public List<String> getFilenames() { 037 return filenames; 038 } 039 040 public static String getBinContentAsString(byte[] bin) { 041 // for now, assume UTF8. To do: extract character encoding from mime type if possible (charset) 042 return new String(bin, StandardCharsets.UTF_8); 043 } 044 045 public String display(Binary bin) throws IOException { 046 XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); 047 render(div, bin); 048 return new XhtmlComposer(false, true).compose(div); 049 } 050 051 public String display(Element bin) throws IOException { 052 XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); 053 render(div, bin); 054 return new XhtmlComposer(false, true).compose(div); 055 } 056 057 public String display(String id, String ct, byte[] cnt) throws IOException { 058 XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); 059 render(div, id, ct, cnt); 060 return new XhtmlComposer(false, true).compose(div); 061 } 062 063 public void render(XhtmlNode x, Binary bin) throws IOException { 064 String ct = bin.getContentType(); 065 byte[] cnt = bin.getContent(); 066 render(x, bin.getId(), ct, cnt); 067 } 068 069 public void render(XhtmlNode x, Element bin) throws IOException { 070 String ct = bin.getNamedChildValue("contentType"); 071 String id = bin.getNamedChildValue("id"); 072 byte[] cnt = Base64.getMimeDecoder().decode(bin.getNamedChildValue("data")); 073 render(x, id, ct, cnt); 074 } 075 076 public void render(XhtmlNode x, String id, String ct, byte[] cnt) throws IOException { 077 filenames.clear(); 078 if (ct == null) { 079 error(x,"No Content Type"); 080 } else if (ct.startsWith("image/")) { 081 image(x, id, ct, cnt); 082 } else if (isXml(ct)) { 083 xml(x, cnt); 084 } else if (isJson(ct)) { 085 json(x, cnt); 086 } else if (isTtl(ct)) { 087 ttl(x, cnt); 088 } else if (isText(ct)) { 089 text(x, cnt, codeForMimeType(ct)); 090 } else { 091 error(x, "The Content Type '"+ct+"' is not rendered in this context"); 092 } 093 } 094 095 096 private String codeForMimeType(String ct) { 097 switch (ct) { 098 case "text/x-gherkin": return "gherkin language-gherkin"; 099 } 100 return scriptMappings.get(ct); 101 } 102 103 private void image(XhtmlNode x, String id, String ct, byte[] cnt) throws IOException { 104 String ext = null; 105 if (ct.startsWith("image/png")) { 106 ext = ".png"; 107 } else if (ct.startsWith("image/jpeg")) { 108 ext = ".jpg"; 109 } else if (ct.startsWith("image/gif")) { 110 ext = ".gif"; 111 } else if (ct.startsWith("image/svg")) { 112 ext = ".svg"; 113 } 114 115 if (ext == null) { 116 error(x, "The Image Type '"+ct+"' is not rendered in this context"); 117 } else { 118 String fn = "Binary-Native-"+id+ext; 119 FileUtilities.bytesToFile(cnt, Utilities.path(folder, fn)); 120 filenames.add(fn); 121 x.img("Binary-Native-"+id+ext, "binary"); 122 } 123 } 124 125 private void error(XhtmlNode x, String message) { 126 x.tx("["+message+"]"); 127 } 128 129 private boolean isXml(String ct) { 130 return ct.startsWith("text/xml") || ct.startsWith("application/xml") || ct.contains("+xml"); 131 } 132 133 private void xml(XhtmlNode x, byte[] cnt) { 134 String content = "\r\n"+getBinContentAsString(cnt); 135 XhtmlNode pre = x.pre("xml"); 136 pre.code(content); 137 } 138 139 private boolean isJson(String ct) { 140 return ct.startsWith("text/json") || ct.startsWith("application/json") || ct.contains("+json"); 141 } 142 143 private void json(XhtmlNode x, byte[] cnt) { 144 String content = "\r\n"+getBinContentAsString(cnt); 145 XhtmlNode pre = x.pre("json"); 146 pre.code(content); 147 } 148 149 private boolean isTtl(String ct) { 150 return ct.startsWith("text/rdf") || ct.contains("+turtle"); 151 } 152 153 private void ttl(XhtmlNode x, byte[] cnt) { 154 String content = "\r\n"+getBinContentAsString(cnt); 155 XhtmlNode pre = x.pre("rdf language-turtle"); 156 pre.code(content); 157 } 158 159 160 private boolean isText(String ct) { 161 return ct.startsWith("text/"); 162 } 163 164 private void text(XhtmlNode x, byte[] cnt, String code) { 165 String content = "\r\n"+getBinContentAsString(cnt); 166 XhtmlNode pre = x.pre(code); 167 pre.code(content); 168 } 169 170 171}