1 package org.eclipse.aether.connector.basic;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.nio.ByteBuffer;
27 import java.security.MessageDigest;
28 import java.security.NoSuchAlgorithmException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36
37 import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
38 import org.eclipse.aether.util.ChecksumUtils;
39
40
41
42
43 final class ChecksumCalculator
44 {
45
46 static class Checksum
47 {
48 final String algorithm;
49
50 final MessageDigest digest;
51
52 Exception error;
53
54 Checksum( String algorithm )
55 {
56 this.algorithm = algorithm;
57 MessageDigest digest = null;
58 try
59 {
60 digest = MessageDigest.getInstance( algorithm );
61 }
62 catch ( NoSuchAlgorithmException e )
63 {
64 error = e;
65 }
66 this.digest = digest;
67 }
68
69 public void update( ByteBuffer buffer )
70 {
71 if ( digest != null )
72 {
73 digest.update( buffer );
74 }
75 }
76
77 public void reset()
78 {
79 if ( digest != null )
80 {
81 digest.reset();
82 error = null;
83 }
84 }
85
86 public void error( Exception error )
87 {
88 if ( digest != null )
89 {
90 this.error = error;
91 }
92 }
93
94 public Object get()
95 {
96 if ( error != null )
97 {
98 return error;
99 }
100 return ChecksumUtils.toHexString( digest.digest() );
101 }
102
103 }
104
105 private final List<Checksum> checksums;
106
107 private final File targetFile;
108
109 public static ChecksumCalculator newInstance( File targetFile, Collection<RepositoryLayout.Checksum> checksums )
110 {
111 if ( checksums == null || checksums.isEmpty() )
112 {
113 return null;
114 }
115 return new ChecksumCalculator( targetFile, checksums );
116 }
117
118 private ChecksumCalculator( File targetFile, Collection<RepositoryLayout.Checksum> checksums )
119 {
120 this.checksums = new ArrayList<>();
121 Set<String> algos = new HashSet<>();
122 for ( RepositoryLayout.Checksum checksum : checksums )
123 {
124 String algo = checksum.getAlgorithm();
125 if ( algos.add( algo ) )
126 {
127 this.checksums.add( new Checksum( algo ) );
128 }
129 }
130 this.targetFile = targetFile;
131 }
132
133 public void init( long dataOffset )
134 {
135 for ( Checksum checksum : checksums )
136 {
137 checksum.reset();
138 }
139 if ( dataOffset <= 0L )
140 {
141 return;
142 }
143
144 InputStream in = null;
145 try
146 {
147 in = new FileInputStream( targetFile );
148 long total = 0;
149 ByteBuffer buffer = ByteBuffer.allocate( 1024 * 32 );
150 for ( byte[] array = buffer.array(); total < dataOffset; )
151 {
152 int read = in.read( array );
153 if ( read < 0 )
154 {
155 if ( total < dataOffset )
156 {
157 throw new IOException( targetFile + " contains only " + total
158 + " bytes, cannot resume download from offset " + dataOffset );
159 }
160 break;
161 }
162 total += read;
163 if ( total > dataOffset )
164 {
165 read -= total - dataOffset;
166 }
167 buffer.rewind();
168 buffer.limit( read );
169 update( buffer );
170 }
171
172 in.close();
173 in = null;
174 }
175 catch ( IOException e )
176 {
177 for ( Checksum checksum : checksums )
178 {
179 checksum.error( e );
180 }
181 }
182 finally
183 {
184 try
185 {
186 if ( in != null )
187 {
188 in.close();
189 }
190 }
191 catch ( IOException e )
192 {
193
194 }
195 }
196 }
197
198 public void update( ByteBuffer data )
199 {
200 for ( Checksum checksum : checksums )
201 {
202 data.mark();
203 checksum.update( data );
204 data.reset();
205 }
206 }
207
208 public Map<String, Object> get()
209 {
210 Map<String, Object> results = new HashMap<>();
211 for ( Checksum checksum : checksums )
212 {
213 results.put( checksum.algorithm, checksum.get() );
214 }
215 return results;
216 }
217
218 }