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