1 |
|
package org.stackoverflowusers.file; |
2 |
|
|
3 |
|
import java.io.ByteArrayOutputStream; |
4 |
|
import java.io.File; |
5 |
|
import java.io.FileInputStream; |
6 |
|
import java.io.IOException; |
7 |
|
import java.io.InputStream; |
8 |
|
import java.text.ParseException; |
9 |
|
import java.util.Locale; |
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
|
17 |
|
|
18 |
|
|
19 |
|
|
20 |
|
|
21 |
|
|
22 |
|
|
23 |
|
|
24 |
|
|
25 |
|
|
26 |
|
|
27 |
|
|
28 |
|
|
29 |
|
|
|
|
| 0% |
Uncovered Elements: 99 (99) |
Complexity: 22 |
Complexity Density: 0.31 |
|
30 |
|
public class WindowsShortcut |
31 |
|
{ |
32 |
|
private boolean isDirectory; |
33 |
|
|
34 |
|
private boolean isLocal; |
35 |
|
|
36 |
|
private String real_file; |
37 |
|
|
38 |
|
|
39 |
|
|
40 |
|
|
41 |
|
|
42 |
|
|
43 |
|
|
44 |
|
@param |
45 |
|
|
46 |
|
@return |
47 |
|
@throws |
48 |
|
|
49 |
|
|
|
|
| 0% |
Uncovered Elements: 7 (7) |
Complexity: 1 |
Complexity Density: 0.14 |
|
50 |
0 |
public static boolean isPotentialValidLink(File file) throws IOException... |
51 |
|
{ |
52 |
0 |
final int minimum_length = 0x64; |
53 |
0 |
InputStream fis = new FileInputStream(file); |
54 |
0 |
boolean isPotentiallyValid = false; |
55 |
0 |
try |
56 |
|
{ |
57 |
0 |
isPotentiallyValid = file.isFile() |
58 |
|
&& file.getName().toLowerCase(Locale.ROOT).endsWith(".lnk") |
59 |
|
&& fis.available() >= minimum_length |
60 |
|
&& isMagicPresent(getBytes(fis, 32)); |
61 |
|
} finally |
62 |
|
{ |
63 |
0 |
fis.close(); |
64 |
|
} |
65 |
0 |
return isPotentiallyValid; |
66 |
|
} |
67 |
|
|
|
|
| 0% |
Uncovered Elements: 4 (4) |
Complexity: 1 |
Complexity Density: 0.25 |
|
68 |
0 |
public WindowsShortcut(File file) throws IOException, ParseException... |
69 |
|
{ |
70 |
0 |
InputStream in = new FileInputStream(file); |
71 |
0 |
try |
72 |
|
{ |
73 |
0 |
parseLink(getBytes(in)); |
74 |
|
} finally |
75 |
|
{ |
76 |
0 |
in.close(); |
77 |
|
} |
78 |
|
} |
79 |
|
|
80 |
|
|
81 |
|
@return |
82 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
83 |
0 |
public String getRealFilename()... |
84 |
|
{ |
85 |
0 |
return real_file; |
86 |
|
} |
87 |
|
|
88 |
|
|
89 |
|
|
90 |
|
|
91 |
|
@return |
92 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
93 |
0 |
public boolean isLocal()... |
94 |
|
{ |
95 |
0 |
return isLocal; |
96 |
|
} |
97 |
|
|
98 |
|
|
99 |
|
|
100 |
|
|
101 |
|
@return |
102 |
|
|
103 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
104 |
0 |
public boolean isDirectory()... |
105 |
|
{ |
106 |
0 |
return isDirectory; |
107 |
|
} |
108 |
|
|
109 |
|
|
110 |
|
|
111 |
|
|
112 |
|
@param |
113 |
|
|
114 |
|
@return |
115 |
|
@throws |
116 |
|
|
117 |
|
|
118 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
119 |
0 |
private static byte[] getBytes(InputStream in) throws IOException... |
120 |
|
{ |
121 |
0 |
return getBytes(in, null); |
122 |
|
} |
123 |
|
|
124 |
|
|
125 |
|
|
126 |
|
|
127 |
|
@param |
128 |
|
|
129 |
|
@param |
130 |
|
|
131 |
|
@return |
132 |
|
@throws |
133 |
|
|
134 |
|
|
135 |
|
|
|
|
| 0% |
Uncovered Elements: 17 (17) |
Complexity: 5 |
Complexity Density: 0.45 |
|
136 |
0 |
private static byte[] getBytes(InputStream in, Integer max)... |
137 |
|
throws IOException |
138 |
|
{ |
139 |
|
|
140 |
0 |
ByteArrayOutputStream bout = new ByteArrayOutputStream(); |
141 |
0 |
byte[] buff = new byte[256]; |
142 |
0 |
while (max == null || max > 0) |
143 |
|
{ |
144 |
0 |
int n = in.read(buff); |
145 |
0 |
if (n == -1) |
146 |
|
{ |
147 |
0 |
break; |
148 |
|
} |
149 |
0 |
bout.write(buff, 0, n); |
150 |
0 |
if (max != null) |
151 |
0 |
max -= n; |
152 |
|
} |
153 |
0 |
in.close(); |
154 |
0 |
return bout.toByteArray(); |
155 |
|
} |
156 |
|
|
|
|
| 0% |
Uncovered Elements: 3 (3) |
Complexity: 1 |
Complexity Density: 0.33 |
|
157 |
0 |
private static boolean isMagicPresent(byte[] link)... |
158 |
|
{ |
159 |
0 |
final int magic = 0x0000004C; |
160 |
0 |
final int magic_offset = 0x00; |
161 |
0 |
return link.length >= 32 && bytesToDword(link, magic_offset) == magic; |
162 |
|
} |
163 |
|
|
164 |
|
|
165 |
|
|
166 |
|
|
167 |
|
@param |
168 |
|
|
169 |
|
|
|
|
| 0% |
Uncovered Elements: 42 (42) |
Complexity: 6 |
Complexity Density: 0.18 |
|
170 |
0 |
private void parseLink(byte[] link) throws ParseException... |
171 |
|
{ |
172 |
0 |
try |
173 |
|
{ |
174 |
0 |
if (!isMagicPresent(link)) |
175 |
0 |
throw new ParseException("Invalid shortcut; magic is missing", 0); |
176 |
|
|
177 |
|
|
178 |
0 |
byte flags = link[0x14]; |
179 |
|
|
180 |
|
|
181 |
0 |
final int file_atts_offset = 0x18; |
182 |
0 |
byte file_atts = link[file_atts_offset]; |
183 |
0 |
byte is_dir_mask = (byte) 0x10; |
184 |
0 |
if ((file_atts & is_dir_mask) > 0) |
185 |
|
{ |
186 |
0 |
isDirectory = true; |
187 |
|
} |
188 |
|
else |
189 |
|
{ |
190 |
0 |
isDirectory = false; |
191 |
|
} |
192 |
|
|
193 |
|
|
194 |
0 |
final int shell_offset = 0x4c; |
195 |
0 |
final byte has_shell_mask = (byte) 0x01; |
196 |
0 |
int shell_len = 0; |
197 |
0 |
if ((flags & has_shell_mask) > 0) |
198 |
|
{ |
199 |
|
|
200 |
0 |
shell_len = bytesToWord(link, shell_offset) + 2; |
201 |
|
} |
202 |
|
|
203 |
|
|
204 |
0 |
int file_start = 0x4c + shell_len; |
205 |
|
|
206 |
0 |
final int file_location_info_flag_offset_offset = 0x08; |
207 |
0 |
int file_location_info_flag = link[file_start |
208 |
|
+ file_location_info_flag_offset_offset]; |
209 |
0 |
isLocal = (file_location_info_flag & 2) == 0; |
210 |
|
|
211 |
|
|
212 |
0 |
final int basename_offset_offset = 0x10; |
213 |
0 |
final int networkVolumeTable_offset_offset = 0x14; |
214 |
0 |
final int finalname_offset_offset = 0x18; |
215 |
0 |
int finalname_offset = link[file_start + finalname_offset_offset] |
216 |
|
+ file_start; |
217 |
0 |
String finalname = getNullDelimitedString(link, finalname_offset); |
218 |
0 |
if (isLocal) |
219 |
|
{ |
220 |
0 |
int basename_offset = link[file_start + basename_offset_offset] |
221 |
|
+ file_start; |
222 |
0 |
String basename = getNullDelimitedString(link, basename_offset); |
223 |
0 |
real_file = basename + finalname; |
224 |
|
} |
225 |
|
else |
226 |
|
{ |
227 |
0 |
int networkVolumeTable_offset = link[file_start |
228 |
|
+ networkVolumeTable_offset_offset] + file_start; |
229 |
0 |
int shareName_offset_offset = 0x08; |
230 |
0 |
int shareName_offset = link[networkVolumeTable_offset |
231 |
|
+ shareName_offset_offset] + networkVolumeTable_offset; |
232 |
0 |
String shareName = getNullDelimitedString(link, shareName_offset); |
233 |
0 |
real_file = shareName + "\\" + finalname; |
234 |
|
} |
235 |
|
} catch (ArrayIndexOutOfBoundsException e) |
236 |
|
{ |
237 |
0 |
throw new ParseException( |
238 |
|
"Could not be parsed, probably not a valid WindowsShortcut", |
239 |
|
0); |
240 |
|
} |
241 |
|
} |
242 |
|
|
|
|
| 0% |
Uncovered Elements: 8 (8) |
Complexity: 2 |
Complexity Density: 0.33 |
|
243 |
0 |
private static String getNullDelimitedString(byte[] bytes, int off)... |
244 |
|
{ |
245 |
0 |
int len = 0; |
246 |
|
|
247 |
0 |
while (true) |
248 |
|
{ |
249 |
0 |
if (bytes[off + len] == 0) |
250 |
|
{ |
251 |
0 |
break; |
252 |
|
} |
253 |
0 |
len++; |
254 |
|
} |
255 |
0 |
return new String(bytes, off, len); |
256 |
|
} |
257 |
|
|
258 |
|
|
259 |
|
|
260 |
|
|
261 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
262 |
0 |
private static int bytesToWord(byte[] bytes, int off)... |
263 |
|
{ |
264 |
0 |
return ((bytes[off + 1] & 0xff) << 8) | (bytes[off] & 0xff); |
265 |
|
} |
266 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
267 |
0 |
private static int bytesToDword(byte[] bytes, int off)... |
268 |
|
{ |
269 |
0 |
return (bytesToWord(bytes, off + 2) << 16) | bytesToWord(bytes, off); |
270 |
|
} |
271 |
|
|
272 |
|
} |