OpenpackagingUtils.java

1
package pro.verron.officestamper.utils.openpackaging;
2
3
import org.docx4j.openpackaging.contenttype.ContentType;
4
import org.docx4j.openpackaging.contenttype.ContentTypeManager;
5
import org.docx4j.openpackaging.contenttype.ContentTypes;
6
import org.docx4j.openpackaging.exceptions.Docx4JException;
7
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
8
import org.docx4j.openpackaging.exceptions.PartUnrecognisedException;
9
import org.docx4j.openpackaging.packages.OpcPackage;
10
import org.docx4j.openpackaging.packages.PresentationMLPackage;
11
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
12
import org.docx4j.openpackaging.parts.DefaultXmlPart;
13
import org.docx4j.openpackaging.parts.Part;
14
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
15
import org.docx4j.openpackaging.parts.XmlPart;
16
import org.docx4j.openpackaging.parts.relationships.Namespaces;
17
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
18
import org.w3c.dom.Document;
19
import pro.verron.officestamper.utils.UtilsException;
20
import pro.verron.officestamper.utils.image.ImgPart;
21
import pro.verron.officestamper.utils.image.ImgUtils;
22
import pro.verron.officestamper.utils.svg.SvgUtils;
23
24
import java.io.InputStream;
25
import java.io.OutputStream;
26
import java.util.Arrays;
27
import java.util.Objects;
28
import java.util.Optional;
29
30
import static pro.verron.officestamper.utils.openpackaging.OpenpackagingFactory.setupRelationship;
31
32
/// Utility class for working with Open Packaging documents. This class provides methods to load and export Word
33
/// documents using DOCX4J
34
public class OpenpackagingUtils {
35
    private OpenpackagingUtils() {
36
        throw new UtilsException("Utility class shouldn't be instantiated");
37
    }
38
39
    /// Loads a Word document from the provided input stream.
40
    ///
41
    /// @param is the input stream containing the Word document data
42
    ///
43
    /// @return a WordprocessingMLPackage representing the loaded document
44
    ///
45
    /// @throws UtilsException if there is an error loading the document
46
    public static WordprocessingMLPackage loadWord(InputStream is) {
47
        try {
48 1 1. loadWord : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::loadWord → NO_COVERAGE
            return WordprocessingMLPackage.load(is);
49
        } catch (Docx4JException e) {
50
            throw new UtilsException(e);
51
        }
52
    }
53
54
    /// Exports a Word document to the provided output stream.
55
    ///
56
    /// @param wordprocessingMLPackage the Word document to export
57
    /// @param os the output stream to write the document to
58
    ///
59
    /// @throws UtilsException if there is an error exporting the document
60
    public static void exportWord(WordprocessingMLPackage wordprocessingMLPackage, OutputStream os) {
61
        try {
62 1 1. exportWord : removed call to org/docx4j/openpackaging/packages/WordprocessingMLPackage::save → NO_COVERAGE
            wordprocessingMLPackage.save(os);
63
        } catch (Docx4JException e) {
64
            throw new UtilsException(e);
65
        }
66
    }
67
68
69
    /// Loads a PowerPoint document from the provided input stream.
70
    ///
71
    /// @param is the input stream containing the PowerPoint document data
72
    ///
73
    /// @return a PresentationMLPackage representing the loaded document
74
    ///
75
    /// @throws UtilsException if there is an error loading the document
76
    public static PresentationMLPackage loadPowerPoint(InputStream is) {
77
        try {
78 1 1. loadPowerPoint : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::loadPowerPoint → NO_COVERAGE
            return PresentationMLPackage.load(is);
79
        } catch (Docx4JException e) {
80
            throw new UtilsException(e);
81
        }
82
    }
83
84
85
    /// Exports a PowerPoint document to the provided output stream.
86
    ///
87
    /// @param presentationMLPackage the PowerPoint document to export
88
    /// @param os the output stream to write the document to
89
    ///
90
    /// @throws UtilsException if there is an error exporting the document
91
    public static void exportPowerPoint(PresentationMLPackage presentationMLPackage, OutputStream os) {
92
        try {
93 1 1. exportPowerPoint : removed call to org/docx4j/openpackaging/packages/PresentationMLPackage::save → NO_COVERAGE
            presentationMLPackage.save(os);
94
        } catch (Docx4JException e) {
95
            throw new UtilsException(e);
96
        }
97
    }
98
99
    public static Optional<ImgPart> findImgPart(OpcPackage opcPackage, Part sourcePart, byte[] bytes) {
100 1 1. findImgPart : negated conditional → NO_COVERAGE
        if (bytes.length == 0) throw new UtilsException("Can't create image from empty byte array");
101
102
        var format = ImgUtils.detectFormat(bytes)
103 1 1. lambda$findImgPart$0 : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::lambda$findImgPart$0 → NO_COVERAGE
                             .orElseThrow(() -> new UtilsException("Could not detect a supported image type."));
104
105
        var mimeType = ImgUtils.supportedContentType(format.name())
106 1 1. lambda$findImgPart$1 : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::lambda$findImgPart$1 → NO_COVERAGE
                               .orElseThrow(() -> new UtilsException("Unsupported image " + "type"));
107
108 1 1. findImgPart : removed call to pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::ensureHasRelationshipPart → NO_COVERAGE
        ensureHasRelationshipPart(sourcePart);
109
        var relationshipId = createRelationshipId(sourcePart);
110
        var ctm = opcPackage.getContentTypeManager();
111
        var isSvg = mimeType.equals(ContentTypes.IMAGE_SVG);
112
        var parts = sourcePart.getPackage()
113
                              .getParts()
114
                              .getParts();
115
        for (var part : parts.values()) {
116
            switch (part) {
117 1 1. findImgPart : negated conditional → NO_COVERAGE
                case DefaultXmlPart xmlPart when isSvg -> {
118
                    var existingXml = extractXml(xmlPart);
119
                    var newXml = extractXml(bytes, ctm);
120 1 1. findImgPart : negated conditional → NO_COVERAGE
                    if (Objects.equals(newXml, existingXml)) {
121
                        var relationship = setupRelationship(sourcePart, xmlPart, relationshipId);
122 1 1. findImgPart : replaced return value with Optional.empty for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::findImgPart → NO_COVERAGE
                        return Optional.of(new ImgPart(format, relationship));
123
                    }
124
                }
125
                case BinaryPartAbstractImage imagePart -> {
126 1 1. findImgPart : negated conditional → NO_COVERAGE
                    if (Arrays.equals(imagePart.getBytes(), bytes)) {
127
                        var relationship = setupRelationship(sourcePart, imagePart, relationshipId);
128 1 1. findImgPart : replaced return value with Optional.empty for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::findImgPart → NO_COVERAGE
                        return Optional.of(new ImgPart(format, relationship));
129
                    }
130
                }
131
                case null, default -> { /* DO NOTHING */ }
132
            }
133
        }
134
        return Optional.empty();
135
    }
136
137
    static void ensureHasRelationshipPart(Part sourcePart) {
138 1 1. ensureHasRelationshipPart : negated conditional → NO_COVERAGE
        if (sourcePart.getRelationshipsPart() == null) RelationshipsPart.createRelationshipsPartForPart(sourcePart);
139
    }
140
141
    static String createRelationshipId(Part sourcePart) {
142
        var relationshipsPart = sourcePart.getRelationshipsPart();
143 1 1. createRelationshipId : replaced return value with "" for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::createRelationshipId → NO_COVERAGE
        return relationshipsPart.getNextId();
144
    }
145
146
    private static String extractXml(XmlPart xmlPart) {
147
        String existingXml;
148
        try {
149
            existingXml = xmlPart.getXML();
150
        } catch (Docx4JException e) {
151
            throw new RuntimeException(e);
152
        }
153 1 1. extractXml : replaced return value with "" for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::extractXml → NO_COVERAGE
        return existingXml;
154
    }
155
156
    private static String extractXml(byte[] bytes, ContentTypeManager ctm) {
157
        var newDocument = SvgUtils.parseDocument(bytes);
158
        var svgPart = createSvgPart(newDocument, ctm, "/temporary");
159 1 1. extractXml : replaced return value with "" for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::extractXml → NO_COVERAGE
        return extractXml(svgPart);
160
    }
161
162
    static XmlPart createSvgPart(
163
            Document document,
164
            ContentTypeManager contentTypeManager,
165
            String partName
166
    ) {
167
        XmlPart part;
168
        try {
169
            part = (XmlPart) contentTypeManager.newPartForContentType(ContentTypes.IMAGE_SVG, partName, null);
170
        } catch (InvalidFormatException | PartUnrecognisedException e) {
171
            throw new UtilsException(e);
172
        }
173 1 1. createSvgPart : removed call to org/docx4j/openpackaging/parts/XmlPart::setRelationshipType → NO_COVERAGE
        part.setRelationshipType(Namespaces.IMAGE);
174 1 1. createSvgPart : removed call to org/docx4j/openpackaging/parts/XmlPart::setContentType → NO_COVERAGE
        part.setContentType(new ContentType(ContentTypes.IMAGE_SVG));
175 1 1. createSvgPart : removed call to org/docx4j/openpackaging/parts/XmlPart::setDocument → NO_COVERAGE
        part.setDocument(document);
176 1 1. createSvgPart : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::createSvgPart → NO_COVERAGE
        return part;
177
    }
178
}

