Browse Source

REPORT-95630 batik 升到1.16

feature/x
Yuan.Wang 1 year ago
parent
commit
d81318655c
  1. 2
      fine-xmlgraphics/xmlgraphics-batik/README.md
  2. 2
      fine-xmlgraphics/xmlgraphics-batik/src/main/java/com/sun/xml/stream/xerces/impl/msg/DOMMessages.properties
  3. 6
      fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/apps/rasterizer/Main.java
  4. 10
      fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/bridge/DefaultExternalResourceSecurity.java
  5. 8
      fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/bridge/DefaultScriptSecurity.java
  6. 32
      fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/bridge/SVGImageElementBridge.java
  7. 65
      fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/bridge/svg12/XPathPatternContentSelector.java
  8. 134
      fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/dom/AbstractDocument.java
  9. 8
      fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/script/rhino/RhinoClassShutter.java
  10. 2
      fine-xmlgraphics/xmlgraphics-batik/src/main/resources/NOTICE
  11. 140
      fine-xmlgraphics/xmlgraphics-batik/src/main/resources/org/org/apache/batik/bridge/resources/Messages.properties
  12. BIN
      fine-xmlgraphics/xmlgraphics-batik/src/main/resources/org/org/apache/batik/bridge/resources/help.gif
  13. BIN
      fine-xmlgraphics/xmlgraphics-batik/src/main/resources/org/org/apache/batik/bridge/resources/move.gif

2
fine-xmlgraphics/xmlgraphics-batik/README.md

@ -1,2 +1,2 @@
源码地址:https://github.com/apache/xmlgraphics-batik <br>
版本:1.14
版本:1.16

2
fine-xmlgraphics/xmlgraphics-batik/src/main/java/com/sun/xml/stream/xerces/impl/msg/DOMMessages.properties

@ -13,7 +13,7 @@
# exception codes
DOMSTRING_SIZE_ERR = The specified range of text does not fit into a DOMString.
HIERARCHY_REQUEST_ERR = An attempt was made to insert a node where it is not permitted.
INDEX_SIZE_ERR = The index or size is negative, or greater than the allowed value.
INDEX_SIZE_ERR = The indexs or size is negative, or greater than the allowed value.
INUSE_ATTRIBUTE_ERR = An attempt is made to add an attribute that is already in use elsewhere.
INVALID_ACCESS_ERR = A parameter or an operation is not supported by the underlying object.
INVALID_CHARACTER_ERR = An invalid or illegal XML character is specified.

6
fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/apps/rasterizer/Main.java

