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