/*******************************************************************************
* Copyright (c) 2009, 2011 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat Incorporated - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.internal.cdt.libhover;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import org.eclipse.cdt.utils.Platform;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.linuxtools.cdt.libhover.ClassInfo;
import org.eclipse.linuxtools.cdt.libhover.FunctionInfo;
import org.eclipse.linuxtools.cdt.libhover.LibHoverInfo;
import org.eclipse.linuxtools.cdt.libhover.LibhoverPlugin;
import org.eclipse.linuxtools.cdt.libhover.TypedefInfo;
import org.osgi.framework.Bundle;
public class LibHoverLibrary {
private String name;
private String location;
private String docs;
private String nameSpace;
private boolean isCPP;
private LibHoverInfo hoverInfo = new LibHoverInfo();
private boolean haveReadHoverInfo = false;
public LibHoverLibrary(String name, String location, String docs,
String nameSpace, boolean isCPP) {
this.name = name;
this.location = location;
this.docs = docs;
this.isCPP = isCPP;
this.nameSpace = nameSpace;
}
/**
* Get the name of the library
*
* @return the name of the library
*/
public String getName() {
return name;
}
/**
* Get the location of the library hover info (URL or file name)
*
* @return the URL or file name string for the library hover info location
*/
public String getLocation() {
return location;
}
/**
* Get the browser help documentation URL for this library
*
* @return the name of the help documentation URL
*/
public String getDocs() {
return docs;
}
/**
* Set the browser help documentation URL for this library
*
* @param docs The name of the help documentation URL
*/
public void setDocs(String docs) {
this.docs = docs;
}
/**
* Get the name space of the library hover extension
*
* @return the name space of the library extension
*/
public String getNameSpace() {
return nameSpace;
}
/**
* Is this library a C++ library?
*
* @return true if C++ library, false otherwise
*/
public boolean isCPP() {
return isCPP;
}
/**
* Get the library hover info for this library
*
* @return the library hover info for this library
*/
public synchronized LibHoverInfo getHoverInfo() {
// We lazily get the hover info for this library since it is possible
// the user will never access or ultimately need it if another library
// supplies the information first.
if (!haveReadHoverInfo) {
try (InputStream docStream = getDocStreamForHoverInfo();
ObjectInputStream input = new ObjectInputStream(docStream)) {
hoverInfo = (LibHoverInfo)input.readObject();
haveReadHoverInfo = true;
} catch (URISyntaxException|MalformedURLException|ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// Do nothing as empty devhelp causes this
}
}
return hoverInfo;
}
private InputStream getDocStreamForHoverInfo() throws URISyntaxException, IOException {
URI acDoc = new URI(location);
IPath p = URIUtil.toPath(acDoc);
if (p == null) {
URL url = acDoc.toURL();
URLConnection c = url.openConnection();
c.setReadTimeout(5000); // pick a timeout value less than 15s (default)
return c.getInputStream();
} else {
// Try to open the file local to the plug-in declaring the
// extension...or fall back to the libhover plug-in itself
// if no name space for the plug-in is stored.
Bundle bundle = LibhoverPlugin.getDefault().getBundle();
String nameSpace = getNameSpace();
if (nameSpace != null) {
bundle = Platform.getBundle(nameSpace);
}
try {
return FileLocator.openStream(bundle, p, false);
} catch (IOException e) {
// File is not local to plug-in, try file system.
return new FileInputStream(p.toFile());
}
}
}
/**
* Set the library hover info.
*
* @param hoverInfo the library hover info to set
*/
public synchronized void setHoverinfo(LibHoverInfo hoverInfo) {
this.hoverInfo = hoverInfo;
}
/**
* Fetch the class info for a given class.
*
* @param className the name of the class to fetch info for
* @return ClassInfo or null if no class info can be found
*/
public ClassInfo getClassInfo(String className, ArrayList<String> templateTypes) {
String typedefName = className.replaceAll("<.*>", "<>"); //$NON-NLS-1$ //$NON-NLS-2$
TypedefInfo typedef = getHoverInfo().typedefs.get(typedefName);
if (typedef != null) {
className = typedef.getTransformedType(className); // Reset class name to typedef transformation
}
int index = className.indexOf('<');
// Check if it is a template reference.
if (index != -1) {
resolveTemplateTypes(className, templateTypes, index);
// It is. We want to see if there are partial specific templates
// and we choose the first match. If nothing matches our particular
// case, we fall back on the initial generic template.
ClassInfo info = getHoverInfo().classes.get(className.substring(0, index));
if (info != null) {
ArrayList<ClassInfo> children = info.getChildren();
if (children != null && children.size() > 0) {
for (int x = 0; x < children.size(); ++x) {
ClassInfo child = children.get(x);
if (className.matches(child.getClassName())) {
info = child;
break;
}
}
}
}
return info;
}
// Otherwise no template, just fetch the class info directly.
return getHoverInfo().classes.get(className);
}
private void resolveTemplateTypes(String className,
ArrayList<String> templateTypes, int index) {
int startIndex = index + 1;
int i = startIndex;
int count = 1;
while (count > 0 && i < className.length()) {
char x = className.charAt(i);
switch (x) {
case ('<'):
++count;
break;
case ('>'):
--count;
if (count == 0) {
templateTypes.add(className.substring(startIndex, i).trim());
}
break;
case (','): {
if (count == 1) {
templateTypes.add(className.substring(startIndex, i).trim());
startIndex = i + 1;
}
}
break;
}
++i;
}
}
/**
* Fetch the function info for a given function.
*
* @param name of function to find info for
* @return FunctionInfo or null if no function info exists
*/
public FunctionInfo getFunctionInfo(String name) {
return getHoverInfo().functions.get(name);
}
}