@ -934,8 +934,10 @@ public class Main implements SVGConverterController {
ApplicationSecurityEnforcer securityEnforcer =
new ApplicationSecurityEnforcer(this.getClass(),
RASTERIZER_SECURITY_POLICY);
securityEnforcer.enforceSecurity(!c.getSecurityOff());
try {
securityEnforcer.enforceSecurity(!c.getSecurityOff());
} catch (UnsupportedOperationException e) {
}
String[] expandedSources = expandSources(sources);

10
fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/bridge/DefaultExternalResourceSecurity.java

@ -20,6 +20,9 @@ package org.apache.batik.bridge;
import org.apache.batik.util.ParsedURL;
import java.net.URI;
import java.net.URISyntaxException;
/**
* Default implementation for the <code>ExternalResourceSecurity</code> interface.
* It allows all types of external resources to be loaded, but only if they
@ -81,6 +84,13 @@ public class DefaultExternalResourceSecurity implements ExternalResourceSecurity
} else {
String docHost = docURL.getHost();
String externalResourceHost = externalResourceURL.getHost();
if (externalResourceHost == null && !DATA_PROTOCOL.equals(externalResourceURL.getProtocol())) {
try {
externalResourceHost = new URI(externalResourceURL.getPath()).getHost();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
if ((docHost != externalResourceHost) &&
((docHost == null) || (!docHost.equals(externalResourceHost)))){

8
fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/bridge/DefaultScriptSecurity.java

@ -20,6 +20,8 @@ package org.apache.batik.bridge;
import org.apache.batik.util.ParsedURL;
import static org.apache.batik.util.SVGConstants.SVG_SCRIPT_TYPE_JAVA;
/**
* Default implementation for the <code>ScriptSecurity</code> interface.
* It allows all types of scripts to be loaded, but only if they
@ -76,13 +78,17 @@ public class DefaultScriptSecurity implements ScriptSecurity {
ParsedURL docURL){
// Make sure that the archives comes from the same host
// as the document itself
if (docURL == null) {
if (docURL == null || SVG_SCRIPT_TYPE_JAVA.equals(scriptType)) {
se = new SecurityException
(Messages.formatMessage(ERROR_CANNOT_ACCESS_DOCUMENT_URL,
new Object[]{scriptURL}));
} else {
String docHost = docURL.getHost();
String scriptHost = scriptURL.getHost();
if (scriptHost == null && scriptURL.getPath() != null) {
scriptHost = new ParsedURL(scriptURL.getPath()).getHost();
}
if ((docHost != scriptHost) &&
((docHost == null) || (!docHost.equals(scriptHost)))) {

32
fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/bridge/SVGImageElementBridge.java

@ -175,33 +175,33 @@ public class SVGImageElementBridge extends AbstractGraphicsNodeBridge {
} else {
purl = new ParsedURL(baseURI, uriStr);
}
checkLoadExternalResource(ctx, e, purl);
return createImageGraphicsNode(ctx, e, purl);
}
protected GraphicsNode createImageGraphicsNode(BridgeContext ctx,
Element e,
ParsedURL purl) {
Rectangle2D bounds = getImageBounds(ctx, e);
if ((bounds.getWidth() == 0) || (bounds.getHeight() == 0)) {
ShapeNode sn = new ShapeNode();
sn.setShape(bounds);
return sn;
}
private void checkLoadExternalResource(BridgeContext ctx, Element e, ParsedURL purl) {
SVGDocument svgDoc = (SVGDocument)e.getOwnerDocument();
String docURL = svgDoc.getURL();
ParsedURL pDocURL = null;
if (docURL != null)
if (docURL != null) {
pDocURL = new ParsedURL(docURL);
}
UserAgent userAgent = ctx.getUserAgent();
try {
userAgent.checkLoadExternalResource(purl, pDocURL);
} catch (SecurityException secEx ) {
throw new BridgeException(ctx, e, secEx, ERR_URI_UNSECURE,
new Object[] {purl});
throw new BridgeException(ctx, e, secEx, ERR_URI_UNSECURE, new Object[] {purl});
}
}
protected GraphicsNode createImageGraphicsNode(BridgeContext ctx,
Element e,
ParsedURL purl) {
Rectangle2D bounds = getImageBounds(ctx, e);
if ((bounds.getWidth() == 0) || (bounds.getHeight() == 0)) {
ShapeNode sn = new ShapeNode();
sn.setShape(bounds);
return sn;
}
DocumentLoader loader = ctx.getDocumentLoader();

65
fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/bridge/svg12/XPathPatternContentSelector.java

@ -18,20 +18,22 @@
*/
package org.apache.batik.bridge.svg12;
import java.util.ArrayList;
import org.apache.xml.utils.PrefixResolver;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
import org.apache.batik.anim.dom.XBLOMContentElement;
import org.apache.batik.dom.AbstractDocument;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.xpath.XPathException;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.util.ArrayList;
import java.util.Iterator;
/**
* A class to handle the XPath Pattern syntax for XBL content elements.
*
@ -48,12 +50,7 @@ public class XPathPatternContentSelector extends AbstractContentSelector {
/**
* The XPath expression.
*/
protected XPath xpath;
/**
* The XPath context.
*/
protected XPathContext context;
protected XPathExpression xpath;
/**
* The selected nodes.
@ -81,10 +78,11 @@ public class XPathPatternContentSelector extends AbstractContentSelector {
* Parses the XPath selector.
*/
protected void parse() {
context = new XPathContext();
try {
xpath = new XPath(expression, null, prefixResolver, XPath.MATCH);
} catch (javax.xml.transform.TransformerException te) {
XPath xPathAPI = XPathFactory.newInstance().newXPath();
xPathAPI.setNamespaceContext(prefixResolver);
xpath = xPathAPI.compile(expression);
} catch (XPathExpressionException te) {
AbstractDocument doc
= (AbstractDocument) contentElement.getOwnerDocument();
throw doc.createXPathException
@ -173,9 +171,8 @@ public class XPathPatternContentSelector extends AbstractContentSelector {
protected void update(Node n) {
if (!isSelected(n)) {
try {
double matchScore
= xpath.execute(context, n, prefixResolver).num();
if (matchScore != XPath.MATCH_SCORE_NONE) {
Double matchScore = (Double) xpath.evaluate(n, XPathConstants.NUMBER);
if (matchScore != null) {
if (!descendantSelected(n)) {
nodes.add(n);
}
@ -186,7 +183,7 @@ public class XPathPatternContentSelector extends AbstractContentSelector {
n = n.getNextSibling();
}
}
} catch (javax.xml.transform.TransformerException te) {
} catch (XPathExpressionException te) {
AbstractDocument doc
= (AbstractDocument) contentElement.getOwnerDocument();
throw doc.createXPathException
@ -217,36 +214,20 @@ public class XPathPatternContentSelector extends AbstractContentSelector {
/**
* Xalan prefix resolver.
*/
protected class NSPrefixResolver implements PrefixResolver {
/**
* Get the base URI for this resolver. Since this resolver isn't
* associated with a particular node, returns null.
*/
public String getBaseIdentifier() {
return null;
}
protected class NSPrefixResolver implements NamespaceContext {
/**
* Resolves the given namespace prefix.
*/
public String getNamespaceForPrefix(String prefix) {
public String getNamespaceURI(String prefix) {
return contentElement.lookupNamespaceURI(prefix);
}
/**
* Resolves the given namespace prefix.
*/
public String getNamespaceForPrefix(String prefix, Node context) {
// ignore the context node
return contentElement.lookupNamespaceURI(prefix);
public String getPrefix(String namespaceURI) {
return null;
}
/**
* Returns whether this PrefixResolver handles a null prefix.
*/
public boolean handlesNullPrefixes() {
return false;
public Iterator getPrefixes(String namespaceURI) {
return null;
}
}
}

134
fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/dom/AbstractDocument.java

@ -45,12 +45,6 @@ import org.apache.batik.util.DOMConstants;
import org.apache.batik.util.SoftDoublyIndexedTable;
import org.apache.batik.constants.XMLConstants;
import org.apache.xml.utils.PrefixResolver;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
import org.apache.xpath.objects.XObject;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
@ -79,6 +73,13 @@ import org.w3c.dom.xpath.XPathExpression;
import org.w3c.dom.xpath.XPathNSResolver;
import org.w3c.dom.xpath.XPathResult;
import javax.xml.namespace.NamespaceContext;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
/**
* This class implements the {@link org.w3c.dom.Document} interface.
*
@ -2177,7 +2178,7 @@ public abstract class AbstractDocument
/**
* The compiled XPath expression.
*/
protected XPath xpath;
protected javax.xml.xpath.XPathExpression xpath;
/**
* The namespace resolver.
@ -2189,11 +2190,6 @@ public abstract class AbstractDocument
*/
protected NSPrefixResolver prefixResolver;
/**
* The XPathContext object.
*/
protected XPathContext context;
/**
* Creates a new XPathExpr object.
*/
@ -2202,9 +2198,10 @@ public abstract class AbstractDocument
resolver = res;
prefixResolver = new NSPrefixResolver();
try {
xpath = new XPath(expr, null, prefixResolver, XPath.SELECT);
context = new XPathContext();
} catch (javax.xml.transform.TransformerException te) {
XPath xPathAPI = XPathFactory.newInstance().newXPath();
xPathAPI.setNamespaceContext(prefixResolver);
xpath = xPathAPI.compile(expr);
} catch (XPathExpressionException te) {
throw createXPathException
(XPathException.INVALID_EXPRESSION_ERR,
"xpath.invalid.expression",
@ -2245,48 +2242,25 @@ public abstract class AbstractDocument
new Object[] {(int) contextNode.getNodeType(),
contextNode.getNodeName() });
}
context.reset();
XObject result = null;
try {
result = xpath.execute(context, contextNode, prefixResolver);
} catch (javax.xml.transform.TransformerException te) {
throw createXPathException
(XPathException.INVALID_EXPRESSION_ERR,
"xpath.error",
new Object[] { xpath.getPatternString(),
te.getMessage() });
}
try {
switch (type) {
case XPathResult.ANY_UNORDERED_NODE_TYPE:
case XPathResult.FIRST_ORDERED_NODE_TYPE:
return convertSingleNode(result, type);
return new Result((Node) xpath.evaluate(contextNode, XPathConstants.NODE), type);
case XPathResult.BOOLEAN_TYPE:
return convertBoolean(result);
return new Result((Boolean) xpath.evaluate(contextNode, XPathConstants.BOOLEAN));
case XPathResult.NUMBER_TYPE:
return convertNumber(result);
return new Result((Double) xpath.evaluate(contextNode, XPathConstants.NUMBER));
case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
return convertNodeIterator(result, type);
return new Result((Node) xpath.evaluate(contextNode, XPathConstants.NODE), type);
case XPathResult.STRING_TYPE:
return convertString(result);
case XPathResult.ANY_TYPE:
switch (result.getType()) {
case XObject.CLASS_BOOLEAN:
return convertBoolean(result);
case XObject.CLASS_NUMBER:
return convertNumber(result);
case XObject.CLASS_STRING:
return convertString(result);
case XObject.CLASS_NODESET:
return convertNodeIterator
(result,
XPathResult.UNORDERED_NODE_ITERATOR_TYPE);
}
return new Result((String) xpath.evaluate(contextNode, XPathConstants.STRING));
}
} catch (javax.xml.transform.TransformerException te) {
} catch (XPathExpressionException | TransformerException te) {
throw createXPathException
(XPathException.TYPE_ERR,
"xpath.cannot.convert.result",
@ -2296,45 +2270,6 @@ public abstract class AbstractDocument
return null;
}
/**
* Converts an XObject to a single node XPathResult.
*/
protected Result convertSingleNode(XObject xo, short type)
throws javax.xml.transform.TransformerException {
return new Result(xo.nodelist().item(0), type);
}
/**
* Converts an XObject to a boolean XPathResult.
*/
protected Result convertBoolean(XObject xo)
throws javax.xml.transform.TransformerException {
return new Result(xo.bool());
}
/**
* Converts an XObject to a number XPathResult.
*/
protected Result convertNumber(XObject xo)
throws javax.xml.transform.TransformerException {
return new Result(xo.num());
}
/**
* Converts an XObject to a string XPathResult.
*/
protected Result convertString(XObject xo) {
return new Result(xo.str());
}
/**
* Converts an XObject to a node iterator XPathResult.
*/
protected Result convertNodeIterator(XObject xo, short type)
throws javax.xml.transform.TransformerException {
return new Result(xo.nodelist(), type);
}
/**
* XPathResult implementation.
* XXX Namespace nodes are not handled correctly, since Xalan returns
@ -2537,42 +2472,23 @@ public abstract class AbstractDocument
/**
* Xalan prefix resolver.
*/
protected class NSPrefixResolver implements PrefixResolver {
/**
* Get the base URI for this resolver. Since this resolver isn't
* associated with a particular node, returns null.
*/
public String getBaseIdentifier() {
return null;
}
protected class NSPrefixResolver implements NamespaceContext {
/**
* Resolves the given namespace prefix.
*/
public String getNamespaceForPrefix(String prefix) {
public String getNamespaceURI(String prefix) {
if (resolver == null) {
return null;
}
return resolver.lookupNamespaceURI(prefix);
}
/**
* Resolves the given namespace prefix.
*/
public String getNamespaceForPrefix(String prefix, Node context) {
// ignore the context node
if (resolver == null) {
return null;
}
return resolver.lookupNamespaceURI(prefix);
public String getPrefix(String namespaceURI) {
return null;
}
/**
* Returns whether this PrefixResolver handles a null prefix.
*/
public boolean handlesNullPrefixes() {
return false;
public Iterator getPrefixes(String namespaceURI) {
return null;
}
}
}

8
fine-xmlgraphics/xmlgraphics-batik/src/main/java/org/apache/batik/script/rhino/RhinoClassShutter.java

@ -20,6 +20,9 @@ package org.apache.batik.script.rhino;
import org.mozilla.javascript.ClassShutter;
import java.util.Arrays;
import java.util.List;
/**
* Class shutter that restricts access to Batik internals from script.
*
@ -27,6 +30,7 @@ import org.mozilla.javascript.ClassShutter;
* @version $Id$
*/
public class RhinoClassShutter implements ClassShutter {
private static final List<String> WHITELIST = Arrays.asList("java.io.PrintStream", "java.lang.System", "java.net.URL");
/*
public RhinoClassShutter() {
@ -55,6 +59,10 @@ public class RhinoClassShutter implements ClassShutter {
* Returns whether the given class is visible to scripts.
*/
public boolean visibleToScripts(String fullClassName) {
if (!WHITELIST.contains(fullClassName) && !fullClassName.endsWith("Permission") && !fullClassName.startsWith("org.")) {
return false;
}
// Don't let them mess with script engine's internals.
if (fullClassName.startsWith("org.mozilla.javascript"))
return false;

2
fine-xmlgraphics/xmlgraphics-batik/src/main/resources/NOTICE

@ -1,5 +1,5 @@
Apache Batik
Copyright 1999-2020 The Apache Software Foundation
Copyright 1999-2022 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

140
fine-xmlgraphics/xmlgraphics-batik/src/main/resources/org/org/apache/batik/bridge/resources/Messages.properties

@ -0,0 +1,140 @@
# -----------------------------------------------------------------------------
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# $Id$
# -----------------------------------------------------------------------------
attribute.missing = \
{0}:{1}\n\
The attribute "{3}" of the element <{2}> is required
attribute.malformed = \
{0}:{1}\n\
The attribute "{3}" of the element <{2}> is invalid
attribute.not.animatable = \
{0}:{1}\n\
The attribute "{4}" of the element <{3}> is not animatable
type.not.animatable = \
{0}:{1}\n\
The attribute "{4}" of the element <{3}> cannot be animated with the \
<{5}> element
length.negative = \
{0}:{1}\n\
The attribute "{3}" of the element <{2}> cannot be negative
css.length.negative = \
{0}:{1}\n\
The CSS property "{3}" found on the element <{2}> cannot be negative
css.uri.badTarget = \
{0}:{1}\n\
The URI "{3}"\n\
for a CSS property found on the element <{2}> is invalid
xlink.href.circularDependencies = \
{0}:{1}\n\
A circular dependency has been detected on the element <{2}> for the URI:\n\
"{3}"
uri.malformed = \
{0}:{1}\n\
The URI "{3}"\n\
specified on the element <{2}> is invalid
uri.badTarget = \
{0}:{1}\n\
Cannot find the referenced element:\n\
"{3}"\n\
specified on the element <{2}> - may be a problem of ''id''
uri.io = \
{0}:{1}\n\
An I/O error occured while processing the URI:\n\
"{3}"\n\
specified on the element <{2}>
uri.unsecure = \
{0}:{1}\n\
A security exception occured while processing the URI:\n\
"{3}"\n\
specified on the element <{2}>
uri.referenceDocument = \
{0}:{1}\n\
The URI "{3}"\n\
specified on the element <{2}> references an entire document. \n\
This is illegal: The element <{2}> must reference an element\n\
inside a document.
uri.image.invalid = \
{0}:{1}\n\
The URI "{3}"\n\
specified on the element <{2}> is invalid
uri.image.broken = \
{0}:{1}\n\
The URI "{3}"\n\
on element <{2}> can''t be opened because:\n\
{4}
uri.image.error = \
The URI can''t be opened:\n\
{0}
##########################################################################
# Messages for DefaultScriptSecurity
##########################################################################
DefaultScriptSecurity.error.cannot.access.document.url = \
Could not access the current document URL when trying to load script file {0}. Script will not be loaded as it is not possible to verify it comes from the same location as the document.
DefaultScriptSecurity.error.script.from.different.url = \
The document references a script file ({0}) which comes from different location than the document itself. This is not allowed with the current security settings and that script will not be loaded.
EmbededScriptSecurity.error.script.not.embeded = \
The document references a script file ({0}) which is not embeded in the document. This is not allowed with the current security settings and that script will not be loaded.
EmbededExternalResourceSecurity.error.external.resource.not.embeded = \
The document references a resource ({0}) which is not embeded in the document. This is not allowed with the current security settings and that resource cannot be loaded.
NoLoadScriptSecurity.error.no.script.of.type.allowed = \
Scripts of type ({0}) cannot be loaded and executed with the current security settings.
DefaultExternalResourceSecurity.error.cannot.access.document.url = \
Could not access the current document URL when trying to load an external resource {0}. The external resource will not be loaded as it is not possible to verify it comes from the same location as the document.
DefaultExternalResourceSecurity.error.external.resource.from.different.url = \
The document references a external resource ({0}) which comes from different location than the document itself. This is not allowed for security reasons and that resource will not be loaded.
NoLoadExternalResourceSecurity.error.no.external.resource.allowed = \
The security settings do not allow any external resources to be referenced from the document
##########################################################################
# Messages for BaseScriptingEnvironment
##########################################################################
BaseScriptingEnvironment.constant.inline.script.description = \
Inline {1} {0}:{2}
BaseScriptingEnvironment.constant.event.script.description = \
Event attribute {0}:{2} {1}
SVG12ScriptingEnvironment.constant.handler.script.description = \
Handler {0}:{3} {1} {2}

BIN
fine-xmlgraphics/xmlgraphics-batik/src/main/resources/org/org/apache/batik/bridge/resources/help.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

BIN
fine-xmlgraphics/xmlgraphics-batik/src/main/resources/org/org/apache/batik/bridge/resources/move.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Loading…
Cancel
Save