Mutations

48

1.1
Location : loadWord
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::loadWord → NO_COVERAGE

62

1.1
Location : exportWord
Killed by : none
removed call to org/docx4j/openpackaging/packages/WordprocessingMLPackage::save → NO_COVERAGE

78

1.1
Location : loadPowerPoint
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::loadPowerPoint → NO_COVERAGE

93

1.1
Location : exportPowerPoint
Killed by : none
removed call to org/docx4j/openpackaging/packages/PresentationMLPackage::save → NO_COVERAGE

100

1.1
Location : findImgPart
Killed by : none
negated conditional → NO_COVERAGE

103

1.1
Location : lambda$findImgPart$0
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::lambda$findImgPart$0 → NO_COVERAGE

106

1.1
Location : lambda$findImgPart$1
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::lambda$findImgPart$1 → NO_COVERAGE

108

1.1
Location : findImgPart
Killed by : none
removed call to pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::ensureHasRelationshipPart → NO_COVERAGE

117

1.1
Location : findImgPart
Killed by : none
negated conditional → NO_COVERAGE

120

1.1
Location : findImgPart
Killed by : none
negated conditional → NO_COVERAGE

122

1.1
Location : findImgPart
Killed by : none
replaced return value with Optional.empty for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::findImgPart → NO_COVERAGE

126

1.1
Location : findImgPart
Killed by : none
negated conditional → NO_COVERAGE

128

1.1
Location : findImgPart
Killed by : none
replaced return value with Optional.empty for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::findImgPart → NO_COVERAGE

138

1.1
Location : ensureHasRelationshipPart
Killed by : none
negated conditional → NO_COVERAGE

143

1.1
Location : createRelationshipId
Killed by : none
replaced return value with "" for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::createRelationshipId → NO_COVERAGE

153

1.1
Location : extractXml
Killed by : none
replaced return value with "" for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::extractXml → NO_COVERAGE

159

1.1
Location : extractXml
Killed by : none
replaced return value with "" for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::extractXml → NO_COVERAGE

173

1.1
Location : createSvgPart
Killed by : none
removed call to org/docx4j/openpackaging/parts/XmlPart::setRelationshipType → NO_COVERAGE

174

1.1
Location : createSvgPart
Killed by : none
removed call to org/docx4j/openpackaging/parts/XmlPart::setContentType → NO_COVERAGE

175

1.1
Location : createSvgPart
Killed by : none
removed call to org/docx4j/openpackaging/parts/XmlPart::setDocument → NO_COVERAGE

176

1.1
Location : createSvgPart
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::createSvgPart → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.23.1 support