mirror of https://github.com/apache/poi.git
#61459 - HSLFShape.getShapeName() returns name of shapeType and not the shape name
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1829656 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e816131759
commit
7ddef62cc4
|
@ -38,7 +38,14 @@ public interface Shape<
|
|||
* @return the anchor of this shape
|
||||
*/
|
||||
Rectangle2D getAnchor();
|
||||
|
||||
|
||||
/**
|
||||
* @return human-readable name of this shape, e.g. "Rectange 3"
|
||||
*
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
String getShapeName();
|
||||
|
||||
/**
|
||||
* Convenience method to draw a single shape
|
||||
*
|
||||
|
|
|
@ -44,7 +44,10 @@ public class SlideShowFactory {
|
|||
*
|
||||
* @throws IOException if an error occurs while reading the data
|
||||
*/
|
||||
public static SlideShow<?,?> create(NPOIFSFileSystem fs) throws IOException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(NPOIFSFileSystem fs) throws IOException {
|
||||
return create(fs, null);
|
||||
}
|
||||
|
||||
|
@ -59,7 +62,10 @@ public class SlideShowFactory {
|
|||
*
|
||||
* @throws IOException if an error occurs while reading the data
|
||||
*/
|
||||
public static SlideShow<?,?> create(final NPOIFSFileSystem fs, String password) throws IOException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(final NPOIFSFileSystem fs, String password) throws IOException {
|
||||
return create(fs.getRoot(), password);
|
||||
}
|
||||
|
||||
|
@ -72,7 +78,10 @@ public class SlideShowFactory {
|
|||
*
|
||||
* @throws IOException if an error occurs while reading the data
|
||||
*/
|
||||
public static SlideShow<?,?> create(final DirectoryNode root) throws IOException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(final DirectoryNode root) throws IOException {
|
||||
return create(root, null);
|
||||
}
|
||||
|
||||
|
@ -88,7 +97,10 @@ public class SlideShowFactory {
|
|||
*
|
||||
* @throws IOException if an error occurs while reading the data
|
||||
*/
|
||||
public static SlideShow<?,?> create(final DirectoryNode root, String password) throws IOException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(final DirectoryNode root, String password) throws IOException {
|
||||
// Encrypted OOXML files go inside OLE2 containers, is this one?
|
||||
if (root.hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
|
||||
InputStream stream = null;
|
||||
|
@ -136,7 +148,10 @@ public class SlideShowFactory {
|
|||
* @throws IOException if an error occurs while reading the data
|
||||
* @throws EncryptedDocumentException If the SlideShow given is password protected
|
||||
*/
|
||||
public static SlideShow<?,?> create(InputStream inp) throws IOException, EncryptedDocumentException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(InputStream inp) throws IOException, EncryptedDocumentException {
|
||||
return create(inp, null);
|
||||
}
|
||||
|
||||
|
@ -160,7 +175,10 @@ public class SlideShowFactory {
|
|||
* @throws IOException if an error occurs while reading the data
|
||||
* @throws EncryptedDocumentException If the wrong password is given for a protected file
|
||||
*/
|
||||
public static SlideShow<?,?> create(InputStream inp, String password) throws IOException, EncryptedDocumentException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(InputStream inp, String password) throws IOException, EncryptedDocumentException {
|
||||
InputStream is = FileMagic.prepareToCheckMagic(inp);
|
||||
FileMagic fm = FileMagic.valueOf(is);
|
||||
|
||||
|
@ -188,7 +206,10 @@ public class SlideShowFactory {
|
|||
* @throws IOException if an error occurs while reading the data
|
||||
* @throws EncryptedDocumentException If the SlideShow given is password protected
|
||||
*/
|
||||
public static SlideShow<?,?> create(File file) throws IOException, EncryptedDocumentException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(File file) throws IOException, EncryptedDocumentException {
|
||||
return create(file, null);
|
||||
}
|
||||
|
||||
|
@ -207,7 +228,10 @@ public class SlideShowFactory {
|
|||
* @throws IOException if an error occurs while reading the data
|
||||
* @throws EncryptedDocumentException If the wrong password is given for a protected file
|
||||
*/
|
||||
public static SlideShow<?,?> create(File file, String password) throws IOException, EncryptedDocumentException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(File file, String password) throws IOException, EncryptedDocumentException {
|
||||
return create(file, password, false);
|
||||
}
|
||||
|
||||
|
@ -228,7 +252,10 @@ public class SlideShowFactory {
|
|||
* @throws IOException if an error occurs while reading the data
|
||||
* @throws EncryptedDocumentException If the wrong password is given for a protected file
|
||||
*/
|
||||
public static SlideShow<?,?> create(File file, String password, boolean readOnly) throws IOException, EncryptedDocumentException {
|
||||
public static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> create(File file, String password, boolean readOnly) throws IOException, EncryptedDocumentException {
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException(file.toString());
|
||||
}
|
||||
|
@ -246,15 +273,24 @@ public class SlideShowFactory {
|
|||
}
|
||||
}
|
||||
|
||||
protected static SlideShow<?,?> createHSLFSlideShow(Object... args) throws IOException, EncryptedDocumentException {
|
||||
private static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> createHSLFSlideShow(Object... args) throws IOException, EncryptedDocumentException {
|
||||
return createSlideShow("org.apache.poi.hslf.usermodel.HSLFSlideShowFactory", args);
|
||||
}
|
||||
|
||||
protected static SlideShow<?,?> createXSLFSlideShow(Object... args) throws IOException, EncryptedDocumentException {
|
||||
private static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> createXSLFSlideShow(Object... args) throws IOException, EncryptedDocumentException {
|
||||
return createSlideShow("org.apache.poi.xslf.usermodel.XSLFSlideShowFactory", args);
|
||||
}
|
||||
|
||||
protected static SlideShow<?,?> createSlideShow(String factoryClass, Object args[]) throws IOException, EncryptedDocumentException {
|
||||
|
||||
private static <
|
||||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> SlideShow<S,P> createSlideShow(String factoryClass, Object args[]) throws IOException, EncryptedDocumentException {
|
||||
try {
|
||||
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(factoryClass);
|
||||
Class<?> argsClz[] = new Class<?>[args.length];
|
||||
|
@ -269,7 +305,7 @@ public class SlideShowFactory {
|
|||
argsClz[i++] = c;
|
||||
}
|
||||
Method m = clazz.getMethod("createSlideShow", argsClz);
|
||||
return (SlideShow<?,?>)m.invoke(null, args);
|
||||
return (SlideShow<S,P>)m.invoke(null, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) {
|
||||
|
|
|
@ -652,4 +652,76 @@ public class StringUtil {
|
|||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a byte array of 16-bit unicode characters in Little Endian
|
||||
* format (most important byte last), return a Java String representation
|
||||
* of it.
|
||||
*
|
||||
* Scans the byte array for two continous 0 bytes and returns the string before.
|
||||
* <p>
|
||||
*
|
||||
* #61881: there seem to be programs out there, which write the 0-termination also
|
||||
* at the beginning of the string. Check if the next two bytes contain a valid ascii char
|
||||
* and correct the _recdata with a '?' char
|
||||
*
|
||||
*
|
||||
* @param string the byte array to be converted
|
||||
* @param offset the initial offset into the
|
||||
* byte array. it is assumed that string[ offset ] and string[ offset +
|
||||
* 1 ] contain the first 16-bit unicode character
|
||||
* @param len the max. length of the final string
|
||||
* @return the converted string, never <code>null</code>.
|
||||
* @throws ArrayIndexOutOfBoundsException if offset is out of bounds for
|
||||
* the byte array (i.e., is negative or is greater than or equal to
|
||||
* string.length)
|
||||
* @throws IllegalArgumentException if len is too large (i.e.,
|
||||
* there is not enough data in string to create a String of that
|
||||
* length)
|
||||
*/
|
||||
public static String getFromUnicodeLE0Terminated(
|
||||
final byte[] string,
|
||||
final int offset,
|
||||
final int len)
|
||||
throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
|
||||
if ((offset < 0) || (offset >= string.length)) {
|
||||
throw new ArrayIndexOutOfBoundsException("Illegal offset " + offset + " (String data is of length " + string.length + ")");
|
||||
}
|
||||
|
||||
if ((len < 0) || (((string.length - offset) / 2) < len)) {
|
||||
throw new IllegalArgumentException("Illegal length " + len);
|
||||
}
|
||||
|
||||
final int newOffset;
|
||||
final int newMaxLen;
|
||||
final String prefix;
|
||||
|
||||
// #61881 - for now we only check the first char
|
||||
if (len > 0 && string[offset] == 0 && string[offset+1] == 0) {
|
||||
newOffset = offset+2;
|
||||
prefix = "?";
|
||||
|
||||
// check if the next char is garbage and limit the len if necessary
|
||||
final int cp = (len > 1) ? LittleEndian.getShort(string, offset+2) : 0;
|
||||
newMaxLen = Character.isJavaIdentifierPart(cp) ? len-1 : 0;
|
||||
} else {
|
||||
newOffset = offset;
|
||||
prefix = "";
|
||||
newMaxLen = len;
|
||||
}
|
||||
|
||||
int newLen = 0;
|
||||
|
||||
// loop until we find a null-terminated end
|
||||
for(; newLen < newMaxLen; newLen++) {
|
||||
if (string[newOffset + newLen * 2] == 0 && string[newOffset + newLen * 2 + 1] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
newLen = Math.min(newLen, newMaxLen);
|
||||
|
||||
return prefix + ((newLen == 0) ? "" : new String(string, newOffset, newLen * 2, UTF16LE));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,9 +97,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
|
|||
return _sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return human-readable name of this shape, e.g. "Rectange 3"
|
||||
*/
|
||||
@Override
|
||||
public String getShapeName(){
|
||||
return getCNvPr().getName();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import org.apache.poi.EncryptedDocumentException;
|
|||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.openxml4j.opc.PackageAccess;
|
||||
import org.apache.poi.sl.usermodel.SlideShow;
|
||||
import org.apache.poi.sl.usermodel.SlideShowFactory;
|
||||
import org.apache.poi.util.Internal;
|
||||
|
||||
|
@ -45,7 +44,7 @@ public class XSLFSlideShowFactory extends SlideShowFactory {
|
|||
* @throws IOException if an error occurs while reading the data
|
||||
* @throws InvalidFormatException
|
||||
*/
|
||||
public static SlideShow<?,?> createSlideShow(OPCPackage pkg) throws IOException {
|
||||
public static XMLSlideShow createSlideShow(OPCPackage pkg) throws IOException {
|
||||
try {
|
||||
return new XMLSlideShow(pkg);
|
||||
} catch (IllegalArgumentException ioe) {
|
||||
|
@ -72,7 +71,7 @@ public class XSLFSlideShowFactory extends SlideShowFactory {
|
|||
* @throws EncryptedDocumentException If the wrong password is given for a protected file
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public static SlideShow<?,?> createSlideShow(File file, boolean readOnly)
|
||||
public static XMLSlideShow createSlideShow(File file, boolean readOnly)
|
||||
throws IOException, InvalidFormatException {
|
||||
OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE);
|
||||
return createSlideShow(pkg);
|
||||
|
@ -92,7 +91,7 @@ public class XSLFSlideShowFactory extends SlideShowFactory {
|
|||
* @throws InvalidFormatException
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public static SlideShow<?,?> createSlideShow(InputStream stream) throws IOException, InvalidFormatException {
|
||||
public static XMLSlideShow createSlideShow(InputStream stream) throws IOException, InvalidFormatException {
|
||||
OPCPackage pkg = OPCPackage.open(stream);
|
||||
return createSlideShow(pkg);
|
||||
}
|
||||
|
|
|
@ -86,38 +86,8 @@ public final class FontEntityAtom extends RecordAtom {
|
|||
* @return font name
|
||||
*/
|
||||
public String getFontName(){
|
||||
final int maxLen = Math.min(_recdata.length,64);
|
||||
for(int i = 0; i+1 < maxLen; i+=2){
|
||||
//loop until find null-terminated end of the font name
|
||||
if(_recdata[i] == 0 && _recdata[i + 1] == 0 && !isFontNamePremature0terminated(i)) {
|
||||
return StringUtil.getFromUnicodeLE(_recdata, 0, i/2);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* #61881: there seem to be programs out there, which write the 0-termination also
|
||||
* at the beginning of the string. Check if the next two bytes contain a valid ascii char
|
||||
* and correct the _recdata with a '?' char
|
||||
*/
|
||||
private boolean isFontNamePremature0terminated(final int index) {
|
||||
if (index > 0) {
|
||||
// for now we only check the first char
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_recdata.length < index+4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int cp = LittleEndian.getShort(_recdata, index+2);
|
||||
if (!Character.isJavaIdentifierPart(cp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_recdata[index] = '?';
|
||||
return true;
|
||||
final int maxLen = Math.min(_recdata.length,64)/2;
|
||||
return StringUtil.getFromUnicodeLE0Terminated(_recdata, 0, maxLen);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.apache.poi.ddf.EscherClientDataRecord;
|
|||
import org.apache.poi.ddf.EscherColorRef;
|
||||
import org.apache.poi.ddf.EscherColorRef.SysIndexProcedure;
|
||||
import org.apache.poi.ddf.EscherColorRef.SysIndexSource;
|
||||
import org.apache.poi.ddf.EscherComplexProperty;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherProperties;
|
||||
import org.apache.poi.ddf.EscherProperty;
|
||||
|
@ -49,6 +50,7 @@ import org.apache.poi.sl.usermodel.ShapeContainer;
|
|||
import org.apache.poi.sl.usermodel.ShapeType;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
import org.apache.poi.util.Units;
|
||||
|
||||
/**
|
||||
|
@ -123,8 +125,15 @@ public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
|
|||
/**
|
||||
* @return name of the shape.
|
||||
*/
|
||||
@Override
|
||||
public String getShapeName(){
|
||||
return getShapeType().nativeName;
|
||||
final EscherComplexProperty ep = getEscherProperty(getEscherOptRecord(), EscherProperties.GROUPSHAPE__SHAPENAME);
|
||||
if (ep != null) {
|
||||
final byte[] cd = ep.getComplexData();
|
||||
return StringUtil.getFromUnicodeLE0Terminated(cd, 0, cd.length/2);
|
||||
} else {
|
||||
return getShapeType().nativeName+" "+getShapeId();
|
||||
}
|
||||
}
|
||||
|
||||
public ShapeType getShapeType(){
|
||||
|
|
|
@ -157,4 +157,19 @@ public abstract class BaseTestSlideShow {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shapeName() throws IOException {
|
||||
final String file = "SampleShow.ppt"+(getClass().getSimpleName().contains("XML")?"x":"");
|
||||
try (final InputStream is = slTests.openResourceAsStream(file)) {
|
||||
try (final SlideShow<? extends Shape, ?> ppt = SlideShowFactory.create(is)) {
|
||||
final List<? extends Shape> shapes1 = ppt.getSlides().get(0).getShapes();
|
||||
assertEquals("The Title", shapes1.get(0).getShapeName());
|
||||
assertEquals("Another Subtitle", shapes1.get(1).getShapeName());
|
||||
final List<? extends Shape> shapes2 = ppt.getSlides().get(1).getShapes();
|
||||
assertEquals("Title 1", shapes2.get(0).getShapeName());
|
||||
assertEquals("Content Placeholder 2", shapes2.get(1).getShapeName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue