1 package nl.dedicon.pipeline.braille.calabash.impl;
2
3 import com.xmlcalabash.core.XProcException;
4 import com.xmlcalabash.core.XProcRuntime;
5 import com.xmlcalabash.core.XProcStep;
6 import com.xmlcalabash.library.DefaultStep;
7 import com.xmlcalabash.runtime.XAtomicStep;
8 import java.io.File;
9 import java.io.IOException;
10 import java.net.URI;
11 import java.net.URISyntaxException;
12 import java.nio.file.Files;
13 import java.nio.file.Path;
14 import java.util.Arrays;
15 import net.sf.saxon.s9api.QName;
16 import net.sf.saxon.s9api.SaxonApiException;
17 import org.apache.commons.lang3.StringUtils;
18 import org.daisy.common.xproc.calabash.XProcStepProvider;
19 import org.osgi.service.component.annotations.Component;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23
24
25
26
27
28 public class BrlReplaceDoubleFormFeedsStep extends DefaultStep {
29
30 private static final Logger logger = LoggerFactory.getLogger(BrlReplaceDoubleFormFeedsStep.class);
31
32 private static final QName _brl_uri = new QName("brl-uri");
33
34 private BrlReplaceDoubleFormFeedsStep(XProcRuntime runtime, XAtomicStep step) {
35 super(runtime, step);
36 }
37
38 @Override
39 public void reset() {
40 }
41
42 @Override
43 public void run() throws SaxonApiException {
44 super.run();
45
46 try {
47 String brlUri = getOption(_brl_uri, "");
48 if (StringUtils.isNotBlank(brlUri)) {
49
50 try {
51
52 Path path = new File(new URI(brlUri)).toPath();
53
54
55 byte[] inBytes = Files.readAllBytes(path);
56 byte[] outBytes = new byte[inBytes.length];
57
58 int inIndex = 0;
59 int outIndex = 0;
60 while (inIndex < inBytes.length) {
61 int doubleFormFeedLength = findDoubleFormFeed(inBytes, inIndex);
62 if (doubleFormFeedLength > 0) {
63 outBytes[outIndex] = 0xC;
64 inIndex += doubleFormFeedLength;
65 outIndex ++;
66 } else {
67 outBytes[outIndex] = inBytes[inIndex];
68 inIndex ++;
69 outIndex ++;
70 }
71 }
72
73 Files.write(path, Arrays.copyOfRange(outBytes, 0, outIndex));
74
75 } catch (URISyntaxException|IOException e) {
76 logger.error(String.format("Failed to replace double form feeds in file %s due to %s", brlUri, e.getMessage()));
77 throw e;
78 }
79 }
80 } catch (Exception e) {
81 logger.error("dedicon:brl-replace-double-form-feeds failed", e);
82 throw new XProcException(step.getNode(), e);
83 }
84 }
85
86
87 private int findDoubleFormFeed(byte[] bytes, int index) {
88 int length = 0;
89 if (index + length < bytes.length && bytes[index + length] == 0xC) {
90 length ++;
91 while (index + length < bytes.length + 1 && bytes[index + length] == 0xD && bytes[index + length + 1] == 0xA) {
92 length += 2;
93 }
94 if (index + length < bytes.length && bytes[index + length] == 0xC) {
95 length ++;
96 return length;
97 }
98 }
99 return -1;
100 }
101
102 @Component(
103 name = "dedicon:brl-replace-double-form-feeds",
104 service = {XProcStepProvider.class},
105 property = {"type:String={http://www.dedicon.nl}brl-replace-double-form-feeds"}
106 )
107 public static class Provider implements XProcStepProvider {
108
109 @Override
110 public XProcStep newStep(XProcRuntime runtime, XAtomicStep step) {
111 return new BrlReplaceDoubleFormFeedsStep(runtime, step);
112 }
113 }
114 }