1 | /**
|
---|
2 | *#########################################################################
|
---|
3 | *
|
---|
4 | * A component of the Gatherer application, part of the Greenstone digital
|
---|
5 | * library suite from the New Zealand Digital Library Project at the
|
---|
6 | * University of Waikato, New Zealand.
|
---|
7 | *
|
---|
8 | * <BR><BR>
|
---|
9 | *
|
---|
10 | * Author: John Thompson, Greenstone Digital Library, University of Waikato
|
---|
11 | *
|
---|
12 | * <BR><BR>
|
---|
13 | *
|
---|
14 | * Copyright (C) 1999 New Zealand Digital Library Project
|
---|
15 | *
|
---|
16 | * <BR><BR>
|
---|
17 | *
|
---|
18 | * This program is free software; you can redistribute it and/or modify
|
---|
19 | * it under the terms of the GNU General Public License as published by
|
---|
20 | * the Free Software Foundation; either version 2 of the License, or
|
---|
21 | * (at your option) any later version.
|
---|
22 | *
|
---|
23 | * <BR><BR>
|
---|
24 | *
|
---|
25 | * This program is distributed in the hope that it will be useful,
|
---|
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
28 | * GNU General Public License for more details.
|
---|
29 | *
|
---|
30 | * <BR><BR>
|
---|
31 | *
|
---|
32 | * You should have received a copy of the GNU General Public License
|
---|
33 | * along with this program; if not, write to the Free Software
|
---|
34 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
35 | *########################################################################
|
---|
36 | */
|
---|
37 |
|
---|
38 |
|
---|
39 |
|
---|
40 |
|
---|
41 |
|
---|
42 |
|
---|
43 | package org.greenstone.gatherer.util;
|
---|
44 | /**
|
---|
45 | * Title: The Gatherer
|
---|
46 | * Description: The Gatherer: a tool for gathering and enriching digital collections.
|
---|
47 | * Copyright: Copyright (c) 2001
|
---|
48 | * Company: The University of Waikato
|
---|
49 | * Written: 18/11/01
|
---|
50 | * Revised: 24/07/02
|
---|
51 | * @author John Thompson, Greenstone Digital Libraries
|
---|
52 | * @version 2.1
|
---|
53 | */
|
---|
54 | import java.lang.reflect.Method;
|
---|
55 | /** This class provides access to the Windows registry via the preferences modules of JDK1.4. But wouldn't you know it, it doesn't always read the windows key files correctly as they appear to have changed how they store keys between win98, win2000 and winNT. To combat this, this class will eventually be swallowed by the LauchProgramManager, and used only to attempt to determine the default launching commands. */
|
---|
56 | public class WinRegistry {
|
---|
57 | /** Windows security mask */
|
---|
58 | private final static int KEY_QUERY_VALUE = 1;
|
---|
59 | /** A constant used to interpret the return of a native function as successful. */
|
---|
60 | private final static int NATIVE_HANDLE = 0;
|
---|
61 | /** A constant used to interpret the return of a native function as an error. */
|
---|
62 | private final static int ERROR_CODE = 1;
|
---|
63 | /** Windows error codes. */
|
---|
64 | private final static int ERROR_SUCCESS = 0;
|
---|
65 | /** HKEY_LOCAL_MACHINE address. */
|
---|
66 | private final static int HKEY_LOCAL_MACHINE = 0x80000002;
|
---|
67 | /** Called to build a command string that will launch the given file in its associated program according to the windows registry.
|
---|
68 | * @param filename The name of a file, including the required extension, as a <strong>String</strong>.
|
---|
69 | * @return Another <strong>String</strong> containing a command line which, when run in a command shell, will launch an external application to view this file.
|
---|
70 | */
|
---|
71 | public static String openCommand(String filename) {
|
---|
72 | if(filename.indexOf(".") != -1) {
|
---|
73 | String extension = filename.substring(filename.indexOf("."));
|
---|
74 | try {
|
---|
75 | // First find the name of the file type that is associated with this extension.
|
---|
76 | String file_type = getValue("Software\\CLASSES\\" + extension);
|
---|
77 | // Then if we got a type, get the open command from its shell reference.
|
---|
78 | ///ystem.err.println("Searching for file-type = " + file_type);
|
---|
79 | if(file_type != null) {
|
---|
80 | String raw = getValue("Software\\CLASSES\\" + file_type + "\\shell\\open\\command");
|
---|
81 | //Replace "%1" with "filename"
|
---|
82 | if(raw.indexOf("%1") != -1) {
|
---|
83 | String prefix = raw.substring(0, raw.indexOf("%1"));
|
---|
84 | if(!prefix.endsWith("\"")) {
|
---|
85 | prefix = prefix + "\"";
|
---|
86 | }
|
---|
87 | String suffix = raw.substring(raw.indexOf("%1") + 2);
|
---|
88 | if(!suffix.endsWith("\"")) {
|
---|
89 | suffix = suffix + "\"";
|
---|
90 | }
|
---|
91 | return prefix + filename + suffix;
|
---|
92 | }
|
---|
93 | // Arg. There is a windows flag called /dde, which if it exists in a command tells it to use the filename (hence the meaningful name dde eh?)
|
---|
94 | else if(raw.indexOf("/dde") != -1) {
|
---|
95 | String prefix = raw.substring(0, raw.indexOf("/dde"));
|
---|
96 | if(!prefix.endsWith("\"")) {
|
---|
97 | prefix = prefix + "\"";
|
---|
98 | }
|
---|
99 | String suffix = raw.substring(raw.indexOf("/dde") + 4);
|
---|
100 | if(!suffix.endsWith("\"")) {
|
---|
101 | suffix = suffix + "\"";
|
---|
102 | }
|
---|
103 | return prefix + filename + suffix;
|
---|
104 | }
|
---|
105 | // No file parameter. Append the file to the command and hope for the best.
|
---|
106 | return raw + " \"" + filename + "\"";
|
---|
107 | }
|
---|
108 | }
|
---|
109 | catch (Exception error) {
|
---|
110 | ///ystem.err.println("No such value.");
|
---|
111 | //error.printStackTrace();
|
---|
112 | }
|
---|
113 | }
|
---|
114 | return null;
|
---|
115 | }
|
---|
116 | /** Attempts to retrieve the value at the location given from the registry using Reflection.
|
---|
117 | * @param path The path to the desired key as a <strong>String</strong>.
|
---|
118 | * @return The value found at the indicated key as a <strong>String</strong>.
|
---|
119 | */
|
---|
120 | private static String getValue(String path)
|
---|
121 | throws ClassNotFoundException, Exception, NoSuchMethodException {
|
---|
122 | ///ystem.err.println("Get value " + path);
|
---|
123 | byte[] WINDOWS_ROOT_PATH = stringToByteArray(path);
|
---|
124 | Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
|
---|
125 | int[] result = openKey(HKEY_LOCAL_MACHINE, WINDOWS_ROOT_PATH, KEY_QUERY_VALUE);
|
---|
126 | if (result[ERROR_CODE] != ERROR_SUCCESS) {
|
---|
127 | throw new Exception("Path not found!");
|
---|
128 | }
|
---|
129 | int native_handle = result[NATIVE_HANDLE];
|
---|
130 | Method m = theClass.getDeclaredMethod("WindowsRegQueryValueEx", new Class[]{int.class, byte[].class});
|
---|
131 | m.setAccessible(true);
|
---|
132 | byte[] windows_name = toWindowsName("");
|
---|
133 | Object value = m.invoke(null, new Object[]{new Integer(native_handle), windows_name});
|
---|
134 | WindowsRegCloseKey(native_handle);
|
---|
135 | if (value == null) {
|
---|
136 | throw new Exception("Path found. Key not found.");
|
---|
137 | }
|
---|
138 | byte[] origBuffer = (byte[]) value;
|
---|
139 | byte[] destBuffer = new byte[origBuffer.length - 1];
|
---|
140 | System.arraycopy(origBuffer, 0, destBuffer, 0, origBuffer.length - 1);
|
---|
141 | return new String(destBuffer);
|
---|
142 | }
|
---|
143 | /** Closes the reference (and hence the instantiated objects) to a certain entry within the registry. Do this or suffer massive memory leaks.
|
---|
144 | * @param nativeHandle A reference to the piece of memory containing an inspected windows key-value pair.
|
---|
145 | * @return The status code returned from closing the key, as an <i>int</i>.
|
---|
146 | */
|
---|
147 | public static int WindowsRegCloseKey(int nativeHandle)
|
---|
148 | throws Exception {
|
---|
149 | Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
|
---|
150 | Method m = theClass.getDeclaredMethod("WindowsRegCloseKey", new Class[]{int.class});
|
---|
151 | m.setAccessible(true);
|
---|
152 | Object ret = m.invoke(null, new Object[]{new Integer(nativeHandle)});
|
---|
153 | return ((Integer) ret).intValue();
|
---|
154 | }
|
---|
155 | /** Attempts to open a certain key-value pair from the windows registry, from within a certain region (or HKEY).
|
---|
156 | * @param hkey An <i>int</i> which is the offset for a certain group within the registry.
|
---|
157 | * @param windowsAbsolutePath A <i>byte[]</i> containing the path to the desired key, relative to the given HKEY.
|
---|
158 | * @param securityMask A mask needed to read values from the registry, as an <i>int</i>.
|
---|
159 | * @return An <i>int[]</i> pair, the first of which is the reference to the indicated key if no error occured, and the second of which reports the end error state of the registry open attempt.
|
---|
160 | */
|
---|
161 | public static int[] openKey(int hkey, byte[] windowsAbsolutePath, int securityMask)
|
---|
162 | throws Exception {
|
---|
163 | Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
|
---|
164 | Method m = theClass.getDeclaredMethod("WindowsRegOpenKey", new Class[]{int.class, byte[].class, int.class});
|
---|
165 | m.setAccessible(true);
|
---|
166 | Object ret = m.invoke(null, new Object[]{new Integer(hkey), windowsAbsolutePath, new Integer(securityMask)});
|
---|
167 | return (int[]) ret;
|
---|
168 | }
|
---|
169 | /** Converts a string to a byte array. Duh!
|
---|
170 | * @param str The <strong>String</strong> to be converted.
|
---|
171 | * @return A <i>byte[]</i> containing orderer characters from the String.
|
---|
172 | */
|
---|
173 | private static byte[] stringToByteArray(String str) {
|
---|
174 | byte[] result = new byte[str.length() + 1];
|
---|
175 | for (int i = 0; i < str.length(); i++) {
|
---|
176 | result[i] = (byte) str.charAt(i);
|
---|
177 | }
|
---|
178 | result[str.length()] = 0;
|
---|
179 | return result;
|
---|
180 | }
|
---|
181 |
|
---|
182 | private static String toJavaValueString(byte[] windowsNameArray) {
|
---|
183 | // Use modified native2ascii algorithm
|
---|
184 | String windowsName = byteArrayToString(windowsNameArray);
|
---|
185 | StringBuffer javaName = new StringBuffer();
|
---|
186 | char ch;
|
---|
187 | for (int i = 0; i < windowsName.length(); i++) {
|
---|
188 | if ((ch = windowsName.charAt(i)) == '/') {
|
---|
189 | char next = ' ';
|
---|
190 |
|
---|
191 | if (windowsName.length() > i + 1 &&
|
---|
192 | (next = windowsName.charAt(i + 1)) == 'u') {
|
---|
193 | if (windowsName.length() < i + 6) {
|
---|
194 | break;
|
---|
195 | } else {
|
---|
196 | ch = (char) Integer.parseInt
|
---|
197 | (windowsName.substring(i + 2, i + 6), 16);
|
---|
198 | i += 5;
|
---|
199 | }
|
---|
200 | } else
|
---|
201 | if ((windowsName.length() > i + 1) &&
|
---|
202 | ((windowsName.charAt(i + 1)) >= 'A') && (next <= 'Z')) {
|
---|
203 | ch = next;
|
---|
204 | i++;
|
---|
205 | } else if ((windowsName.length() > i + 1) &&
|
---|
206 | (next == '/')) {
|
---|
207 | ch = '\\';
|
---|
208 | i++;
|
---|
209 | }
|
---|
210 | } else if (ch == '\\') {
|
---|
211 | ch = '/';
|
---|
212 | }
|
---|
213 | javaName.append(ch);
|
---|
214 | }
|
---|
215 | return javaName.toString();
|
---|
216 | }
|
---|
217 | /** */
|
---|
218 | private static String byteArrayToString(byte[] array) {
|
---|
219 | StringBuffer result = new StringBuffer();
|
---|
220 | for (int i = 0; i < array.length - 1; i++) {
|
---|
221 | result.append((char) array[i]);
|
---|
222 | }
|
---|
223 | return result.toString();
|
---|
224 | }
|
---|
225 | /** Magics the name of a certain path component from a Java String to the unique string windows requires.
|
---|
226 | * @param javaName The name of a path component as a <strong>String</strong>.
|
---|
227 | * @return A <i>byte[]</i> containing the translated string.
|
---|
228 | */
|
---|
229 | private static byte[] toWindowsName(String javaName) {
|
---|
230 | StringBuffer windowsName = new StringBuffer();
|
---|
231 | for (int i = 0; i < javaName.length(); i++) {
|
---|
232 | char ch = javaName.charAt(i);
|
---|
233 | if ((ch < 0x0020) || (ch > 0x007f)) {
|
---|
234 | throw new RuntimeException("Unable to convert to Windows name");
|
---|
235 | }
|
---|
236 | if (ch == '\\') {
|
---|
237 | windowsName.append("//");
|
---|
238 | } else if (ch == '/') {
|
---|
239 | windowsName.append('\\');
|
---|
240 | } else if ((ch >= 'A') && (ch <= 'Z')) {
|
---|
241 | windowsName.append("/" + ch);
|
---|
242 | } else {
|
---|
243 | windowsName.append(ch);
|
---|
244 | }
|
---|
245 | }
|
---|
246 | return stringToByteArray(windowsName.toString());
|
---|
247 | }
|
---|
248 | }
|
---|