Skip to content

Instantly share code, notes, and snippets.

@jmini
Created May 9, 2022 22:02
Show Gist options
  • Save jmini/4acd5749543fb70b24242565f4edf6b9 to your computer and use it in GitHub Desktop.
Save jmini/4acd5749543fb70b24242565f4edf6b9 to your computer and use it in GitHub Desktop.
Decode drawio compressed xml
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.github.vlsi.mxgraph:jgraphx:4.2.2
//JAVA 8
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import com.mxgraph.util.mxXmlUtils;
public class decodeDiagram {
public static void main(String... args) throws Exception {
if (args == null || args.length != 1) {
System.err.println("Usage: " + decodeDiagram.class.getSimpleName() + " <file path>");
System.exit(1);
throw new IllegalStateException("Unreachable code");
}
Path file = Paths.get(args[0]);
if (!Files.exists(file)) {
System.err.println("Can not read file: " + file);
System.exit(1);
throw new IllegalStateException("Unreachable code");
}
String content = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
decodeDiagram instance = new decodeDiagram();
Document document = instance.getDiagramData(content);
printDocument(document, System.out);
}
public Document getDiagramData(String xmlString) throws DataFormatException, IOException {
Document xmlDocument = mxXmlUtils.parseXml(xmlString);
Node diagram = xmlDocument.getElementsByTagName("diagram")
.item(0);
String textContent = diagram.getTextContent();
if (!textContent.startsWith("<")) {
byte[] compressed = base64Decode(textContent);
byte[] decompressed = inflate(compressed);
textContent = urlDecode(new String(decompressed));
Document expanded = mxXmlUtils.parseXml(textContent);
Node imported = xmlDocument.importNode(expanded.getFirstChild(), true);
diagram.setTextContent(null);
diagram.appendChild(imported);
}
return xmlDocument;
}
private byte[] inflate(byte[] compressed) throws IOException, DataFormatException {
int compressedDataLength = 0;
Inflater compresser = new Inflater(true);
compresser.setInput(compressed, 0, compressed.length);
ByteArrayOutputStream o = new ByteArrayOutputStream(compressed.length);
byte[] result = new byte[1024];
try {
while (!compresser.finished()) {
compressedDataLength = compresser.inflate(result);
if (compressedDataLength == 0) {
break;
}
o.write(result, 0, compressedDataLength);
}
} finally {
o.close();
}
compresser.end();
return o.toByteArray();
}
private byte[] base64Decode(String input) {
return Base64.getDecoder()
.decode(input);
}
private String urlDecode(String input) {
return URLDecoder.decode(input);
}
public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "UTF-8")));
}
}
@jmini
Copy link
Author

jmini commented May 9, 2022

Script to uncompress drawio xml. Script can be executed using jbang.

Usage example:

With a doc.drawio file with following content:

<mxfile host="Electron" modified="2022-04-25T10:16:45.897Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/17.4.2 Chrome/100.0.4896.60 Electron/18.0.1 Safari/537.36" etag="5BqQubEyUl9RtjgusI6h" version="17.4.2" type="device"><diagram id="PLuXOcR_mGlr0jXjKg2p" name="Page-1">zVbfb5swEP5reOwUMBD2uKZZW2mbKmXSur05+ALeDI6MSaB//Uw4As7vVm3VJ3yf787cd99hHDLJqltFl+l3yUA43ohVDrlxPM91R6F5NEjdIuOx3wKJ4gydemDGnwDBEaIlZ1BYjlpKofnSBmOZ5xBrC6NKybXttpDCPnVJE9gDZjEV++gvznTaor5LevwOeJLiyUGEGxntfLGQIqVMrgcQmTpkoqTU7SqrJiAa7jpa2rivR3a376Ug15cE3CcZfbhj85/3f8gqKK9+hJ+frjDLiooS68WX1XVHgJJlzqBJMnLI9TrlGmZLGje7a9Nyg6U6E8ZyzXLBhZhIIdUmliwWCy+ODV5oJf/BYIeF8zAIzc5+Gd07gdJQDSAs6xZkBlrVxgV3O4ZrWznrvl0RQumgUz5iFAWSbPP2JJoF8vgMTvcpBGYkhaZUOpWJzKmY9ui1TXLv803KJVL7F7SucT5oqaVNPFRcPw7Wv5tUn7wAzZsKU2+MujNyU+/j0GjDxkFn93Ebqws82rRCliqGE+TgdGiqEtAn/ILWr2HupAQUCKr5yh7WV28pedsxYQFEzD80JpE3J+ErjYnrux9qTvzzpELOvjTfcGPFghYFj3dUf0TA3jkBHx6X8elxebnqu4vrnOrJhaoftCw40LIOu3g48IQHyU1l/Xd1Ry9uZGdoy8ag4c2zk2ds5wl30rSs7KXZaGpb88tlFrzxFRfFcPiKm0eBH5zUzTOuuNB7p9k1Zv9P0vag/7Ej0/8=</diagram></mxfile>

When ./decodeDiagram doc.drawio is executed, following is displayed:

<mxfile agent="5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/17.4.2 Chrome/100.0.4896.60 Electron/18.0.1 Safari/537.36" etag="5BqQubEyUl9RtjgusI6h" host="Electron" modified="2022-04-25T10:16:45.897Z" type="device" version="17.4.2">
  <diagram id="PLuXOcR_mGlr0jXjKg2p" name="Page-1">
    <mxGraphModel arrows="1" connect="1" dx="1106" dy="774" fold="1" grid="1" gridSize="10" guides="1" math="0" page="1" pageHeight="583" pageScale="1" pageWidth="413" shadow="0" tooltips="1">
      <root>
        <mxCell id="0"/>
        <mxCell id="1" parent="0"/>
        <mxCell id="IgmaPHdbTIZ3v5u-N69z-1" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" value="" vertex="1">
          <mxGeometry as="geometry" height="40" width="80" x="20" y="10"/>
        </mxCell>
        <mxCell edge="1" id="IgmaPHdbTIZ3v5u-N69z-2" parent="1" source="IgmaPHdbTIZ3v5u-N69z-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" target="IgmaPHdbTIZ3v5u-N69z-5">
          <mxGeometry as="geometry" relative="1"/>
        </mxCell>
        <mxCell id="IgmaPHdbTIZ3v5u-N69z-3" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" value="" vertex="1">
          <mxGeometry as="geometry" height="40" width="80" x="141" y="10"/>
        </mxCell>
        <mxCell edge="1" id="IgmaPHdbTIZ3v5u-N69z-4" parent="1" source="IgmaPHdbTIZ3v5u-N69z-1" style="endArrow=classic;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;exitX=1;exitY=0.75;exitDx=0;exitDy=0;" target="IgmaPHdbTIZ3v5u-N69z-3" value="">
          <mxGeometry as="geometry" height="50" relative="1" width="50">
            <mxPoint as="sourcePoint" x="21" y="118"/>
            <mxPoint as="targetPoint" x="71" y="68"/>
          </mxGeometry>
        </mxCell>
        <mxCell id="IgmaPHdbTIZ3v5u-N69z-5" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" value="" vertex="1">
          <mxGeometry as="geometry" height="40" width="80" x="262" y="10"/>
        </mxCell>
      </root>
    </mxGraphModel>
  </diagram>
</mxfile>

(see the *.drawio content in a separated gist)

See also:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment