/*
* org.openmicroscopy.shoola.env.data.model.appdata.WindowsApplicationDataExtractor
*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2012 University of Dundee & Open Microscopy Environment.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.env.data.model.appdata;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;
import javax.swing.Icon;
import javax.swing.filechooser.FileSystemView;
import org.apache.commons.io.FilenameUtils;
import org.openmicroscopy.shoola.env.data.model.ApplicationData;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Version;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
/**
* Provides the Windows implementation to extract application properties using
* the {@link LANGANDCODEPAGE} class with the <a
* href="https://github.com/twall/jna">JNA</a> library.
*
* @author Scott Littlewood, <a
* href="mailto:sylittlewood@dundee.ac.uk">sylittlewood@dundee.ac.uk</a>
* @since Beta4.4
*/
public class WindowsApplicationDataExtractor implements
ApplicationDataExtractor {
/**
* Windows specific keys for accessing application properties @see
* http://msdn
* .microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx
*/
private static final String APPLICATION_PROPERTY_KEY_COMMENTS = "Comments";
private static final String APPLICATION_PROPERTY_KEY_COMPANY_NAME = "CompanyName";
private static final String APPLICATION_PROPERTY_KEY_FILE_DESCRIPTION = "FileDescription";
private static final String APPLICATION_PROPERTY_KEY_FILE_VERSION = "FileVersion";
private static final String APPLICATION_PROPERTY_KEY_INTERNAL_NAME = "InternalName";
private static final String APPLICATION_PROPERTY_KEY_LEGAL_COPYRIGHT = "LegalCopyright";
private static final String APPLICATION_PROPERTY_KEY_LEGAL_TRADEMARK = "LegalTrademark";
private static final String APPLICATION_PROPERTY_KEY_ORIGINAL_FILE_NAME = "OriginalFileName";
private static final String APPLICATION_PROPERTY_KEY_PRODUCT_NAME = "ProductName";
private static final String APPLICATION_PROPERTY_KEY_PRODUCT_VERSION = "ProductVersion";
private static final String APPLICATION_PROPERTY_KEY_PRIVATE_BUILD = "PrivateBuild";
private static final String APPLICATION_PROPERTY_KEY_SPECIAL_BUILD = "SpecialBuild";
private static final String WINDOWS_QUERYPATH_TRANSLATION = "\\VarFileInfo\\Translation";
/** The default application location on <code>Windows</code> platform. */
private static final String LOCATION_WINDOWS = "C:\\Program Files\\";
/**
* Gets the system icon for the application
*
* @param file
* the file location of the application to retrieve the icon for
* @return the icon associated with this application
*/
private Icon getSystemIconFor(File file) {
Icon icon = FileSystemView.getFileSystemView().getSystemIcon(file);
return icon;
}
/**
* Allocates a portion of memory for use by JNA
*
* @param size
* the size of the memory to allocate
* @return a pointer to the memory location
*/
private Pointer allocateBuffer(int size) {
byte[] bufferarray = new byte[size];
Pointer buffer = new Memory(bufferarray.length);
return buffer;
}
/**
* Returns the language code page string for the application on the current
* windows platform
*
* @param applicationPath
* @param fileVersionInfoSize
* @return See above.
* @throws Exception
*/
private String getTranslation(String applicationPath,
int fileVersionInfoSize) throws Exception {
Pointer lpData = allocateBuffer(fileVersionInfoSize);
boolean fileVersionInfoSuccess = Version.INSTANCE.GetFileVersionInfo(
applicationPath, 0, fileVersionInfoSize, lpData);
if (!fileVersionInfoSuccess)
throw new Exception("Unable to load application information");
PointerByReference lplpBuffer = new PointerByReference();
IntByReference puLen = new IntByReference();
boolean verQueryValSuccess = ExecuteQuery(lpData,
WINDOWS_QUERYPATH_TRANSLATION, lplpBuffer, puLen);
if (!verQueryValSuccess)
throw new Exception("Unable to load application information");
LANGANDCODEPAGE lplpBufStructure = new LANGANDCODEPAGE(
lplpBuffer.getValue());
lplpBufStructure.read();
StringBuilder hexBuilder = new StringBuilder();
String languageAsHex = String
.format("%04x", lplpBufStructure.wLanguage);
String codePageAsHex = String
.format("%04x", lplpBufStructure.wCodePage);
hexBuilder.append(languageAsHex);
hexBuilder.append(codePageAsHex);
return hexBuilder.toString();
}
/**
* Performs the windows specific query related to application properties
*
* @param lpData
* @param lpSubBlock
* @param lplpBuffer
* @param puLen
* @return
*/
private boolean ExecuteQuery(Pointer lpData, String lpSubBlock,
PointerByReference lplpBuffer, IntByReference puLen) {
return Version.INSTANCE.VerQueryValue(lpData, lpSubBlock, lplpBuffer,
puLen);
}
/**
* Extracts the information item with key @propertyKey from the application
* properties found in @applicationPath
*
* @param applicationPath
* @param fileVersionInfoSize
* @param translation
* @param propertyKey
* @return
* @throws Exception
*/
private String getFilePropertyValue(String applicationPath,
int fileVersionInfoSize, String translation, String propertyKey)
throws Exception {
Pointer lpData = allocateBuffer(fileVersionInfoSize);
boolean fileInfoStatusSuccess = Version.INSTANCE.GetFileVersionInfo(
applicationPath, 0, fileVersionInfoSize, lpData);
if (!fileInfoStatusSuccess)
throw new Exception("Unable to load application information");
String queryPath = "\\StringFileInfo\\" + translation + "\\"
+ propertyKey;
PointerByReference lplpBuffer = new PointerByReference();
IntByReference puLen = new IntByReference();
boolean verQuerySuccess = ExecuteQuery(lpData, queryPath, lplpBuffer,
puLen);
if (!verQuerySuccess)
throw new Exception("Unable to load application information");
int descLength = puLen.getValue();
Pointer pointerToPropertyStringValue = lplpBuffer.getValue();
char[] charBuffer = pointerToPropertyStringValue.getCharArray(0,
descLength);
String propertyValue = new String(charBuffer);
return propertyValue.trim();
}
/**
* @return the Windows specific directory where applications are located
*/
public String getDefaultAppDirectory() {
return LOCATION_WINDOWS;
}
/**
* Extracts the application data for the application on a windows platform
*
* @param file
* the file pointing to the application's location on disk
* @return the {@link ApplicationData} object representing this applications
* system properties
* @throws FileNotFoundException
* if the file specified is null or does not exist on disk
*/
public ApplicationData extractAppData(File file) throws Exception {
String absPath = file.getAbsolutePath();
if (file == null || !file.exists())
throw new FileNotFoundException(absPath);
Icon icon = getSystemIconFor(file);
IntByReference dwDummy = new IntByReference(0);
int fileVersionInfoSize = com.sun.jna.platform.win32.Version.INSTANCE
.GetFileVersionInfoSize(absPath, dwDummy);
String applicationName = FilenameUtils.getBaseName(absPath);
if (fileVersionInfoSize > 0) {
String translation = getTranslation(absPath, fileVersionInfoSize);
String fileDescription = getFilePropertyValue(absPath,
fileVersionInfoSize, translation,
APPLICATION_PROPERTY_KEY_FILE_DESCRIPTION);
String productName = getFilePropertyValue(absPath,
fileVersionInfoSize, translation,
APPLICATION_PROPERTY_KEY_PRODUCT_NAME);
if (fileDescription != "")
applicationName = fileDescription;
else if (productName != "")
applicationName = productName;
}
return new ApplicationData(icon, applicationName, absPath);
}
/**
* Returns the command string to launch the default application for the
* file specified by {@code location}.
* @param location
* the location pointing to the object to be opened
* @return See above.
*/
public String[] getDefaultOpenCommandFor(URL location) {
return new String[] { "cmd", "/c", "start", location.toString() };
}
}