1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.connector.basic;
20
21 import java.io.BufferedInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.nio.Buffer;
25 import java.nio.ByteBuffer;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35
36 import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm;
37 import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
38
39 import static java.util.Objects.requireNonNull;
40
41
42
43
44 final class ChecksumCalculator {
45
46 static class Checksum {
47 final ChecksumAlgorithmFactory checksumAlgorithmFactory;
48
49 ChecksumAlgorithm algorithm;
50
51 Exception error;
52
53 Checksum(ChecksumAlgorithmFactory checksumAlgorithmFactory) {
54 this.checksumAlgorithmFactory = requireNonNull(checksumAlgorithmFactory);
55 this.algorithm = checksumAlgorithmFactory.getAlgorithm();
56 }
57
58 public void reset() {
59 this.algorithm = checksumAlgorithmFactory.getAlgorithm();
60 this.error = null;
61 }
62
63 public void update(ByteBuffer buffer) {
64 this.algorithm.update(buffer);
65 }
66
67 public void error(Exception error) {
68 this.error = error;
69 }
70
71 public Object get() {
72 if (error != null) {
73 return error;
74 }
75 return algorithm.checksum();
76 }
77 }
78
79 private final List<Checksum> checksums;
80
81 private final Path targetFile;
82
83 public static ChecksumCalculator newInstance(
84 Path targetFile, Collection<ChecksumAlgorithmFactory> checksumAlgorithmFactories) {
85 if (checksumAlgorithmFactories == null || checksumAlgorithmFactories.isEmpty()) {
86 return null;
87 }
88 return new ChecksumCalculator(targetFile, checksumAlgorithmFactories);
89 }
90
91 private ChecksumCalculator(Path targetFile, Collection<ChecksumAlgorithmFactory> checksumAlgorithmFactories) {
92 this.checksums = new ArrayList<>();
93 Set<String> algos = new HashSet<>();
94 for (ChecksumAlgorithmFactory checksumAlgorithmFactory : checksumAlgorithmFactories) {
95 if (algos.add(checksumAlgorithmFactory.getName())) {
96 this.checksums.add(new Checksum(checksumAlgorithmFactory));
97 }
98 }
99 this.targetFile = targetFile;
100 }
101
102 public void init(long dataOffset) {
103 for (Checksum checksum : checksums) {
104 checksum.reset();
105 }
106 if (dataOffset <= 0L) {
107 return;
108 }
109
110 try (InputStream in = new BufferedInputStream(Files.newInputStream(targetFile))) {
111 long total = 0;
112 final byte[] buffer = new byte[1024 * 32];
113 while (total < dataOffset) {
114 int read = in.read(buffer);
115 if (read < 0) {
116 throw new IOException(targetFile + " contains only " + total
117 + " bytes, cannot resume download from offset " + dataOffset);
118 }
119 total += read;
120 if (total > dataOffset) {
121 read -= total - dataOffset;
122 }
123 update(ByteBuffer.wrap(buffer, 0, read));
124 }
125 } catch (IOException e) {
126 for (Checksum checksum : checksums) {
127 checksum.error(e);
128 }
129 }
130 }
131
132 public void update(ByteBuffer data) {
133 for (Checksum checksum : checksums) {
134 ((Buffer) data).mark();
135 checksum.update(data);
136 ((Buffer) data).reset();
137 }
138 }
139
140 public Map<String, Object> get() {
141 Map<String, Object> results = new HashMap<>();
142 for (Checksum checksum : checksums) {
143 results.put(checksum.checksumAlgorithmFactory.getName(), checksum.get());
144 }
145 return results;
146 }
147 }