Mercurial > hg > openjdk > jigsaw > jdk
changeset 7346:f90b7503019f
Merge
author | vinnie |
---|---|
date | Wed, 17 Apr 2013 02:53:02 -0700 |
parents | 13e18d3ac414 (current diff) 779ba708fee3 (diff) |
children | 7ded74ffea36 |
files | src/share/lib/security/java.security-linux src/share/lib/security/java.security-macosx src/share/lib/security/java.security-solaris src/share/lib/security/java.security-windows src/share/native/java/lang/ResourceBundle.c |
diffstat | 310 files changed, 11169 insertions(+), 2313 deletions(-) [+] |
line wrap: on
line diff
--- a/make/java/java/FILES_c.gmk Tue Apr 16 05:32:39 2013 -0700 +++ b/make/java/java/FILES_c.gmk Wed Apr 17 02:53:02 2013 -0700 @@ -48,7 +48,6 @@ Proxy.c \ RandomAccessFile.c \ RandomAccessFile_md.c \ - ResourceBundle.c \ Runtime.c \ SecurityManager.c \ Shutdown.c \
--- a/make/java/java/mapfile-vers Tue Apr 16 05:32:39 2013 -0700 +++ b/make/java/java/mapfile-vers Wed Apr 17 02:53:02 2013 -0700 @@ -134,7 +134,6 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load; Java_java_lang_ClassLoader_00024NativeLibrary_unload; Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib; - Java_java_lang_ClassLoader_getCaller; Java_java_lang_ClassLoader_registerNatives; Java_java_lang_Compiler_registerNatives; Java_java_lang_Double_longBitsToDouble; @@ -233,7 +232,6 @@ Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2; Java_java_security_AccessController_getStackAccessControlContext; Java_java_security_AccessController_getInheritedAccessControlContext; - Java_java_util_ResourceBundle_getClassContext; Java_java_util_TimeZone_getSystemTimeZoneID; Java_java_util_TimeZone_getSystemGMTOffsetID; Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
--- a/make/java/java/reorder-i586 Tue Apr 16 05:32:39 2013 -0700 +++ b/make/java/java/reorder-i586 Wed Apr 17 02:53:02 2013 -0700 @@ -73,7 +73,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/make/java/java/reorder-sparc Tue Apr 16 05:32:39 2013 -0700 +++ b/make/java/java/reorder-sparc Wed Apr 17 02:53:02 2013 -0700 @@ -78,7 +78,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/make/java/java/reorder-sparcv9 Tue Apr 16 05:32:39 2013 -0700 +++ b/make/java/java/reorder-sparcv9 Wed Apr 17 02:53:02 2013 -0700 @@ -74,7 +74,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/make/sun/font/FILES_c.gmk Tue Apr 16 05:32:39 2013 -0700 +++ b/make/sun/font/FILES_c.gmk Wed Apr 17 02:53:02 2013 -0700 @@ -106,7 +106,21 @@ OpenTypeLayoutEngine.cpp \ ThaiLayoutEngine.cpp \ ScriptAndLanguageTags.cpp \ - FontInstanceAdapter.cpp + FontInstanceAdapter.cpp \ + ContextualGlyphInsertionProc2.cpp \ + ContextualGlyphSubstProc2.cpp \ + GXLayoutEngine2.cpp \ + IndicRearrangementProcessor2.cpp \ + LigatureSubstProc2.cpp \ + MorphTables2.cpp \ + NonContextualGlyphSubstProc2.cpp \ + SegmentArrayProcessor2.cpp \ + SegmentSingleProcessor2.cpp \ + SimpleArrayProcessor2.cpp \ + SingleTableProcessor2.cpp \ + StateTableProcessor2.cpp \ + SubtableProcessor2.cpp \ + TrimmedArrayProcessor2.cpp ifeq ($(PLATFORM),windows)
--- a/makefiles/mapfiles/libjava/mapfile-vers Tue Apr 16 05:32:39 2013 -0700 +++ b/makefiles/mapfiles/libjava/mapfile-vers Wed Apr 17 02:53:02 2013 -0700 @@ -134,7 +134,6 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load; Java_java_lang_ClassLoader_00024NativeLibrary_unload; Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib; - Java_java_lang_ClassLoader_getCaller; Java_java_lang_ClassLoader_registerNatives; Java_java_lang_Compiler_registerNatives; Java_java_lang_Double_longBitsToDouble; @@ -233,7 +232,6 @@ Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2; Java_java_security_AccessController_getStackAccessControlContext; Java_java_security_AccessController_getInheritedAccessControlContext; - Java_java_util_ResourceBundle_getClassContext; Java_java_util_TimeZone_getSystemTimeZoneID; Java_java_util_TimeZone_getSystemGMTOffsetID; Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
--- a/makefiles/mapfiles/libjava/reorder-sparc Tue Apr 16 05:32:39 2013 -0700 +++ b/makefiles/mapfiles/libjava/reorder-sparc Wed Apr 17 02:53:02 2013 -0700 @@ -78,7 +78,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/makefiles/mapfiles/libjava/reorder-sparcv9 Tue Apr 16 05:32:39 2013 -0700 +++ b/makefiles/mapfiles/libjava/reorder-sparcv9 Wed Apr 17 02:53:02 2013 -0700 @@ -74,7 +74,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/makefiles/mapfiles/libjava/reorder-x86 Tue Apr 16 05:32:39 2013 -0700 +++ b/makefiles/mapfiles/libjava/reorder-x86 Wed Apr 17 02:53:02 2013 -0700 @@ -73,7 +73,6 @@ # Test Sleep # Test IntToString # Test LoadToolkit -text: .text%Java_java_util_ResourceBundle_getClassContext; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess;
--- a/src/macosx/classes/sun/lwawt/LWWindowPeer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/macosx/classes/sun/lwawt/LWWindowPeer.java Wed Apr 17 02:53:02 2013 -0700 @@ -170,7 +170,7 @@ setTitle(((Dialog) getTarget()).getTitle()); } - setAlwaysOnTop(getTarget().isAlwaysOnTop()); + updateAlwaysOnTopState(); updateMinimumSize(); final Shape shape = getTarget().getShape(); @@ -357,8 +357,8 @@ } @Override - public void setAlwaysOnTop(boolean value) { - platformWindow.setAlwaysOnTop(value); + public void updateAlwaysOnTopState() { + platformWindow.setAlwaysOnTop(getTarget().isAlwaysOnTop()); } @Override
--- a/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,7 +180,7 @@ } @Override - public void setAlwaysOnTop(boolean alwaysOnTop) { + public void updateAlwaysOnTopState() { } @Override
--- a/src/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ } // 1.6 peer method - public void setAlwaysOnTop(boolean value) { + public void updateAlwaysOnTopState() { // no-op, since we just show the native print dialog }
--- a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Wed Apr 17 02:53:02 2013 -0700 @@ -243,12 +243,17 @@ * sending warnings to listeners. */ protected void warningOccurred(int code) { - if ((code < 0) || (code > MAX_WARNING)){ - throw new InternalError("Invalid warning index"); + cbLock.lock(); + try { + if ((code < 0) || (code > MAX_WARNING)){ + throw new InternalError("Invalid warning index"); + } + processWarningOccurred + ("com.sun.imageio.plugins.jpeg.JPEGImageReaderResources", + Integer.toString(code)); + } finally { + cbLock.unlock(); } - processWarningOccurred - ("com.sun.imageio.plugins.jpeg.JPEGImageReaderResources", - Integer.toString(code)); } /** @@ -265,7 +270,12 @@ * library warnings from being printed to stderr. */ protected void warningWithMessage(String msg) { - processWarningOccurred(msg); + cbLock.lock(); + try { + processWarningOccurred(msg); + } finally { + cbLock.unlock(); + } } public void setInput(Object input, @@ -274,18 +284,55 @@ { setThreadLock(); try { + cbLock.check(); + super.setInput(input, seekForwardOnly, ignoreMetadata); this.ignoreMetadata = ignoreMetadata; resetInternalState(); iis = (ImageInputStream) input; // Always works - setSource(structPointer, iis); + setSource(structPointer); } finally { clearThreadLock(); } } - private native void setSource(long structPointer, - ImageInputStream source); + /** + * This method is called from native code in order to fill + * native input buffer. + * + * We block any attempt to change the reading state during this + * method, in order to prevent a corruption of the native decoder + * state. + * + * @return number of bytes read from the stream. + */ + private int readInputData(byte[] buf, int off, int len) throws IOException { + cbLock.lock(); + try { + return iis.read(buf, off, len); + } finally { + cbLock.unlock(); + } + } + + /** + * This method is called from the native code in order to + * skip requested number of bytes in the input stream. + * + * @param n + * @return + * @throws IOException + */ + private long skipInputBytes(long n) throws IOException { + cbLock.lock(); + try { + return iis.skipBytes(n); + } finally { + cbLock.unlock(); + } + } + + private native void setSource(long structPointer); private void checkTablesOnly() throws IOException { if (debug) { @@ -337,6 +384,8 @@ public int getNumImages(boolean allowSearch) throws IOException { setThreadLock(); try { // locked thread + cbLock.check(); + return getNumImagesOnThread(allowSearch); } finally { clearThreadLock(); @@ -536,8 +585,13 @@ if (debug) { System.out.println("pushing back " + num + " bytes"); } - iis.seek(iis.getStreamPosition()-num); - // The buffer is clear after this, so no need to set haveSeeked. + cbLock.lock(); + try { + iis.seek(iis.getStreamPosition()-num); + // The buffer is clear after this, so no need to set haveSeeked. + } finally { + cbLock.unlock(); + } } /** @@ -644,7 +698,12 @@ * Ignore this profile. */ iccCS = null; - warningOccurred(WARNING_IGNORE_INVALID_ICC); + cbLock.lock(); + try { + warningOccurred(WARNING_IGNORE_INVALID_ICC); + } finally { + cbLock.unlock(); + } } } } @@ -653,6 +712,7 @@ setThreadLock(); try { if (currentImage != imageIndex) { + cbLock.check(); readHeader(imageIndex, true); } return width; @@ -665,6 +725,7 @@ setThreadLock(); try { if (currentImage != imageIndex) { + cbLock.check(); readHeader(imageIndex, true); } return height; @@ -693,6 +754,8 @@ setThreadLock(); try { if (currentImage != imageIndex) { + cbLock.check(); + readHeader(imageIndex, true); } @@ -716,6 +779,7 @@ private Iterator getImageTypesOnThread(int imageIndex) throws IOException { if (currentImage != imageIndex) { + cbLock.check(); readHeader(imageIndex, true); } @@ -931,6 +995,7 @@ setThreadLock(); try { if (!tablesOnlyChecked) { + cbLock.check(); checkTablesOnly(); } return streamMetadata; @@ -951,6 +1016,8 @@ return imageMetadata; } + cbLock.check(); + gotoImage(imageIndex); imageMetadata = new JPEGMetadata(false, false, iis, this); @@ -967,6 +1034,7 @@ throws IOException { setThreadLock(); try { + cbLock.check(); try { readInternal(imageIndex, param, false); } catch (RuntimeException e) { @@ -1196,58 +1264,63 @@ } target.setRect(destROI.x, destROI.y + y, raster); - processImageUpdate(image, - destROI.x, destROI.y+y, - raster.getWidth(), 1, - 1, 1, - destinationBands); - if ((y > 0) && (y%progInterval == 0)) { - int height = target.getHeight()-1; - float percentOfPass = ((float)y)/height; - if (progressive) { - if (knownPassCount != UNKNOWN) { - processImageProgress((pass + percentOfPass)*100.0F - / knownPassCount); - } else if (maxProgressivePass != Integer.MAX_VALUE) { - // Use the range of allowed progressive passes - processImageProgress((pass + percentOfPass)*100.0F - / (maxProgressivePass - minProgressivePass + 1)); + cbLock.lock(); + try { + processImageUpdate(image, + destROI.x, destROI.y+y, + raster.getWidth(), 1, + 1, 1, + destinationBands); + if ((y > 0) && (y%progInterval == 0)) { + int height = target.getHeight()-1; + float percentOfPass = ((float)y)/height; + if (progressive) { + if (knownPassCount != UNKNOWN) { + processImageProgress((pass + percentOfPass)*100.0F + / knownPassCount); + } else if (maxProgressivePass != Integer.MAX_VALUE) { + // Use the range of allowed progressive passes + processImageProgress((pass + percentOfPass)*100.0F + / (maxProgressivePass - minProgressivePass + 1)); + } else { + // Assume there are a minimum of MIN_ESTIMATED_PASSES + // and that there is always one more pass + // Compute the percentage as the percentage at the end + // of the previous pass, plus the percentage of this + // pass scaled to be the percentage of the total remaining, + // assuming a minimum of MIN_ESTIMATED_PASSES passes and + // that there is always one more pass. This is monotonic + // and asymptotic to 1.0, which is what we need. + int remainingPasses = // including this one + Math.max(2, MIN_ESTIMATED_PASSES-pass); + int totalPasses = pass + remainingPasses-1; + progInterval = Math.max(height/20*totalPasses, + totalPasses); + if (y%progInterval == 0) { + percentToDate = previousPassPercentage + + (1.0F - previousPassPercentage) + * (percentOfPass)/remainingPasses; + if (debug) { + System.out.print("pass= " + pass); + System.out.print(", y= " + y); + System.out.print(", progInt= " + progInterval); + System.out.print(", % of pass: " + percentOfPass); + System.out.print(", rem. passes: " + + remainingPasses); + System.out.print(", prev%: " + + previousPassPercentage); + System.out.print(", %ToDate: " + percentToDate); + System.out.print(" "); + } + processImageProgress(percentToDate*100.0F); + } + } } else { - // Assume there are a minimum of MIN_ESTIMATED_PASSES - // and that there is always one more pass - // Compute the percentage as the percentage at the end - // of the previous pass, plus the percentage of this - // pass scaled to be the percentage of the total remaining, - // assuming a minimum of MIN_ESTIMATED_PASSES passes and - // that there is always one more pass. This is monotonic - // and asymptotic to 1.0, which is what we need. - int remainingPasses = // including this one - Math.max(2, MIN_ESTIMATED_PASSES-pass); - int totalPasses = pass + remainingPasses-1; - progInterval = Math.max(height/20*totalPasses, - totalPasses); - if (y%progInterval == 0) { - percentToDate = previousPassPercentage + - (1.0F - previousPassPercentage) - * (percentOfPass)/remainingPasses; - if (debug) { - System.out.print("pass= " + pass); - System.out.print(", y= " + y); - System.out.print(", progInt= " + progInterval); - System.out.print(", % of pass: " + percentOfPass); - System.out.print(", rem. passes: " - + remainingPasses); - System.out.print(", prev%: " - + previousPassPercentage); - System.out.print(", %ToDate: " + percentToDate); - System.out.print(" "); - } - processImageProgress(percentToDate*100.0F); - } + processImageProgress(percentOfPass * 100.0F); } - } else { - processImageProgress(percentOfPass * 100.0F); } + } finally { + cbLock.unlock(); } } @@ -1260,33 +1333,58 @@ } private void passStarted (int pass) { - this.pass = pass; - previousPassPercentage = percentToDate; - processPassStarted(image, - pass, - minProgressivePass, - maxProgressivePass, - 0, 0, - 1,1, - destinationBands); + cbLock.lock(); + try { + this.pass = pass; + previousPassPercentage = percentToDate; + processPassStarted(image, + pass, + minProgressivePass, + maxProgressivePass, + 0, 0, + 1,1, + destinationBands); + } finally { + cbLock.unlock(); + } } private void passComplete () { - processPassComplete(image); + cbLock.lock(); + try { + processPassComplete(image); + } finally { + cbLock.unlock(); + } } void thumbnailStarted(int thumbnailIndex) { - processThumbnailStarted(currentImage, thumbnailIndex); + cbLock.lock(); + try { + processThumbnailStarted(currentImage, thumbnailIndex); + } finally { + cbLock.unlock(); + } } // Provide access to protected superclass method void thumbnailProgress(float percentageDone) { - processThumbnailProgress(percentageDone); + cbLock.lock(); + try { + processThumbnailProgress(percentageDone); + } finally { + cbLock.unlock(); + } } // Provide access to protected superclass method void thumbnailComplete() { - processThumbnailComplete(); + cbLock.lock(); + try { + processThumbnailComplete(); + } finally { + cbLock.unlock(); + } } /** @@ -1310,6 +1408,11 @@ public void abort() { setThreadLock(); try { + /** + * NB: we do not check the call back lock here, + * we allow to abort the reader any time. + */ + super.abort(); abortRead(structPointer); } finally { @@ -1332,6 +1435,7 @@ setThreadLock(); Raster retval = null; try { + cbLock.check(); /* * This could be further optimized by not resetting the dest. * offset and creating a translated raster in readInternal() @@ -1371,6 +1475,8 @@ public int getNumThumbnails(int imageIndex) throws IOException { setThreadLock(); try { + cbLock.check(); + getImageMetadata(imageIndex); // checks iis state for us // Now check the jfif segments JFIFMarkerSegment jfif = @@ -1391,6 +1497,8 @@ throws IOException { setThreadLock(); try { + cbLock.check(); + if ((thumbnailIndex < 0) || (thumbnailIndex >= getNumThumbnails(imageIndex))) { throw new IndexOutOfBoundsException("No such thumbnail"); @@ -1409,6 +1517,8 @@ throws IOException { setThreadLock(); try { + cbLock.check(); + if ((thumbnailIndex < 0) || (thumbnailIndex >= getNumThumbnails(imageIndex))) { throw new IndexOutOfBoundsException("No such thumbnail"); @@ -1428,6 +1538,8 @@ throws IOException { setThreadLock(); try { + cbLock.check(); + if ((thumbnailIndex < 0) || (thumbnailIndex >= getNumThumbnails(imageIndex))) { throw new IndexOutOfBoundsException("No such thumbnail"); @@ -1468,6 +1580,7 @@ public void reset() { setThreadLock(); try { + cbLock.check(); super.reset(); } finally { clearThreadLock(); @@ -1479,6 +1592,8 @@ public void dispose() { setThreadLock(); try { + cbLock.check(); + if (structPointer != 0) { disposerRecord.dispose(); structPointer = 0; @@ -1540,6 +1655,36 @@ theThread = null; } } + + private CallBackLock cbLock = new CallBackLock(); + + private static class CallBackLock { + + private State lockState; + + CallBackLock() { + lockState = State.Unlocked; + } + + void check() { + if (lockState != State.Unlocked) { + throw new IllegalStateException("Access to the reader is not allowed"); + } + } + + private void lock() { + lockState = State.Locked; + } + + private void unlock() { + lockState = State.Unlocked; + } + + private static enum State { + Unlocked, + Locked + } + } } /**
--- a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Wed Apr 17 02:53:02 2013 -0700 @@ -183,8 +183,7 @@ return null; } }); - initWriterIDs(ImageOutputStream.class, - JPEGQTable.class, + initWriterIDs(JPEGQTable.class, JPEGHuffmanTable.class); } @@ -200,11 +199,13 @@ public void setOutput(Object output) { setThreadLock(); try { + cbLock.check(); + super.setOutput(output); // validates output resetInternalState(); ios = (ImageOutputStream) output; // so this will always work // Set the native destination - setDest(structPointer, ios); + setDest(structPointer); } finally { clearThreadLock(); } @@ -359,6 +360,8 @@ ImageWriteParam param) throws IOException { setThreadLock(); try { + cbLock.check(); + writeOnThread(streamMetadata, image, param); } finally { clearThreadLock(); @@ -1082,13 +1085,18 @@ haveMetadata, restartInterval); - if (aborted) { - processWriteAborted(); - } else { - processImageComplete(); + cbLock.lock(); + try { + if (aborted) { + processWriteAborted(); + } else { + processImageComplete(); + } + + ios.flush(); + } finally { + cbLock.unlock(); } - - ios.flush(); currentImage++; // After a successful write } @@ -1096,6 +1104,8 @@ throws IOException { setThreadLock(); try { + cbLock.check(); + prepareWriteSequenceOnThread(streamMetadata); } finally { clearThreadLock(); @@ -1175,6 +1185,8 @@ throws IOException { setThreadLock(); try { + cbLock.check(); + if (sequencePrepared == false) { throw new IllegalStateException("sequencePrepared not called!"); } @@ -1188,6 +1200,8 @@ public void endWriteSequence() throws IOException { setThreadLock(); try { + cbLock.check(); + if (sequencePrepared == false) { throw new IllegalStateException("sequencePrepared not called!"); } @@ -1200,6 +1214,10 @@ public synchronized void abort() { setThreadLock(); try { + /** + * NB: we do not check the call back lock here, we allow to abort + * the reader any time. + */ super.abort(); abortWrite(structPointer); } finally { @@ -1223,6 +1241,8 @@ public void reset() { setThreadLock(); try { + cbLock.check(); + super.reset(); } finally { clearThreadLock(); @@ -1232,6 +1252,8 @@ public void dispose() { setThreadLock(); try { + cbLock.check(); + if (structPointer != 0) { disposerRecord.dispose(); structPointer = 0; @@ -1251,13 +1273,18 @@ * sending warnings to listeners. */ void warningOccurred(int code) { - if ((code < 0) || (code > MAX_WARNING)){ - throw new InternalError("Invalid warning index"); + cbLock.lock(); + try { + if ((code < 0) || (code > MAX_WARNING)){ + throw new InternalError("Invalid warning index"); + } + processWarningOccurred + (currentImage, + "com.sun.imageio.plugins.jpeg.JPEGImageWriterResources", + Integer.toString(code)); + } finally { + cbLock.unlock(); } - processWarningOccurred - (currentImage, - "com.sun.imageio.plugins.jpeg.JPEGImageWriterResources", - Integer.toString(code)); } /** @@ -1274,21 +1301,41 @@ * library warnings from being printed to stderr. */ void warningWithMessage(String msg) { - processWarningOccurred(currentImage, msg); + cbLock.lock(); + try { + processWarningOccurred(currentImage, msg); + } finally { + cbLock.unlock(); + } } void thumbnailStarted(int thumbnailIndex) { - processThumbnailStarted(currentImage, thumbnailIndex); + cbLock.lock(); + try { + processThumbnailStarted(currentImage, thumbnailIndex); + } finally { + cbLock.unlock(); + } } // Provide access to protected superclass method void thumbnailProgress(float percentageDone) { - processThumbnailProgress(percentageDone); + cbLock.lock(); + try { + processThumbnailProgress(percentageDone); + } finally { + cbLock.unlock(); + } } // Provide access to protected superclass method void thumbnailComplete() { - processThumbnailComplete(); + cbLock.lock(); + try { + processThumbnailComplete(); + } finally { + cbLock.unlock(); + } } ///////// End of Package-access API @@ -1615,16 +1662,14 @@ ////////////// Native methods and callbacks /** Sets up static native structures. */ - private static native void initWriterIDs(Class iosClass, - Class qTableClass, + private static native void initWriterIDs(Class qTableClass, Class huffClass); /** Sets up per-writer native structure and returns a pointer to it. */ private native long initJPEGImageWriter(); /** Sets up native structures for output stream */ - private native void setDest(long structPointer, - ImageOutputStream ios); + private native void setDest(long structPointer); /** * Returns <code>true</code> if the write was aborted. @@ -1749,7 +1794,12 @@ } raster.setRect(sourceLine); if ((y > 7) && (y%8 == 0)) { // Every 8 scanlines - processImageProgress((float) y / (float) sourceHeight * 100.0F); + cbLock.lock(); + try { + processImageProgress((float) y / (float) sourceHeight * 100.0F); + } finally { + cbLock.unlock(); + } } } @@ -1777,6 +1827,25 @@ } } + /** + * This method is called from native code in order to write encoder + * output to the destination. + * + * We block any attempt to change the writer state during this + * method, in order to prevent a corruption of the native encoder + * state. + */ + private void writeOutputData(byte[] data, int offset, int len) + throws IOException + { + cbLock.lock(); + try { + ios.write(data, offset, len); + } finally { + cbLock.unlock(); + } + } + private Thread theThread = null; private int theLockCount = 0; @@ -1811,4 +1880,34 @@ theThread = null; } } + + private CallBackLock cbLock = new CallBackLock(); + + private static class CallBackLock { + + private State lockState; + + CallBackLock() { + lockState = State.Unlocked; + } + + void check() { + if (lockState != State.Unlocked) { + throw new IllegalStateException("Access to the writer is not allowed"); + } + } + + private void lock() { + lockState = State.Locked; + } + + private void unlock() { + lockState = State.Unlocked; + } + + private static enum State { + Unlocked, + Locked + } + } }
--- a/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.io.ObjectInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.security.Permission; import java.util.Map; import java.util.logging.Level; @@ -213,7 +214,6 @@ Object moi; - // ------------------------------ // ------------------------------ Constructor<?> cons = findConstructor(theClass, null); @@ -224,6 +224,7 @@ // Instantiate the new object try { ReflectUtil.checkPackageAccess(theClass); + ensureClassAccess(theClass); moi= cons.newInstance(); } catch (InvocationTargetException e) { // Wrap the exception. @@ -270,7 +271,6 @@ checkMBeanPermission(theClass, null, null, "instantiate"); // Instantiate the new object - // ------------------------------ // ------------------------------ final Class<?>[] tab; @@ -300,6 +300,7 @@ } try { ReflectUtil.checkPackageAccess(theClass); + ensureClassAccess(theClass); moi = cons.newInstance(params); } catch (NoSuchMethodError error) { @@ -741,4 +742,13 @@ sm.checkPermission(perm); } } + + private static void ensureClassAccess(Class clazz) + throws IllegalAccessException + { + int mod = clazz.getModifiers(); + if (!Modifier.isPublic(mod)) { + throw new IllegalAccessException("Class is not public and can't be instantiated"); + } + } }
--- a/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java Wed Apr 17 02:53:02 2013 -0700 @@ -56,7 +56,7 @@ // from simultaneous creation and destruction // reduces possibility of deadlock, compared to // synchronizing to the class instance - private Object traRecLock = new Object(); + private final Object traRecLock = new Object(); // DEVICE ATTRIBUTES @@ -474,7 +474,7 @@ This is necessary for Receivers retrieved via MidiSystem.getReceiver() (which opens the device implicitely). */ - protected abstract class AbstractReceiver implements MidiDeviceReceiver { + abstract class AbstractReceiver implements MidiDeviceReceiver { private boolean open = true; @@ -483,24 +483,24 @@ Receiver. Therefore, subclasses should not override this method. Instead, they should implement implSend(). */ - public synchronized void send(MidiMessage message, long timeStamp) { - if (open) { - implSend(message, timeStamp); - } else { + @Override + public final synchronized void send(final MidiMessage message, + final long timeStamp) { + if (!open) { throw new IllegalStateException("Receiver is not open"); } + implSend(message, timeStamp); } - - protected abstract void implSend(MidiMessage message, long timeStamp); - + abstract void implSend(MidiMessage message, long timeStamp); /** Close the Receiver. * Here, the call to the magic method closeInternal() takes place. * Therefore, subclasses that override this method must call * 'super.close()'. */ - public void close() { + @Override + public final void close() { open = false; synchronized (AbstractMidiDevice.this.traRecLock) { AbstractMidiDevice.this.getReceiverList().remove(this); @@ -508,11 +508,12 @@ AbstractMidiDevice.this.closeInternal(this); } - public MidiDevice getMidiDevice() { + @Override + public final MidiDevice getMidiDevice() { return AbstractMidiDevice.this; } - protected boolean isOpen() { + final boolean isOpen() { return open; }
--- a/src/share/classes/com/sun/media/sound/FastShortMessage.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/com/sun/media/sound/FastShortMessage.java Wed Apr 17 02:53:02 2013 -0700 @@ -32,7 +32,7 @@ * * @author Florian Bomers */ -class FastShortMessage extends ShortMessage { +final class FastShortMessage extends ShortMessage { private int packedMsg; public FastShortMessage(int packedMsg) throws InvalidMidiDataException {
--- a/src/share/classes/com/sun/media/sound/FastSysexMessage.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/com/sun/media/sound/FastSysexMessage.java Wed Apr 17 02:53:02 2013 -0700 @@ -32,7 +32,7 @@ * * @author Florian Bomers */ -class FastSysexMessage extends SysexMessage { +final class FastSysexMessage extends SysexMessage { FastSysexMessage(byte[] data) throws InvalidMidiDataException { super(data);
--- a/src/share/classes/com/sun/media/sound/MidiOutDevice.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/com/sun/media/sound/MidiOutDevice.java Wed Apr 17 02:53:02 2013 -0700 @@ -103,9 +103,9 @@ class MidiOutReceiver extends AbstractReceiver { - protected void implSend(MidiMessage message, long timeStamp) { - int length = message.getLength(); - int status = message.getStatus(); + void implSend(final MidiMessage message, final long timeStamp) { + final int length = message.getLength(); + final int status = message.getStatus(); if (length <= 3 && status != 0xF0 && status != 0xF7) { int packedMsg; if (message instanceof ShortMessage) { @@ -140,11 +140,15 @@ } nSendShortMessage(id, packedMsg, timeStamp); } else { + final byte[] data; if (message instanceof FastSysexMessage) { - nSendLongMessage(id, ((FastSysexMessage) message).getReadOnlyMessage(), - length, timeStamp); + data = ((FastSysexMessage) message).getReadOnlyMessage(); } else { - nSendLongMessage(id, message.getMessage(), length, timeStamp); + data = message.getMessage(); + } + final int dataLength = Math.min(length, data.length); + if (dataLength > 0) { + nSendLongMessage(id, data, dataLength, timeStamp); } } }
--- a/src/share/classes/com/sun/media/sound/RealTimeSequencer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/com/sun/media/sound/RealTimeSequencer.java Wed Apr 17 02:53:02 2013 -0700 @@ -1026,7 +1026,7 @@ class SequencerReceiver extends AbstractReceiver { - protected void implSend(MidiMessage message, long timeStamp) { + void implSend(MidiMessage message, long timeStamp) { if (recording) { long tickPos = 0;
--- a/src/share/classes/java/awt/Window.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/awt/Window.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2234,7 +2234,7 @@ WindowPeer peer = (WindowPeer)this.peer; synchronized(getTreeLock()) { if (peer != null) { - peer.setAlwaysOnTop(alwaysOnTop); + peer.updateAlwaysOnTopState(); } } }
--- a/src/share/classes/java/awt/peer/WindowPeer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/awt/peer/WindowPeer.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,15 +53,14 @@ void toBack(); /** - * Sets if the window should always stay on top of all other windows or - * not. + * Updates the window's always-on-top state. + * Sets if the window should always stay + * on top of all other windows or not. * - * @param alwaysOnTop if the window should always stay on top of all other - * windows or not - * + * @see Window#getAlwaysOnTop() * @see Window#setAlwaysOnTop(boolean) */ - void setAlwaysOnTop(boolean alwaysOnTop); + void updateAlwaysOnTopState(); /** * Updates the window's focusable state.
--- a/src/share/classes/java/beans/ThreadGroupContext.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/beans/ThreadGroupContext.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import com.sun.beans.finder.PropertyEditorFinder; import java.awt.GraphicsEnvironment; -import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; @@ -42,7 +41,7 @@ */ final class ThreadGroupContext { - private static final Map<ThreadGroup, ThreadGroupContext> contexts = new WeakHashMap<>(); + private static final WeakIdentityMap<ThreadGroupContext> contexts = new WeakIdentityMap<>(); /** * Returns the appropriate {@code AppContext} for the caller, @@ -69,6 +68,8 @@ private BeanInfoFinder beanInfoFinder; private PropertyEditorFinder propertyEditorFinder; + private ThreadGroupContext() { + } boolean isDesignTime() { return this.isDesignTime;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/beans/WeakIdentityMap.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.beans; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; + +/** + * Hash table based mapping, which uses weak references to store keys + * and reference-equality in place of object-equality to compare them. + * An entry will automatically be removed when its key is no longer + * in ordinary use. Both null values and the null key are supported. + * + * @see java.util.IdentityHashMap + * @see java.util.WeakHashMap + */ +final class WeakIdentityMap<T> { + + private static final int MAXIMUM_CAPACITY = 1 << 30; // it MUST be a power of two + private static final Object NULL = new Object(); // special object for null key + + private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); + + private Entry<T>[] table = newTable(1<<3); // table's length MUST be a power of two + private int threshold = 6; // the next size value at which to resize + private int size = 0; // the number of key-value mappings + + public T get(Object key) { + removeStaleEntries(); + if (key == null) { + key = NULL; + } + int hash = key.hashCode(); + int index = getIndex(this.table, hash); + for (Entry<T> entry = this.table[index]; entry != null; entry = entry.next) { + if (entry.isMatched(key, hash)) { + return entry.value; + } + } + return null; + } + + public T put(Object key, T value) { + removeStaleEntries(); + if (key == null) { + key = NULL; + } + int hash = key.hashCode(); + int index = getIndex(this.table, hash); + for (Entry<T> entry = this.table[index]; entry != null; entry = entry.next) { + if (entry.isMatched(key, hash)) { + T oldValue = entry.value; + entry.value = value; + return oldValue; + } + } + this.table[index] = new Entry<T>(key, hash, value, this.queue, this.table[index]); + if (++this.size >= this.threshold) { + if (this.table.length == MAXIMUM_CAPACITY) { + this.threshold = Integer.MAX_VALUE; + } + else { + removeStaleEntries(); + Entry<T>[] table = newTable(this.table.length * 2); + transfer(this.table, table); + + // If ignoring null elements and processing ref queue caused massive + // shrinkage, then restore old table. This should be rare, but avoids + // unbounded expansion of garbage-filled tables. + if (this.size >= this.threshold / 2) { + this.table = table; + this.threshold *= 2; + } + else { + transfer(table, this.table); + } + } + } + return null; + } + + private void removeStaleEntries() { + for (Object ref = this.queue.poll(); ref != null; ref = this.queue.poll()) { + @SuppressWarnings("unchecked") + Entry<T> entry = (Entry<T>) ref; + int index = getIndex(this.table, entry.hash); + + Entry<T> prev = this.table[index]; + Entry<T> current = prev; + while (current != null) { + Entry<T> next = current.next; + if (current == entry) { + if (prev == entry) { + this.table[index] = next; + } + else { + prev.next = next; + } + entry.value = null; // Help GC + entry.next = null; // Help GC + this.size--; + break; + } + prev = current; + current = next; + } + } + } + + private void transfer(Entry<T>[] oldTable, Entry<T>[] newTable) { + for (int i = 0; i < oldTable.length; i++) { + Entry<T> entry = oldTable[i]; + oldTable[i] = null; + while (entry != null) { + Entry<T> next = entry.next; + Object key = entry.get(); + if (key == null) { + entry.value = null; // Help GC + entry.next = null; // Help GC + this.size--; + } + else { + int index = getIndex(newTable, entry.hash); + entry.next = newTable[index]; + newTable[index] = entry; + } + entry = next; + } + } + } + + + @SuppressWarnings("unchecked") + private Entry<T>[] newTable(int length) { + return (Entry<T>[]) new Entry<?>[length]; + } + + private static int getIndex(Entry<?>[] table, int hash) { + return hash & (table.length - 1); + } + + private static class Entry<T> extends WeakReference<Object> { + private final int hash; + private T value; + private Entry<T> next; + + Entry(Object key, int hash, T value, ReferenceQueue<Object> queue, Entry<T> next) { + super(key, queue); + this.hash = hash; + this.value = value; + this.next = next; + } + + boolean isMatched(Object key, int hash) { + return (this.hash == hash) && (key == get()); + } + } +}
--- a/src/share/classes/java/io/ObjectInputStream.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/io/ObjectInputStream.java Wed Apr 17 02:53:02 2013 -0700 @@ -41,6 +41,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import static java.io.ObjectStreamClass.processQueue; +import sun.reflect.misc.ReflectUtil; /** * An ObjectInputStream deserializes primitive data and objects previously @@ -1519,6 +1520,12 @@ } } + private boolean isCustomSubclass() { + // Return true if this class is a custom subclass of ObjectInputStream + return getClass().getClassLoader() + != ObjectInputStream.class.getClassLoader(); + } + /** * Reads in and returns class descriptor for a dynamic proxy class. Sets * passHandle to proxy class descriptor's assigned handle. If proxy class @@ -1548,6 +1555,15 @@ try { if ((cl = resolveProxyClass(ifaces)) == null) { resolveEx = new ClassNotFoundException("null class"); + } else if (!Proxy.isProxyClass(cl)) { + throw new InvalidClassException("Not a proxy"); + } else { + // ReflectUtil.checkProxyPackageAccess makes a test + // equivalent to isCustomSubclass so there's no need + // to condition this call to isCustomSubclass == true here. + ReflectUtil.checkProxyPackageAccess( + getClass().getClassLoader(), + cl.getInterfaces()); } } catch (ClassNotFoundException ex) { resolveEx = ex; @@ -1589,9 +1605,12 @@ Class<?> cl = null; ClassNotFoundException resolveEx = null; bin.setBlockDataMode(true); + final boolean checksRequired = isCustomSubclass(); try { if ((cl = resolveClass(readDesc)) == null) { resolveEx = new ClassNotFoundException("null class"); + } else if (checksRequired) { + ReflectUtil.checkPackageAccess(cl); } } catch (ClassNotFoundException ex) { resolveEx = ex;
--- a/src/share/classes/java/lang/Class.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/Class.java Wed Apr 17 02:53:02 2013 -0700 @@ -53,6 +53,7 @@ import java.util.HashMap; import java.util.Objects; import sun.misc.Unsafe; +import sun.reflect.CallerSensitive; import sun.reflect.ConstantPool; import sun.reflect.Reflection; import sun.reflect.ReflectionFactory; @@ -250,9 +251,11 @@ * by this method fails * @exception ClassNotFoundException if the class cannot be located */ + @CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { - return forName0(className, true, ClassLoader.getCallerClassLoader()); + return forName0(className, true, + ClassLoader.getClassLoader(Reflection.getCallerClass())); } @@ -317,6 +320,7 @@ * @see java.lang.ClassLoader * @since 1.2 */ + @CallerSensitive public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException @@ -324,7 +328,7 @@ if (sun.misc.VM.isSystemDomainLoader(loader)) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = ClassLoader.getCallerClassLoader(); + ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass()); if (!sun.misc.VM.isSystemDomainLoader(ccl)) { sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); @@ -386,18 +390,14 @@ * </ul> * */ + @CallerSensitive public T newInstance() throws InstantiationException, IllegalAccessException { if (System.getSecurityManager() != null) { - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); } - return newInstance0(); - } - private T newInstance0() - throws InstantiationException, IllegalAccessException - { // NOTE: the following code may not be strictly correct under // the current Java memory model. @@ -432,7 +432,7 @@ // Security check (same as in java.lang.reflect.Constructor) int modifiers = tmpConstructor.getModifiers(); if (!Reflection.quickCheckMemberAccess(this, modifiers)) { - Class<?> caller = Reflection.getCallerClass(3); + Class<?> caller = Reflection.getCallerClass(); if (newInstanceCallerCache != caller) { Reflection.ensureMemberAccess(caller, this, null, modifiers); newInstanceCallerCache = caller; @@ -674,16 +674,14 @@ * @see SecurityManager#checkPermission * @see java.lang.RuntimePermission */ + @CallerSensitive public ClassLoader getClassLoader() { ClassLoader cl = getClassLoader0(); if (cl == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = ClassLoader.getCallerClassLoader(); - if (ClassLoader.needsClassLoaderPermissionCheck(ccl, cl)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass()); } return cl; } @@ -1392,11 +1390,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Class<?>[] getClasses() { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); // Privileged so this implementation can look at DECLARED classes, // something the caller might not have privilege to do. The code here @@ -1467,11 +1463,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Field[] getFields() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return copyFields(privateGetPublicFields(null)); } @@ -1518,11 +1512,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Method[] getMethods() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return copyMethods(privateGetPublicMethods()); } @@ -1567,11 +1559,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Constructor<?>[] getConstructors() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return copyConstructors(privateGetDeclaredConstructors(true)); } @@ -1625,12 +1615,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Field getField(String name) throws NoSuchFieldException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); Field field = getField0(name); if (field == null) { throw new NoSuchFieldException(name); @@ -1710,12 +1698,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); Method method = getMethod0(name, parameterTypes); if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); @@ -1764,12 +1750,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return getConstructor0(parameterTypes, Member.PUBLIC); } @@ -1807,11 +1791,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Class<?>[] getDeclaredClasses() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), false); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false); return getDeclaredClasses0(); } @@ -1851,11 +1833,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Field[] getDeclaredFields() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyFields(privateGetDeclaredFields(false)); } @@ -1899,11 +1879,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Method[] getDeclaredMethods() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyMethods(privateGetDeclaredMethods(false)); } @@ -1944,11 +1922,9 @@ * * @since JDK1.1 */ + @CallerSensitive public Constructor<?>[] getDeclaredConstructors() throws SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyConstructors(privateGetDeclaredConstructors(false)); } @@ -1987,12 +1963,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); Field field = searchFields(privateGetDeclaredFields(false), name); if (field == null) { throw new NoSuchFieldException(name); @@ -2042,12 +2016,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes); if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); @@ -2092,12 +2064,10 @@ * * @since JDK1.1 */ + @CallerSensitive public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { - // be very careful not to change the stack depth of this - // checkMemberAccess call for security reasons - // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); + checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return getConstructor0(parameterTypes, Member.DECLARED); } @@ -2255,23 +2225,40 @@ */ static native Class<?> getPrimitiveClass(String name); + private static boolean isCheckMemberAccessOverridden(SecurityManager smgr) { + if (smgr.getClass() == SecurityManager.class) return false; + + Class<?>[] paramTypes = new Class<?>[] {Class.class, int.class}; + return smgr.getClass().getMethod0("checkMemberAccess", paramTypes). + getDeclaringClass() != SecurityManager.class; + } /* * Check if client is allowed to access members. If access is denied, * throw a SecurityException. * - * Be very careful not to change the stack depth of this checkMemberAccess - * call for security reasons. - * See java.lang.SecurityManager.checkMemberAccess. - * * <p> Default policy: allow all clients access with normal Java access * control. */ - private void checkMemberAccess(int which, ClassLoader ccl, boolean checkProxyInterfaces) { - SecurityManager s = System.getSecurityManager(); + private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) { + final SecurityManager s = System.getSecurityManager(); if (s != null) { - s.checkMemberAccess(this, which); - ClassLoader cl = getClassLoader0(); + final ClassLoader ccl = ClassLoader.getClassLoader(caller); + final ClassLoader cl = getClassLoader0(); + if (!isCheckMemberAccessOverridden(s)) { + // Inlined SecurityManager.checkMemberAccess + if (which != Member.PUBLIC) { + if (ccl != cl) { + s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); + } + } + } else { + // Don't refactor; otherwise break the stack depth for + // checkMemberAccess of subclasses of SecurityManager as specified. + s.checkMemberAccess(this, which); + } + + if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) { String name = this.getName(); int i = name.lastIndexOf('.');
--- a/src/share/classes/java/lang/ClassLoader.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/ClassLoader.java Wed Apr 17 02:53:02 2013 -0700 @@ -55,6 +55,7 @@ import sun.misc.Resource; import sun.misc.URLClassPath; import sun.misc.VM; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; @@ -1159,11 +1160,6 @@ return java.util.Collections.emptyEnumeration(); } - // index 0: java.lang.ClassLoader.class - // index 1: the immediate caller of index 0. - // index 2: the immediate caller of index 1. - private static native Class<? extends ClassLoader> getCaller(int index); - /** * Registers the caller as parallel capable.</p> * The registration succeeds if and only if all of the following @@ -1179,8 +1175,11 @@ * * @since 1.7 */ + @CallerSensitive protected static boolean registerAsParallelCapable() { - return ParallelLoaders.register(getCaller(1)); + Class<? extends ClassLoader> callerClass = + Reflection.getCallerClass().asSubclass(ClassLoader.class); + return ParallelLoaders.register(callerClass); } /** @@ -1340,15 +1339,13 @@ * * @since 1.2 */ + @CallerSensitive public final ClassLoader getParent() { if (parent == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = getCallerClassLoader(); - if (needsClassLoaderPermissionCheck(ccl, this)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + checkClassLoaderPermission(this, Reflection.getCallerClass()); } return parent; } @@ -1408,6 +1405,7 @@ * * @revised 1.4 */ + @CallerSensitive public static ClassLoader getSystemClassLoader() { initSystemClassLoader(); if (scl == null) { @@ -1415,10 +1413,7 @@ } SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = getCallerClassLoader(); - if (needsClassLoaderPermissionCheck(ccl, scl)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; } @@ -1471,8 +1466,8 @@ // class loader 'from' is same as class loader 'to' or an ancestor // of 'to'. The class loader in a system domain can access // any class loader. - static boolean needsClassLoaderPermissionCheck(ClassLoader from, - ClassLoader to) + private static boolean needsClassLoaderPermissionCheck(ClassLoader from, + ClassLoader to) { if (from == to) return false; @@ -1483,13 +1478,8 @@ return !to.isAncestor(from); } - // Returns the invoker's class loader, or null if none. - // NOTE: This must always be invoked when there is exactly one intervening - // frame from the core libraries on the stack between this method's - // invocation and the desired invoker. - static ClassLoader getCallerClassLoader() { - // NOTE use of more generic Reflection.getCallerClass() - Class<?> caller = Reflection.getCallerClass(3); + // Returns the class's class loader, or null if none. + static ClassLoader getClassLoader(Class<?> caller) { // This can be null if the VM is requesting it if (caller == null) { return null; @@ -1498,6 +1488,17 @@ return caller.getClassLoader0(); } + static void checkClassLoaderPermission(ClassLoader cl, Class<?> caller) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // caller can be null if the VM is requesting it + ClassLoader ccl = getClassLoader(caller); + if (needsClassLoaderPermissionCheck(ccl, cl)) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + } + // The class loader for the system // @GuardedBy("ClassLoader.class") private static ClassLoader scl;
--- a/src/share/classes/java/lang/Package.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/Package.java Wed Apr 17 02:53:02 2013 -0700 @@ -49,6 +49,8 @@ import java.util.Iterator; import sun.net.www.ParseUtil; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; import java.lang.annotation.Annotation; @@ -273,8 +275,9 @@ * @return the package of the requested name. It may be null if no package * information is available from the archive or codebase. */ + @CallerSensitive public static Package getPackage(String name) { - ClassLoader l = ClassLoader.getCallerClassLoader(); + ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); if (l != null) { return l.getPackage(name); } else { @@ -294,8 +297,9 @@ * @return a new array of packages known to the callers {@code ClassLoader} * instance. An zero length array is returned if none are known. */ + @CallerSensitive public static Package[] getPackages() { - ClassLoader l = ClassLoader.getCallerClassLoader(); + ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); if (l != null) { return l.getPackages(); } else {
--- a/src/share/classes/java/lang/ProcessBuilder.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/ProcessBuilder.java Wed Apr 17 02:53:02 2013 -0700 @@ -30,6 +30,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.FileOutputStream; +import java.security.AccessControlException; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @@ -1024,13 +1025,24 @@ redirects, redirectErrorStream); } catch (IOException e) { + String exceptionInfo = ": " + e.getMessage(); + Throwable cause = e; + if (security != null) { + // Can not disclose the fail reason for read-protected files. + try { + security.checkRead(prog); + } catch (AccessControlException ace) { + exceptionInfo = ""; + cause = ace; + } + } // It's much easier for us to create a high-quality error // message than the low-level C code which found the problem. throw new IOException( "Cannot run program \"" + prog + "\"" + (dir == null ? "" : " (in directory \"" + dir + "\")") - + ": " + e.getMessage(), - e); + + exceptionInfo, + cause); } } }
--- a/src/share/classes/java/lang/Runtime.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/Runtime.java Wed Apr 17 02:53:02 2013 -0700 @@ -27,6 +27,8 @@ import java.io.*; import java.util.StringTokenizer; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; /** * Every Java application has a single instance of class @@ -790,8 +792,9 @@ * @see java.lang.SecurityException * @see java.lang.SecurityManager#checkLink(java.lang.String) */ + @CallerSensitive public void load(String filename) { - load0(System.getCallerClass(), filename); + load0(Reflection.getCallerClass(), filename); } synchronized void load0(Class<?> fromClass, String filename) { @@ -850,8 +853,9 @@ * @see java.lang.SecurityException * @see java.lang.SecurityManager#checkLink(java.lang.String) */ + @CallerSensitive public void loadLibrary(String libname) { - loadLibrary0(System.getCallerClass(), libname); + loadLibrary0(Reflection.getCallerClass(), libname); } synchronized void loadLibrary0(Class<?> fromClass, String libname) {
--- a/src/share/classes/java/lang/SecurityManager.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/SecurityManager.java Wed Apr 17 02:53:02 2013 -0700 @@ -36,10 +36,10 @@ import java.net.NetPermission; import java.util.Hashtable; import java.net.InetAddress; -import java.lang.reflect.Member; import java.lang.reflect.*; import java.net.URL; +import sun.reflect.CallerSensitive; import sun.security.util.SecurityConstants; /** @@ -1679,6 +1679,7 @@ * @since JDK1.1 * @see #checkPermission(java.security.Permission) checkPermission */ + @CallerSensitive public void checkMemberAccess(Class<?> clazz, int which) { if (clazz == null) { throw new NullPointerException("class can't be null");
--- a/src/share/classes/java/lang/System.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/System.java Wed Apr 17 02:53:02 2013 -0700 @@ -35,6 +35,7 @@ import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; import sun.nio.ch.Interruptible; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; import sun.reflect.annotation.AnnotationType; @@ -1072,8 +1073,9 @@ * @see java.lang.Runtime#load(java.lang.String) * @see java.lang.SecurityManager#checkLink(java.lang.String) */ + @CallerSensitive public static void load(String filename) { - Runtime.getRuntime().load0(getCallerClass(), filename); + Runtime.getRuntime().load0(Reflection.getCallerClass(), filename); } /** @@ -1107,8 +1109,9 @@ * @see java.lang.Runtime#loadLibrary(java.lang.String) * @see java.lang.SecurityManager#checkLink(java.lang.String) */ + @CallerSensitive public static void loadLibrary(String libname) { - Runtime.getRuntime().loadLibrary0(getCallerClass(), libname); + Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname); } /** @@ -1245,10 +1248,4 @@ } }); } - - /* returns the class of the caller. */ - static Class<?> getCallerClass() { - // NOTE use of more generic Reflection.getCallerClass() - return Reflection.getCallerClass(3); - } }
--- a/src/share/classes/java/lang/Thread.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/Thread.java Wed Apr 17 02:53:02 2013 -0700 @@ -37,6 +37,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.LockSupport; import sun.nio.ch.Interruptible; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; import sun.security.util.SecurityConstants; @@ -1443,15 +1445,14 @@ * * @since 1.2 */ + @CallerSensitive public ClassLoader getContextClassLoader() { if (contextClassLoader == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader ccl = ClassLoader.getCallerClassLoader(); - if (ClassLoader.needsClassLoaderPermissionCheck(ccl, contextClassLoader)) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } + ClassLoader.checkClassLoaderPermission(contextClassLoader, + Reflection.getCallerClass()); } return contextClassLoader; }
--- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java Wed Apr 17 02:53:02 2013 -0700 @@ -709,7 +709,9 @@ InvokerBytecodeGenerator.maybeDump(className, classFile); Class<? extends BoundMethodHandle> bmhClass = //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class); - UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class); + UNSAFE.defineClass(className, classFile, 0, classFile.length, + BoundMethodHandle.class.getClassLoader(), null) + .asSubclass(BoundMethodHandle.class); UNSAFE.ensureClassInitialized(bmhClass); return bmhClass;
--- a/src/share/classes/java/lang/invoke/MemberName.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MemberName.java Wed Apr 17 02:53:02 2013 -0700 @@ -391,10 +391,11 @@ // private flags, not part of RECOGNIZED_MODIFIERS: static final int - IS_METHOD = MN_IS_METHOD, // method (not constructor) - IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor - IS_FIELD = MN_IS_FIELD, // field - IS_TYPE = MN_IS_TYPE; // nested type + IS_METHOD = MN_IS_METHOD, // method (not constructor) + IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor + IS_FIELD = MN_IS_FIELD, // field + IS_TYPE = MN_IS_TYPE, // nested type + CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE; @@ -430,6 +431,10 @@ public boolean isPackage() { return !testAnyFlags(ALL_ACCESS); } + /** Query whether this member has a CallerSensitive annotation. */ + public boolean isCallerSensitive() { + return testAllFlags(CALLER_SENSITIVE); + } /** Utility method to query whether this member is accessible from a given lookup class. */ public boolean isAccessibleFrom(Class<?> lookupClass) {
--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -34,6 +34,8 @@ import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyType; import sun.invoke.util.Wrapper; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; @@ -891,9 +893,11 @@ } } + @CallerSensitive private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) { - final int FRAME_COUNT_ARG = 2; // [0] Reflection [1] BindCaller [2] Expected - Class<?> actual = sun.reflect.Reflection.getCallerClass(FRAME_COUNT_ARG); + // This method is called via MH_checkCallerClass and so it's + // correct to ask for the immediate caller here. + Class<?> actual = Reflection.getCallerClass(); if (actual != expected && actual != expected2) throw new InternalError("found "+actual.getName()+", expected "+expected.getName() +(expected == expected2 ? "" : ", or else "+expected2.getName()));
--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java Wed Apr 17 02:53:02 2013 -0700 @@ -26,7 +26,6 @@ package java.lang.invoke; import java.lang.invoke.MethodHandles.Lookup; -import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; @@ -34,7 +33,7 @@ /** * The JVM interface for the method handles package is all here. - * This is an interface internal and private to an implemetantion of JSR 292. + * This is an interface internal and private to an implementation of JSR 292. * <em>This class is not part of the JSR 292 standard.</em> * @author jrose */ @@ -101,6 +100,7 @@ MN_IS_CONSTRUCTOR = 0x00020000, // constructor MN_IS_FIELD = 0x00040000, // field MN_IS_TYPE = 0x00080000, // nested type + MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected MN_REFERENCE_KIND_SHIFT = 24, // refKind MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT, // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers: @@ -391,129 +391,24 @@ * I.e., does it call Reflection.getCallerClass or a similer method * to ask about the identity of its caller? */ - // FIXME: Replace this pattern match by an annotation @sun.reflect.CallerSensitive. static boolean isCallerSensitive(MemberName mem) { if (!mem.isInvocable()) return false; // fields are not caller sensitive + + return mem.isCallerSensitive() || canBeCalledVirtual(mem); + } + + static boolean canBeCalledVirtual(MemberName mem) { + assert(mem.isInvocable()); Class<?> defc = mem.getDeclaringClass(); switch (mem.getName()) { - case "doPrivileged": - case "doPrivilegedWithCombiner": - return defc == java.security.AccessController.class; case "checkMemberAccess": return canBeCalledVirtual(mem, java.lang.SecurityManager.class); - case "getUnsafe": - return defc == sun.misc.Unsafe.class; - case "lookup": - return defc == java.lang.invoke.MethodHandles.class; - case "findStatic": - case "findVirtual": - case "findConstructor": - case "findSpecial": - case "findGetter": - case "findSetter": - case "findStaticGetter": - case "findStaticSetter": - case "bind": - case "unreflect": - case "unreflectSpecial": - case "unreflectConstructor": - case "unreflectGetter": - case "unreflectSetter": - return defc == java.lang.invoke.MethodHandles.Lookup.class; - case "invoke": - return defc == java.lang.reflect.Method.class; - case "get": - case "getBoolean": - case "getByte": - case "getChar": - case "getShort": - case "getInt": - case "getLong": - case "getFloat": - case "getDouble": - case "set": - case "setBoolean": - case "setByte": - case "setChar": - case "setShort": - case "setInt": - case "setLong": - case "setFloat": - case "setDouble": - return defc == java.lang.reflect.Field.class; - case "newInstance": - if (defc == java.lang.reflect.Constructor.class) return true; - if (defc == java.lang.Class.class) return true; - break; - case "forName": - case "getClassLoader": - case "getClasses": - case "getFields": - case "getMethods": - case "getConstructors": - case "getDeclaredClasses": - case "getDeclaredFields": - case "getDeclaredMethods": - case "getDeclaredConstructors": - case "getField": - case "getMethod": - case "getConstructor": - case "getDeclaredField": - case "getDeclaredMethod": - case "getDeclaredConstructor": - return defc == java.lang.Class.class; - case "getConnection": - case "getDriver": - case "getDrivers": - case "deregisterDriver": - return defc == getClass("java.sql.DriverManager"); - case "newUpdater": - if (defc == java.util.concurrent.atomic.AtomicIntegerFieldUpdater.class) return true; - if (defc == java.util.concurrent.atomic.AtomicLongFieldUpdater.class) return true; - if (defc == java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class) return true; - break; case "getContextClassLoader": return canBeCalledVirtual(mem, java.lang.Thread.class); - case "getPackage": - case "getPackages": - return defc == java.lang.Package.class; - case "getParent": - case "getSystemClassLoader": - return defc == java.lang.ClassLoader.class; - case "load": - case "loadLibrary": - if (defc == java.lang.Runtime.class) return true; - if (defc == java.lang.System.class) return true; - break; - case "getCallerClass": - if (defc == sun.reflect.Reflection.class) return true; - if (defc == java.lang.System.class) return true; - break; - case "getCallerClassLoader": - return defc == java.lang.ClassLoader.class; - case "registerAsParallelCapable": - return canBeCalledVirtual(mem, java.lang.ClassLoader.class); - case "getProxyClass": - case "newProxyInstance": - return defc == java.lang.reflect.Proxy.class; - case "asInterfaceInstance": - return defc == java.lang.invoke.MethodHandleProxies.class; - case "getBundle": - case "clearCache": - return defc == java.util.ResourceBundle.class; } return false; } - // avoid static dependency to a class in other modules - private static Class<?> getClass(String cn) { - try { - return Class.forName(cn, false, - MethodHandleNatives.class.getClassLoader()); - } catch (ClassNotFoundException e) { - throw new InternalError(e); - } - } static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) { Class<?> symbolicRefClass = symbolicRef.getDeclaringClass(); if (symbolicRefClass == definingClass) return true;
--- a/src/share/classes/java/lang/invoke/MethodHandleProxies.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandleProxies.java Wed Apr 17 02:53:02 2013 -0700 @@ -30,6 +30,7 @@ import java.security.PrivilegedAction; import sun.invoke.WrapperInstance; import java.util.ArrayList; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; @@ -137,14 +138,14 @@ // entry points, must be covered by hand-written or automatically // generated adapter classes. // + @CallerSensitive public static <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) { if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) throw new IllegalArgumentException("not a public interface: "+intfc.getName()); final MethodHandle mh; if (System.getSecurityManager() != null) { - final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller - final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME); + final Class<?> caller = Reflection.getCallerClass(); final ClassLoader ccl = caller != null ? caller.getClassLoader() : null; ReflectUtil.checkProxyPackageAccess(ccl, intfc); mh = ccl != null ? bindCaller(target, caller) : target;
--- a/src/share/classes/java/lang/invoke/MethodHandles.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/invoke/MethodHandles.java Wed Apr 17 02:53:02 2013 -0700 @@ -26,13 +26,17 @@ package java.lang.invoke; import java.lang.reflect.*; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyAccess; import sun.invoke.util.Wrapper; -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; +import sun.security.util.SecurityConstants; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; @@ -65,8 +69,9 @@ * This lookup object is a <em>capability</em> which may be delegated to trusted agents. * Do not store it in place where untrusted code can access it. */ + @CallerSensitive public static Lookup lookup() { - return new Lookup(); + return new Lookup(Reflection.getCallerClass()); } /** @@ -416,20 +421,13 @@ * for method handle creation. * Must be called by from a method in this package, * which in turn is called by a method not in this package. - * <p> - * Also, don't make it private, lest javac interpose - * an access$N method. */ - Lookup() { - this(getCallerClassAtEntryPoint(false), ALL_MODES); + Lookup(Class<?> lookupClass) { + this(lookupClass, ALL_MODES); // make sure we haven't accidentally picked up a privileged class: checkUnprivilegedlookupClass(lookupClass); } - Lookup(Class<?> lookupClass) { - this(lookupClass, ALL_MODES); - } - private Lookup(Class<?> lookupClass, int allowedModes) { this.lookupClass = lookupClass; this.allowedModes = allowedModes; @@ -554,20 +552,6 @@ } } - /* Obtain the external caller class, when called from Lookup.<init> or a first-level subroutine. */ - private static Class<?> getCallerClassAtEntryPoint(boolean inSubroutine) { - final int CALLER_DEPTH = 4; - // Stack for the constructor entry point (inSubroutine=false): - // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint, - // 2: Lookup.<init>, 3: MethodHandles.*, 4: caller - // The stack is slightly different for a subroutine of a Lookup.find* method: - // 2: Lookup.*, 3: Lookup.find*.*, 4: caller - // Note: This should be the only use of getCallerClass in this file. - assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class); - assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class)); - return Reflection.getCallerClass(CALLER_DEPTH); - } - /** * Produces a method handle for a static method. * The type of the method handle will be that of the method. @@ -594,12 +578,14 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor - return getDirectMethod(REF_invokeStatic, refc, method, callerClass); + Class<?> callerClass = Reflection.getCallerClass(); + checkSecurityManager(refc, method, callerClass); + return getDirectMethod(REF_invokeStatic, refc, method, + findBoundCallerClass(method, callerClass)); } /** @@ -645,6 +631,7 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { if (refc == MethodHandle.class) { MethodHandle mh = findVirtualForMH(name, type); @@ -652,9 +639,10 @@ } byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual); MemberName method = resolveOrFail(refKind, refc, name, type); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - Class<?> callerClass = findBoundCallerClass(method); - return getDirectMethod(refKind, refc, method, callerClass); + Class<?> callerClass = Reflection.getCallerClass(); + checkSecurityManager(refc, method, callerClass); + return getDirectMethod(refKind, refc, method, + findBoundCallerClass(method, callerClass)); } private MethodHandle findVirtualForMH(String name, MethodType type) { // these names require special lookups because of the implicit MethodType argument @@ -691,10 +679,11 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { String name = "<init>"; MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type); - checkSecurityManager(refc, ctor); // stack walk magic: do not refactor + checkSecurityManager(refc, ctor, Reflection.getCallerClass()); return getDirectConstructor(refc, ctor); } @@ -732,14 +721,16 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException { checkSpecialCaller(specialCaller); Lookup specialLookup = this.in(specialCaller); MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - Class<?> callerClass = findBoundCallerClass(method); - return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass); + Class<?> callerClass = Reflection.getCallerClass(); + checkSecurityManager(refc, method, callerClass); + return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, + findBoundCallerClass(method, callerClass)); } /** @@ -759,9 +750,10 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_getField, refc, name, type); - checkSecurityManager(refc, field); // stack walk magic: do not refactor + checkSecurityManager(refc, field, Reflection.getCallerClass()); return getDirectField(REF_getField, refc, field); } @@ -782,9 +774,10 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_putField, refc, name, type); - checkSecurityManager(refc, field); // stack walk magic: do not refactor + checkSecurityManager(refc, field, Reflection.getCallerClass()); return getDirectField(REF_putField, refc, field); } @@ -804,9 +797,10 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_getStatic, refc, name, type); - checkSecurityManager(refc, field); // stack walk magic: do not refactor + checkSecurityManager(refc, field, Reflection.getCallerClass()); return getDirectField(REF_getStatic, refc, field); } @@ -826,9 +820,10 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_putStatic, refc, name, type); - checkSecurityManager(refc, field); // stack walk magic: do not refactor + checkSecurityManager(refc, field, Reflection.getCallerClass()); return getDirectField(REF_putStatic, refc, field); } @@ -878,12 +873,14 @@ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { Class<? extends Object> refc = receiver.getClass(); // may get NPE MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type); - checkSecurityManager(refc, method); // stack walk magic: do not refactor - Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor - MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass); + Class<?> callerClass = Reflection.getCallerClass(); + checkSecurityManager(refc, method, callerClass); + MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, + findBoundCallerClass(method, callerClass)); return mh.bindReceiver(receiver).setVarargs(method); } @@ -908,13 +905,14 @@ * is set and {@code asVarargsCollector} fails * @throws NullPointerException if the argument is null */ + @CallerSensitive public MethodHandle unreflect(Method m) throws IllegalAccessException { MemberName method = new MemberName(m); byte refKind = method.getReferenceKind(); if (refKind == REF_invokeSpecial) refKind = REF_invokeVirtual; assert(method.isMethod()); - Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass()); Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass); } @@ -940,12 +938,13 @@ * is set and {@code asVarargsCollector} fails * @throws NullPointerException if any argument is null */ + @CallerSensitive public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException { checkSpecialCaller(specialCaller); Lookup specialLookup = this.in(specialCaller); MemberName method = new MemberName(m, true); assert(method.isMethod()); - Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass()); // ignore m.isAccessible: this is a new kind of access return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass); } @@ -1050,20 +1049,35 @@ * If this lookup object has private access, then the caller class is the lookupClass. * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual). * This is the same caller class as is used by checkSecurityManager. - * This function performs stack walk magic: do not refactor it. */ - Class<?> findBoundCallerClass(MemberName m) { + Class<?> findBoundCallerClass(MemberName m, Class<?> callerAtEntryPoint) { Class<?> callerClass = null; if (MethodHandleNatives.isCallerSensitive(m)) { // Do not refactor this to a more "logical" place, since it is stack walk magic. // Note that this is the same expression as in Step 2 below in checkSecurityManager. callerClass = ((allowedModes & PRIVATE) != 0 ? lookupClass // for strong access modes, no extra check - // next line does stack walk magic; do not refactor: - : getCallerClassAtEntryPoint(true)); + : callerAtEntryPoint); } return callerClass; } + + /** + * Determine whether a security manager has an overridden + * SecurityManager.checkMemberAccess method. + */ + private boolean isCheckMemberAccessOverridden(SecurityManager sm) { + final Class<? extends SecurityManager> cls = sm.getClass(); + if (cls == SecurityManager.class) return false; + + try { + return cls.getMethod("checkMemberAccess", Class.class, int.class). + getDeclaringClass() != SecurityManager.class; + } catch (NoSuchMethodException e) { + throw new InternalError("should not reach here"); + } + } + /** * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>. * Determines a trustable caller class to compare with refc, the symbolic reference class. @@ -1071,46 +1085,55 @@ * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual). * This function performs stack walk magic: do not refactor it. */ - void checkSecurityManager(Class<?> refc, MemberName m) { + void checkSecurityManager(Class<?> refc, MemberName m, Class<?> caller) { SecurityManager smgr = System.getSecurityManager(); if (smgr == null) return; if (allowedModes == TRUSTED) return; + + final boolean overridden = isCheckMemberAccessOverridden(smgr); // Step 1: - smgr.checkMemberAccess(refc, Member.PUBLIC); + { + // Default policy is to allow Member.PUBLIC; no need to check + // permission if SecurityManager is the default implementation + final int which = Member.PUBLIC; + final Class<?> clazz = refc; + if (overridden) { + // Don't refactor; otherwise break the stack depth for + // checkMemberAccess of subclasses of SecurityManager as specified. + smgr.checkMemberAccess(clazz, which); + } + } + // Step 2: Class<?> callerClass = ((allowedModes & PRIVATE) != 0 ? lookupClass // for strong access modes, no extra check - // next line does stack walk magic; do not refactor: - : getCallerClassAtEntryPoint(true)); + : caller); if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) || (callerClass != lookupClass && !VerifyAccess.classLoaderIsAncestor(callerClass, refc))) smgr.checkPackageAccess(VerifyAccess.getPackageName(refc)); + // Step 3: if (m.isPublic()) return; Class<?> defc = m.getDeclaringClass(); - smgr.checkMemberAccess(defc, Member.DECLARED); // STACK WALK HERE + { + // Inline SecurityManager.checkMemberAccess + final int which = Member.DECLARED; + final Class<?> clazz = defc; + if (!overridden) { + if (caller.getClassLoader() != clazz.getClassLoader()) { + smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); + } + } else { + // Don't refactor; otherwise break the stack depth for + // checkMemberAccess of subclasses of SecurityManager as specified. + smgr.checkMemberAccess(clazz, which); + } + } + // Step 4: if (defc != refc) smgr.checkPackageAccess(VerifyAccess.getPackageName(defc)); - - // Comment from SM.checkMemberAccess, where which=DECLARED: - /* - * stack depth of 4 should be the caller of one of the - * methods in java.lang.Class that invoke checkMember - * access. The stack should look like: - * - * someCaller [3] - * java.lang.Class.someReflectionAPI [2] - * java.lang.Class.checkMemberAccess [1] - * SecurityManager.checkMemberAccess [0] - * - */ - // For us it is this stack: - // someCaller [3] - // Lookup.findSomeMember [2] - // Lookup.checkSecurityManager [1] - // SecurityManager.checkMemberAccess [0] } void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException { @@ -1237,6 +1260,30 @@ checkMethod(refKind, refc, method); if (method.isMethodHandleInvoke()) return fakeMethodHandleInvoke(method); + + Class<?> refcAsSuper; + if (refKind == REF_invokeSpecial && + refc != lookupClass() && + refc != (refcAsSuper = lookupClass().getSuperclass()) && + refc.isAssignableFrom(lookupClass())) { + assert(!method.getName().equals("<init>")); // not this code path + // Per JVMS 6.5, desc. of invokespecial instruction: + // If the method is in a superclass of the LC, + // and if our original search was above LC.super, + // repeat the search (symbolic lookup) from LC.super. + // FIXME: MemberName.resolve should handle this instead. + MemberName m2 = new MemberName(refcAsSuper, + method.getName(), + method.getMethodType(), + REF_invokeSpecial); + m2 = IMPL_NAMES.resolveOrNull(refKind, m2, lookupClassOrNull()); + if (m2 == null) throw new InternalError(method.toString()); + method = m2; + refc = refcAsSuper; + // redo basic checks + checkMethod(refKind, refc, method); + } + MethodHandle mh = DirectMethodHandle.make(refKind, refc, method); mh = maybeBindCaller(method, mh, callerClass); mh = mh.setVarargs(method);
--- a/src/share/classes/java/lang/ref/Finalizer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/ref/Finalizer.java Wed Apr 17 02:53:02 2013 -0700 @@ -38,9 +38,9 @@ */ static native void invokeFinalizeMethod(Object o) throws Throwable; - static private ReferenceQueue queue = new ReferenceQueue(); - static private Finalizer unfinalized = null; - static private Object lock = new Object(); + private static ReferenceQueue queue = new ReferenceQueue(); + private static Finalizer unfinalized = null; + private static final Object lock = new Object(); private Finalizer next = null, @@ -142,7 +142,11 @@ /* Called by Runtime.runFinalization() */ static void runFinalization() { forkSecondaryFinalizer(new Runnable() { + private volatile boolean running; public void run() { + if (running) + return; + running = true; for (;;) { Finalizer f = (Finalizer)queue.poll(); if (f == null) break; @@ -155,7 +159,11 @@ /* Invoked by java.lang.Shutdown */ static void runAllFinalizers() { forkSecondaryFinalizer(new Runnable() { + private volatile boolean running; public void run() { + if (running) + return; + running = true; for (;;) { Finalizer f; synchronized (lock) { @@ -168,10 +176,14 @@ } private static class FinalizerThread extends Thread { + private volatile boolean running; FinalizerThread(ThreadGroup g) { super(g, "Finalizer"); } public void run() { + if (running) + return; + running = true; for (;;) { try { Finalizer f = (Finalizer)queue.remove();
--- a/src/share/classes/java/lang/reflect/Constructor.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/reflect/Constructor.java Wed Apr 17 02:53:02 2013 -0700 @@ -25,6 +25,7 @@ package java.lang.reflect; +import sun.reflect.CallerSensitive; import sun.reflect.ConstructorAccessor; import sun.reflect.Reflection; import sun.reflect.generics.repository.ConstructorRepository; @@ -392,14 +393,14 @@ * @exception ExceptionInInitializerError if the initialization provoked * by this method fails. */ + @CallerSensitive public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class<?> caller = Reflection.getCallerClass(2); - + Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, null, modifiers); } }
--- a/src/share/classes/java/lang/reflect/Field.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/reflect/Field.java Wed Apr 17 02:53:02 2013 -0700 @@ -25,6 +25,7 @@ package java.lang.reflect; +import sun.reflect.CallerSensitive; import sun.reflect.FieldAccessor; import sun.reflect.Reflection; import sun.reflect.generics.repository.FieldRepository; @@ -376,9 +377,16 @@ * @exception ExceptionInInitializerError if the initialization provoked * by this method fails. */ + @CallerSensitive public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).get(obj); } @@ -404,9 +412,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public boolean getBoolean(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getBoolean(obj); } @@ -432,9 +447,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public byte getByte(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getByte(obj); } @@ -462,9 +484,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public char getChar(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getChar(obj); } @@ -492,9 +521,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public short getShort(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getShort(obj); } @@ -522,9 +558,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public int getInt(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getInt(obj); } @@ -552,9 +595,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public long getLong(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getLong(obj); } @@ -582,9 +632,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public float getFloat(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getFloat(obj); } @@ -612,9 +669,16 @@ * by this method fails. * @see Field#get */ + @CallerSensitive public double getDouble(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } return getFieldAccessor(obj).getDouble(obj); } @@ -684,9 +748,16 @@ * @exception ExceptionInInitializerError if the initialization provoked * by this method fails. */ + @CallerSensitive public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).set(obj, value); } @@ -714,9 +785,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setBoolean(Object obj, boolean z) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setBoolean(obj, z); } @@ -744,9 +822,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setByte(Object obj, byte b) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setByte(obj, b); } @@ -774,9 +859,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setChar(Object obj, char c) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setChar(obj, c); } @@ -804,9 +896,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setShort(Object obj, short s) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setShort(obj, s); } @@ -834,9 +933,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setInt(Object obj, int i) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setInt(obj, i); } @@ -864,9 +970,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setLong(Object obj, long l) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setLong(obj, l); } @@ -894,9 +1007,16 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setFloat(Object obj, float f) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setFloat(obj, f); } @@ -924,20 +1044,26 @@ * by this method fails. * @see Field#set */ + @CallerSensitive public void setDouble(Object obj, double d) throws IllegalArgumentException, IllegalAccessException { + if (!override) { + if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { + Class<?> caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); + } + } getFieldAccessor(obj).setDouble(obj, d); } - // Convenience routine which performs security checks + // security check is done before calling this method private FieldAccessor getFieldAccessor(Object obj) throws IllegalAccessException { - doSecurityCheck(obj); boolean ov = override; - FieldAccessor a = (ov)? overrideFieldAccessor : fieldAccessor; - return (a != null)? a : acquireFieldAccessor(ov); + FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor; + return (a != null) ? a : acquireFieldAccessor(ov); } // NOTE that there is no synchronization used here. It is correct @@ -982,19 +1108,6 @@ } } - // NOTE: be very careful if you change the stack depth of this - // routine. The depth of the "getCallerClass" call is hardwired so - // that the compiler can have an easier time if this gets inlined. - private void doSecurityCheck(Object obj) throws IllegalAccessException { - if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class<?> caller = Reflection.getCallerClass(4); - - checkAccess(caller, clazz, obj, modifiers); - } - } - } - /** * @throws NullPointerException {@inheritDoc} * @since 1.5
--- a/src/share/classes/java/lang/reflect/Method.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/reflect/Method.java Wed Apr 17 02:53:02 2013 -0700 @@ -25,6 +25,7 @@ package java.lang.reflect; +import sun.reflect.CallerSensitive; import sun.reflect.MethodAccessor; import sun.reflect.Reflection; import sun.reflect.generics.repository.MethodRepository; @@ -472,14 +473,14 @@ * @exception ExceptionInInitializerError if the initialization * provoked by this method fails. */ + @CallerSensitive public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class<?> caller = Reflection.getCallerClass(1); - + Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } }
--- a/src/share/classes/java/lang/reflect/Proxy.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/lang/reflect/Proxy.java Wed Apr 17 02:53:02 2013 -0700 @@ -39,6 +39,8 @@ import java.util.List; import java.util.WeakHashMap; import sun.misc.ProxyGenerator; +import sun.misc.VM; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; @@ -408,28 +410,21 @@ * @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null} */ + @CallerSensitive public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException { - return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor - } - - private static void checkProxyLoader(ClassLoader ccl, - ClassLoader loader) - { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - if (loader == null && ccl != null) { - if (!ProxyAccessHelper.allowNullLoader) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } - } + checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); } + + return getProxyClass0(loader, interfaces); } /* - * Generate a proxy class (caller-sensitive). + * Check permissions required to create a Proxy class. * * To define a proxy class, it performs the access checks as in * Class.forName (VM will invoke ClassLoader.checkPackageAccess): @@ -446,17 +441,28 @@ * will throw IllegalAccessError when the generated proxy class is * being defined via the defineClass0 method. */ - private static Class<?> getProxyClass0(ClassLoader loader, - Class<?>... interfaces) { + private static void checkProxyAccess(Class<?> caller, + ClassLoader loader, + Class<?>... interfaces) + { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller - final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME); - final ClassLoader ccl = caller.getClassLoader(); - checkProxyLoader(ccl, loader); + ClassLoader ccl = caller.getClassLoader(); + if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) { + if (!ProxyAccessHelper.allowNullLoader) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } ReflectUtil.checkProxyPackageAccess(ccl, interfaces); } + } + /** + * Generate a proxy class. Must call the checkProxyAccess method + * to perform permission checks before calling this. + */ + private static Class<?> getProxyClass0(ClassLoader loader, + Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } @@ -698,6 +704,7 @@ * if the invocation handler, {@code h}, is * {@code null} */ + @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) @@ -707,10 +714,15 @@ throw new NullPointerException(); } + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); + } + /* * Look up or generate the designated proxy class. */ - Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor + Class<?> cl = getProxyClass0(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. @@ -718,7 +730,6 @@ try { final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; - SecurityManager sm = System.getSecurityManager(); if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission
--- a/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -122,7 +122,7 @@ * not connected already. */ protected void disconnect() { - disconnect0(connectedAddress.family); + disconnect0(connectedAddress.holder().getFamily()); connected = false; connectedAddress = null; connectedPort = -1;
--- a/src/share/classes/java/net/Inet4Address.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/net/Inet4Address.java Wed Apr 17 02:53:02 2013 -0700 @@ -100,27 +100,28 @@ Inet4Address() { super(); - hostName = null; - address = 0; - family = IPv4; + holder().hostName = null; + holder().address = 0; + holder().family = IPv4; } Inet4Address(String hostName, byte addr[]) { - this.hostName = hostName; - this.family = IPv4; + holder().hostName = hostName; + holder().family = IPv4; if (addr != null) { if (addr.length == INADDRSZ) { - address = addr[3] & 0xFF; + int address = addr[3] & 0xFF; address |= ((addr[2] << 8) & 0xFF00); address |= ((addr[1] << 16) & 0xFF0000); address |= ((addr[0] << 24) & 0xFF000000); + holder().address = address; } } } Inet4Address(String hostName, int address) { - this.hostName = hostName; - this.family = IPv4; - this.address = address; + holder().hostName = hostName; + holder().family = IPv4; + holder().address = address; } /** @@ -134,8 +135,8 @@ private Object writeReplace() throws ObjectStreamException { // will replace the to be serialized 'this' object InetAddress inet = new InetAddress(); - inet.hostName = this.hostName; - inet.address = this.address; + inet.holder().hostName = holder().getHostName(); + inet.holder().address = holder().getAddress(); /** * Prior to 1.4 an InetAddress was created with a family @@ -143,7 +144,7 @@ * For compatibility reasons we must therefore write the * the InetAddress with this family. */ - inet.family = 2; + inet.holder().family = 2; return inet; } @@ -157,7 +158,7 @@ * @since JDK1.1 */ public boolean isMulticastAddress() { - return ((address & 0xf0000000) == 0xe0000000); + return ((holder().getAddress() & 0xf0000000) == 0xe0000000); } /** @@ -167,7 +168,7 @@ * @since 1.4 */ public boolean isAnyLocalAddress() { - return address == 0; + return holder().getAddress() == 0; } /** @@ -195,6 +196,7 @@ // defined in "Documenting Special Use IPv4 Address Blocks // that have been Registered with IANA" by Bill Manning // draft-manning-dsua-06.txt + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 169) && (((address >>> 16) & 0xFF) == 254); } @@ -211,6 +213,7 @@ // 10/8 prefix // 172.16/12 prefix // 192.168/16 prefix + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 10) || ((((address >>> 24) & 0xFF) == 172) && (((address >>> 16) & 0xF0) == 16)) @@ -257,6 +260,7 @@ */ public boolean isMCLinkLocal() { // 224.0.0/24 prefix and ttl == 1 + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 224) && (((address >>> 16) & 0xFF) == 0) && (((address >>> 8) & 0xFF) == 0); @@ -272,6 +276,7 @@ */ public boolean isMCSiteLocal() { // 239.255/16 prefix or ttl < 32 + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 239) && (((address >>> 16) & 0xFF) == 255); } @@ -287,6 +292,7 @@ */ public boolean isMCOrgLocal() { // 239.192 - 239.195 + int address = holder().getAddress(); return (((address >>> 24) & 0xFF) == 239) && (((address >>> 16) & 0xFF) >= 192) && (((address >>> 16) & 0xFF) <= 195); @@ -300,6 +306,7 @@ * @return the raw IP address of this object. */ public byte[] getAddress() { + int address = holder().getAddress(); byte[] addr = new byte[INADDRSZ]; addr[0] = (byte) ((address >>> 24) & 0xFF); @@ -325,7 +332,7 @@ * @return a hash code value for this IP address. */ public int hashCode() { - return address; + return holder().getAddress(); } /** @@ -346,7 +353,7 @@ */ public boolean equals(Object obj) { return (obj != null) && (obj instanceof Inet4Address) && - (((InetAddress)obj).address == address); + (((InetAddress)obj).holder().getAddress() == holder().getAddress()); } // Utilities
--- a/src/share/classes/java/net/Inet4AddressImpl.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/net/Inet4AddressImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -40,7 +40,7 @@ public synchronized InetAddress anyLocalAddress() { if (anyLocalAddress == null) { anyLocalAddress = new Inet4Address(); // {0x00,0x00,0x00,0x00} - anyLocalAddress.hostName = "0.0.0.0"; + anyLocalAddress.holder().hostName = "0.0.0.0"; } return anyLocalAddress; }
--- a/src/share/classes/java/net/Inet6Address.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/net/Inet6Address.java Wed Apr 17 02:53:02 2013 -0700 @@ -210,18 +210,18 @@ Inet6Address() { super(); - hostName = null; + holder().hostName = null; ipaddress = new byte[INADDRSZ]; - family = IPv6; + holder().family = IPv6; } /* checking of value for scope_id should be done by caller * scope_id must be >= 0, or -1 to indicate not being set */ Inet6Address(String hostName, byte addr[], int scope_id) { - this.hostName = hostName; + holder().hostName = hostName; if (addr.length == INADDRSZ) { // normal IPv6 address - family = IPv6; + holder().family = IPv6; ipaddress = addr.clone(); } if (scope_id >= 0) { @@ -335,9 +335,9 @@ private void initif(String hostName, byte addr[],NetworkInterface nif) throws UnknownHostException { - this.hostName = hostName; + holder().hostName = hostName; if (addr.length == INADDRSZ) { // normal IPv6 address - family = IPv6; + holder().family = IPv6; ipaddress = addr.clone(); } if (nif != null) { @@ -420,6 +420,11 @@ */ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + + if (getClass().getClassLoader() != null) { + throw new SecurityException ("invalid address type"); + } + s.defaultReadObject(); if (ifname != null && !ifname.equals("")) { @@ -447,7 +452,7 @@ ipaddress.length); } - if (family != IPv6) { + if (holder().getFamily() != IPv6) { throw new InvalidObjectException("invalid address family type"); } }
--- a/src/share/classes/java/net/Inet6AddressImpl.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/net/Inet6AddressImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -81,7 +81,7 @@ if (anyLocalAddress == null) { if (InetAddress.preferIPv6Address) { anyLocalAddress = new Inet6Address(); - anyLocalAddress.hostName = "::"; + anyLocalAddress.holder().hostName = "::"; } else { anyLocalAddress = (new Inet4AddressImpl()).anyLocalAddress(); }
--- a/src/share/classes/java/net/InetAddress.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/net/InetAddress.java Wed Apr 17 02:53:02 2013 -0700 @@ -35,8 +35,12 @@ import java.util.ServiceLoader; import java.security.AccessController; import java.io.ObjectStreamException; +import java.io.ObjectStreamField; import java.io.IOException; import java.io.ObjectInputStream; +import java.io.ObjectInputStream.GetField; +import java.io.ObjectOutputStream; +import java.io.ObjectOutputStream.PutField; import sun.security.action.*; import sun.net.InetAddressCachePolicy; import sun.net.util.IPAddressUtil; @@ -199,25 +203,48 @@ /* Specify address family preference */ static transient boolean preferIPv6Address = false; - /** - * @serial - */ - String hostName; + static class InetAddressHolder { + + InetAddressHolder() {} + + InetAddressHolder(String hostName, int address, int family) { + this.hostName = hostName; + this.address = address; + this.family = family; + } + + String hostName; + + String getHostName() { + return hostName; + } + + /** + * Holds a 32-bit IPv4 address. + */ + int address; - /** - * Holds a 32-bit IPv4 address. - * - * @serial - */ - int address; + int getAddress() { + return address; + } + + /** + * Specifies the address family type, for instance, '1' for IPv4 + * addresses, and '2' for IPv6 addresses. + */ + int family; - /** - * Specifies the address family type, for instance, '1' for IPv4 - * addresses, and '2' for IPv6 addresses. - * - * @serial - */ - int family; + int getFamily() { + return family; + } + } + + /* Used to store the serializable fields of InetAddress */ + private final transient InetAddressHolder holder; + + InetAddressHolder holder() { + return holder; + } /* Used to store the name service provider */ private static List<NameService> nameServices = null; @@ -251,6 +278,7 @@ * put in the address cache, since it is not created by name. */ InetAddress() { + holder = new InetAddressHolder(); } /** @@ -263,7 +291,7 @@ */ private Object readResolve() throws ObjectStreamException { // will replace the deserialized 'this' object - return new Inet4Address(this.hostName, this.address); + return new Inet4Address(holder().getHostName(), holder().getAddress()); } /** @@ -500,10 +528,10 @@ * @see SecurityManager#checkConnect */ String getHostName(boolean check) { - if (hostName == null) { - hostName = InetAddress.getHostFromNameService(this, check); + if (holder().getHostName() == null) { + holder().hostName = InetAddress.getHostFromNameService(this, check); } - return hostName; + return holder().getHostName(); } /** @@ -666,6 +694,7 @@ * @return a string representation of this IP address. */ public String toString() { + String hostName = holder().getHostName(); return ((hostName != null) ? hostName : "") + "/" + getHostAddress(); } @@ -1522,14 +1551,58 @@ } } + private static final long FIELDS_OFFSET; + private static final sun.misc.Unsafe UNSAFE; + + static { + try { + sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); + FIELDS_OFFSET = unsafe.objectFieldOffset( + InetAddress.class.getDeclaredField("holder") + ); + UNSAFE = unsafe; + } catch (ReflectiveOperationException e) { + throw new Error(e); + } + } + private void readObject (ObjectInputStream s) throws IOException, ClassNotFoundException { - s.defaultReadObject (); if (getClass().getClassLoader() != null) { - hostName = null; - address = 0; throw new SecurityException ("invalid address type"); } + GetField gf = s.readFields(); + String host = (String)gf.get("hostName", null); + int address= gf.get("address", 0); + int family= gf.get("family", 0); + InetAddressHolder h = new InetAddressHolder(host, address, family); + UNSAFE.putObject(this, FIELDS_OFFSET, h); + } + + /* needed because the serializable fields no longer exist */ + + /** + * @serialField hostName String + * @serialField address int + * @serialField family int + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("hostName", String.class), + new ObjectStreamField("address", int.class), + new ObjectStreamField("family", int.class), + }; + + private void writeObject (ObjectOutputStream s) throws + IOException { + if (getClass().getClassLoader() != null) { + throw new SecurityException ("invalid address type"); + } + PutField pf = s.putFields(); + pf.put("hostName", holder().getHostName()); + pf.put("address", holder().getAddress()); + pf.put("family", holder().getFamily()); + s.writeFields(); + s.flush(); } }
--- a/src/share/classes/java/net/InetSocketAddress.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/net/InetSocketAddress.java Wed Apr 17 02:53:02 2013 -0700 @@ -87,8 +87,8 @@ if (hostname != null) return hostname; if (addr != null) { - if (addr.hostName != null) - return addr.hostName; + if (addr.holder().getHostName() != null) + return addr.holder().getHostName(); else return addr.getHostAddress(); }
--- a/src/share/classes/java/rmi/server/LogStream.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/rmi/server/LogStream.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,6 +120,13 @@ */ @Deprecated public static synchronized void setDefaultStream(PrintStream newDefault) { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) { + sm.checkPermission( + new java.util.logging.LoggingPermission("control", null)); + } + defaultStream = newDefault; }
--- a/src/share/classes/java/security/AccessController.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/security/AccessController.java Wed Apr 17 02:53:02 2013 -0700 @@ -26,6 +26,8 @@ package java.security; import sun.security.util.Debug; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; /** * <p> The AccessController class is used for access control operations @@ -264,6 +266,7 @@ * @see java.security.DomainCombiner */ + @CallerSensitive public static native <T> T doPrivileged(PrivilegedAction<T> action); /** @@ -288,14 +291,15 @@ * * @since 1.6 */ + @CallerSensitive public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) { - AccessControlContext acc = getStackAccessControlContext(); if (acc == null) { return AccessController.doPrivileged(action); } DomainCombiner dc = acc.getAssignedCombiner(); - return AccessController.doPrivileged(action, preserveCombiner(dc)); + return AccessController.doPrivileged(action, + preserveCombiner(dc, Reflection.getCallerClass())); } @@ -326,6 +330,7 @@ * @see #doPrivileged(PrivilegedAction) * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext) */ + @CallerSensitive public static native <T> T doPrivileged(PrivilegedAction<T> action, AccessControlContext context); @@ -353,6 +358,7 @@ * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction) * @see java.security.DomainCombiner */ + @CallerSensitive public static native <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws PrivilegedActionException; @@ -383,34 +389,29 @@ * * @since 1.6 */ - public static <T> T doPrivilegedWithCombiner - (PrivilegedExceptionAction<T> action) throws PrivilegedActionException { - + @CallerSensitive + public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action) + throws PrivilegedActionException + { AccessControlContext acc = getStackAccessControlContext(); if (acc == null) { return AccessController.doPrivileged(action); } DomainCombiner dc = acc.getAssignedCombiner(); - return AccessController.doPrivileged(action, preserveCombiner(dc)); + return AccessController.doPrivileged(action, + preserveCombiner(dc, Reflection.getCallerClass())); } /** * preserve the combiner across the doPrivileged call */ - private static AccessControlContext preserveCombiner - (DomainCombiner combiner) { - - /** - * callerClass[0] = Reflection.getCallerClass - * callerClass[1] = AccessController.preserveCombiner - * callerClass[2] = AccessController.doPrivileged - * callerClass[3] = caller - */ - final Class<?> callerClass = sun.reflect.Reflection.getCallerClass(3); + private static AccessControlContext preserveCombiner(DomainCombiner combiner, + Class<?> caller) + { ProtectionDomain callerPd = doPrivileged (new PrivilegedAction<ProtectionDomain>() { public ProtectionDomain run() { - return callerClass.getProtectionDomain(); + return caller.getProtectionDomain(); } }); @@ -455,6 +456,7 @@ * @see #doPrivileged(PrivilegedAction) * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext) */ + @CallerSensitive public static native <T> T doPrivileged(PrivilegedExceptionAction<T> action, AccessControlContext context)
--- a/src/share/classes/java/sql/DriverManager.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/sql/DriverManager.java Wed Apr 17 02:53:02 2013 -0700 @@ -30,6 +30,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.CopyOnWriteArrayList; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; @@ -192,14 +193,11 @@ * has been exceeded and has at least tried to cancel the * current database connection attempt */ + @CallerSensitive public static Connection getConnection(String url, java.util.Properties info) throws SQLException { - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); - - return (getConnection(url, info, callerCL)); + return (getConnection(url, info, Reflection.getCallerClass())); } /** @@ -226,14 +224,11 @@ * has been exceeded and has at least tried to cancel the * current database connection attempt */ + @CallerSensitive public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); - if (user != null) { info.put("user", user); } @@ -241,7 +236,7 @@ info.put("password", password); } - return (getConnection(url, info, callerCL)); + return (getConnection(url, info, Reflection.getCallerClass())); } /** @@ -259,16 +254,12 @@ * has been exceeded and has at least tried to cancel the * current database connection attempt */ + @CallerSensitive public static Connection getConnection(String url) throws SQLException { java.util.Properties info = new java.util.Properties(); - - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); - - return (getConnection(url, info, callerCL)); + return (getConnection(url, info, Reflection.getCallerClass())); } /** @@ -282,21 +273,20 @@ * that can connect to the given URL * @exception SQLException if a database access error occurs */ + @CallerSensitive public static Driver getDriver(String url) throws SQLException { println("DriverManager.getDriver(\"" + url + "\")"); - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); + Class<?> callerClass = Reflection.getCallerClass(); // Walk through the loaded registeredDrivers attempting to locate someone // who understands the given URL. for (DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. - if(isDriverAllowed(aDriver.driver, callerCL)) { + if(isDriverAllowed(aDriver.driver, callerClass)) { try { if(aDriver.driver.acceptsURL(url)) { // Success! @@ -350,20 +340,18 @@ * @param driver the JDBC Driver to drop * @exception SQLException if a database access error occurs */ + @CallerSensitive public static synchronized void deregisterDriver(Driver driver) throws SQLException { if (driver == null) { return; } - // Gets the classloader of the code that called this method, - // may be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); println("DriverManager.deregisterDriver: " + driver); DriverInfo aDriver = new DriverInfo(driver); if(registeredDrivers.contains(aDriver)) { - if (isDriverAllowed(driver, callerCL)) { + if (isDriverAllowed(driver, Reflection.getCallerClass())) { registeredDrivers.remove(aDriver); } else { // If the caller does not have permission to load the driver then @@ -384,18 +372,17 @@ * * @return the list of JDBC Drivers loaded by the caller's class loader */ + @CallerSensitive public static java.util.Enumeration<Driver> getDrivers() { java.util.Vector<Driver> result = new java.util.Vector<>(); - // Gets the classloader of the code that called this method, may - // be null. - ClassLoader callerCL = DriverManager.getCallerClassLoader(); + Class<?> callerClass = Reflection.getCallerClass(); // Walk through the loaded registeredDrivers. for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. - if(isDriverAllowed(aDriver.driver, callerCL)) { + if(isDriverAllowed(aDriver.driver, callerClass)) { result.addElement(aDriver.driver); } else { println(" skipping: " + aDriver.getClass().getName()); @@ -493,17 +480,13 @@ //------------------------------------------------------------------------ - // Internal method used to get the caller's class loader. - // Replaces the call to the native method - private static ClassLoader getCallerClassLoader() { - Class<?> cc = Reflection.getCallerClass(3); - ClassLoader cl = (cc != null) ? cc.getClassLoader() : null; - return cl; + // Indicates whether the class object that would be created if the code calling + // DriverManager is accessible. + private static boolean isDriverAllowed(Driver driver, Class<?> caller) { + ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; + return isDriverAllowed(driver, callerCL); } - - // Indicates whether the class object that would be created if the code calling - // DriverManager is accessible. private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) { boolean result = false; if(driver != null) { @@ -556,7 +539,7 @@ */ try{ while(driversIterator.hasNext()) { - println(" Loading done by the java.util.ServiceLoader : "+driversIterator.next()); + driversIterator.next(); } } catch(Throwable t) { // Do nothing @@ -586,18 +569,19 @@ // Worker method called by the public getConnection() methods. private static Connection getConnection( - String url, java.util.Properties info, ClassLoader callerCL) throws SQLException { + String url, java.util.Properties info, Class<?> caller) throws SQLException { /* * When callerCl is null, we should check the application's * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */ + ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; synchronized(DriverManager.class) { - // synchronize loading of the correct classloader. - if(callerCL == null) { - callerCL = Thread.currentThread().getContextClassLoader(); - } + // synchronize loading of the correct classloader. + if (callerCL == null) { + callerCL = Thread.currentThread().getContextClassLoader(); + } } if(url == null) {
--- a/src/share/classes/java/util/Collections.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/Collections.java Wed Apr 17 02:53:02 2013 -0700 @@ -28,6 +28,9 @@ import java.io.ObjectOutputStream; import java.io.IOException; import java.lang.reflect.Array; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; /** * This class consists exclusively of static methods that operate on or return @@ -264,8 +267,7 @@ } private static <T> - int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) - { + int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) { int low = 0; int high = list.size()-1; @@ -441,21 +443,21 @@ /** * Randomly permutes the specified list using a default source of * randomness. All permutations occur with approximately equal - * likelihood.<p> + * likelihood. * - * The hedge "approximately" is used in the foregoing description because + * <p>The hedge "approximately" is used in the foregoing description because * default source of randomness is only approximately an unbiased source * of independently chosen bits. If it were a perfect source of randomly * chosen bits, then the algorithm would choose permutations with perfect - * uniformity.<p> + * uniformity. * - * This implementation traverses the list backwards, from the last element - * up to the second, repeatedly swapping a randomly selected element into - * the "current position". Elements are randomly selected from the + * <p>This implementation traverses the list backwards, from the last + * element up to the second, repeatedly swapping a randomly selected element + * into the "current position". Elements are randomly selected from the * portion of the list that runs from the first element to the current - * position, inclusive.<p> + * position, inclusive. * - * This method runs in linear time. If the specified list does not + * <p>This method runs in linear time. If the specified list does not * implement the {@link RandomAccess} interface and is large, this * implementation dumps the specified list into an array before shuffling * it, and dumps the shuffled array back into the list. This avoids the @@ -469,9 +471,10 @@ public static void shuffle(List<?> list) { Random rnd = r; if (rnd == null) - r = rnd = new Random(); + r = rnd = new Random(); // harmless race. shuffle(list, rnd); } + private static Random r; /** @@ -1391,6 +1394,67 @@ public int hashCode() {return m.hashCode();} public String toString() {return m.toString();} + // Override default methods in Map + @Override + @SuppressWarnings("unchecked") + public V getOrDefault(Object k, V defaultValue) { + // Safe cast as we don't change the value + return ((Map<K, V>)m).getOrDefault(k, defaultValue); + } + + @Override + public void forEach(BiConsumer<? super K, ? super V> action) { + m.forEach(action); + } + + @Override + public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { + throw new UnsupportedOperationException(); + } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, V value, + BiFunction<? super V, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } + /** * We need this class in addition to UnmodifiableSet as * Map.Entries themselves permit modification of the backing Map @@ -1590,9 +1654,9 @@ * </pre> * Failure to follow this advice may result in non-deterministic behavior. * - * <p>The returned collection does <i>not</i> pass the <tt>hashCode</tt> - * and <tt>equals</tt> operations through to the backing collection, but - * relies on <tt>Object</tt>'s equals and hashCode methods. This is + * <p>The returned collection does <i>not</i> pass the {@code hashCode} + * and {@code equals} operations through to the backing collection, but + * relies on {@code Object}'s equals and hashCode methods. This is * necessary to preserve the contracts of these operations in the case * that the backing collection is a set or a list.<p> * @@ -2107,6 +2171,57 @@ public String toString() { synchronized (mutex) {return m.toString();} } + + // Override default methods in Map + @Override + public V getOrDefault(Object k, V defaultValue) { + synchronized (mutex) {return m.getOrDefault(k, defaultValue);} + } + @Override + public void forEach(BiConsumer<? super K, ? super V> action) { + synchronized (mutex) {m.forEach(action);} + } + @Override + public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { + synchronized (mutex) {m.replaceAll(function);} + } + @Override + public V putIfAbsent(K key, V value) { + synchronized (mutex) {return m.putIfAbsent(key, value);} + } + @Override + public boolean remove(Object key, Object value) { + synchronized (mutex) {return m.remove(key, value);} + } + @Override + public boolean replace(K key, V oldValue, V newValue) { + synchronized (mutex) {return m.replace(key, oldValue, newValue);} + } + @Override + public V replace(K key, V value) { + synchronized (mutex) {return m.replace(key, value);} + } + @Override + public V computeIfAbsent(K key, + Function<? super K, ? extends V> mappingFunction) { + synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);} + } + @Override + public V computeIfPresent(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);} + } + @Override + public V compute(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + synchronized (mutex) {return m.compute(key, remappingFunction);} + } + @Override + public V merge(K key, V value, + BiFunction<? super V, ? super V, ? extends V> remappingFunction) { + synchronized (mutex) {return m.merge(key, value, remappingFunction);} + } + private void writeObject(ObjectOutputStream s) throws IOException { synchronized (mutex) {s.defaultWriteObject();} } @@ -2326,6 +2441,8 @@ } public Iterator<E> iterator() { + // JDK-6363904 - unwrapped iterator could be typecast to + // ListIterator with unsafe set() final Iterator<E> it = c.iterator(); return new Iterator<E>() { public boolean hasNext() { return it.hasNext(); } @@ -2652,7 +2769,7 @@ public List<E> subList(int fromIndex, int toIndex) { return new CheckedRandomAccessList<>( - list.subList(fromIndex, toIndex), type); + list.subList(fromIndex, toIndex), type); } } @@ -2717,14 +2834,24 @@ throw new ClassCastException(badValueMsg(value)); } + private BiFunction<? super K, ? super V, ? extends V> typeCheck( + BiFunction<? super K, ? super V, ? extends V> func) { + Objects.requireNonNull(func); + return (k, v) -> { + V newValue = func.apply(k, v); + typeCheck(k, newValue); + return newValue; + }; + } + private String badKeyMsg(Object key) { return "Attempt to insert " + key.getClass() + - " key into map with key type " + keyType; + " key into map with key type " + keyType; } private String badValueMsg(Object value) { return "Attempt to insert " + value.getClass() + - " value into map with value type " + valueType; + " value into map with value type " + valueType; } CheckedMap(Map<K, V> m, Class<K> keyType, Class<V> valueType) { @@ -2768,7 +2895,7 @@ Object v = e.getValue(); typeCheck(k, v); checked.add( - new AbstractMap.SimpleImmutableEntry<>((K) k, (V) v)); + new AbstractMap.SimpleImmutableEntry<>((K)k, (V)v)); } for (Map.Entry<K,V> e : checked) m.put(e.getKey(), e.getValue()); @@ -2782,6 +2909,74 @@ return entrySet; } + // Override default methods in Map + @Override + public void forEach(BiConsumer<? super K, ? super V> action) { + m.forEach(action); + } + + @Override + public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { + m.replaceAll(typeCheck(function)); + } + + @Override + public V putIfAbsent(K key, V value) { + typeCheck(key, value); + return m.putIfAbsent(key, value); + } + + @Override + public boolean remove(Object key, Object value) { + return m.remove(key, value); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + typeCheck(key, newValue); + return m.replace(key, oldValue, newValue); + } + + @Override + public V replace(K key, V value) { + typeCheck(key, value); + return m.replace(key, value); + } + + @Override + public V computeIfAbsent(K key, + Function<? super K, ? extends V> mappingFunction) { + Objects.requireNonNull(mappingFunction); + return m.computeIfAbsent(key, k -> { + V value = mappingFunction.apply(k); + typeCheck(k, value); + return value; + }); + } + + @Override + public V computeIfPresent(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + return m.computeIfPresent(key, typeCheck(remappingFunction)); + } + + @Override + public V compute(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + return m.compute(key, typeCheck(remappingFunction)); + } + + @Override + public V merge(K key, V value, + BiFunction<? super V, ? super V, ? extends V> remappingFunction) { + Objects.requireNonNull(remappingFunction); + return m.merge(key, value, (v1, v2) -> { + V newValue = remappingFunction.apply(v1, v2); + typeCheck(null, newValue); + return newValue; + }); + } + /** * We need this class in addition to CheckedSet as Map.Entry permits * modification of the backing Map via the setValue operation. This @@ -3456,6 +3651,67 @@ public int hashCode() {return 0;} + // Override default methods in Map + @Override + @SuppressWarnings("unchecked") + public V getOrDefault(Object k, V defaultValue) { + return defaultValue; + } + + @Override + public void forEach(BiConsumer<? super K, ? super V> action) { + Objects.requireNonNull(action); + } + + @Override + public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { + Objects.requireNonNull(function); + } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, + Function<? super K, ? extends V> mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, V value, + BiFunction<? super V, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } + // Preserves singleton property private Object readResolve() { return EMPTY_MAP; @@ -3619,6 +3875,65 @@ return values; } + // Override default methods in Map + @Override + public V getOrDefault(Object key, V defaultValue) { + return eq(key, k) ? v : defaultValue; + } + + @Override + public void forEach(BiConsumer<? super K, ? super V> action) { + action.accept(k, v); + } + + @Override + public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { + throw new UnsupportedOperationException(); + } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, + Function<? super K, ? extends V> mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, V value, + BiFunction<? super V, ? super V, ? extends V> remappingFunction) { + throw new UnsupportedOperationException(); + } } // Miscellaneous
--- a/src/share/classes/java/util/CurrencyData.properties Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/CurrencyData.properties Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=154 +dataVersion=155 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -585,7 +585,7 @@ minor0=\ ADP-BEF-BIF-BYB-BYR-CLF-CLP-DJF-ESP-GNF-\ GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\ - TPE-TRL-VND-VUV-XAF-XOF-XPF + TPE-TRL-UGX-VND-VUV-XAF-XOF-XPF minor1= minor3=\ BHD-IQD-JOD-KWD-LYD-OMR-TND
--- a/src/share/classes/java/util/HashMap.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/HashMap.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,11 @@ */ package java.util; + import java.io.*; +import java.util.function.Consumer; +import java.util.function.BiFunction; +import java.util.function.Function; /** * Hash table based implementation of the <tt>Map</tt> interface. This @@ -376,6 +380,13 @@ return null == entry ? null : entry.getValue(); } + @Override + public V getOrDefault(Object key, V defaultValue) { + Entry<K,V> entry = getEntry(key); + + return (entry == null) ? defaultValue : entry.getValue(); + } + /** * Returns <tt>true</tt> if this map contains a mapping for the * specified key. @@ -603,6 +614,261 @@ return (e == null ? null : e.value); } + // optimized implementations of default methods in Map + + @Override + public V putIfAbsent(K key, V value) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)table[i]; + for(; e != null; e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key)) { + if(e.value != null) { + return e.value; + } + e.value = value; + modCount++; + e.recordAccess(this); + return null; + } + } + + modCount++; + addEntry(hash, key, value, i); + return null; + } + + @Override + public boolean remove(Object key, Object value) { + if (isEmpty()) { + return false; + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry<K,V> prev = (Entry<K,V>)table[i]; + Entry<K,V> e = prev; + + while (e != null) { + Entry<K,V> next = e.next; + if (e.hash == hash && Objects.equals(e.key, key)) { + if (!Objects.equals(e.value, value)) { + return false; + } + modCount++; + size--; + if (prev == e) + table[i] = next; + else + prev.next = next; + e.recordRemoval(this); + return true; + } + prev = e; + e = next; + } + + return false; + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + if (isEmpty()) { + return false; + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)table[i]; + for (; e != null; e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key) && Objects.equals(e.value, oldValue)) { + e.value = newValue; + e.recordAccess(this); + return true; + } + } + + return false; + } + + @Override + public V replace(K key, V value) { + if (isEmpty()) { + return null; + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)table[i]; + for (; e != null; e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + e.value = value; + e.recordAccess(this); + return oldValue; + } + } + + return null; + } + + @Override + public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)table[i]; + for (; e != null; e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + return oldValue == null ? (e.value = mappingFunction.apply(key)) : oldValue; + } + } + + V newValue = mappingFunction.apply(key); + if (newValue != null) { + modCount++; + addEntry(hash, key, newValue, i); + } + + return newValue; + } + + @Override + public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + if (isEmpty()) { + return null; + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry<K,V> prev = (Entry<K,V>)table[i]; + Entry<K,V> e = prev; + + while (e != null) { + Entry<K,V> next = e.next; + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + if (oldValue == null) + break; + V newValue = remappingFunction.apply(key, oldValue); + modCount++; + if (newValue == null) { + size--; + if (prev == e) + table[i] = next; + else + prev.next = next; + e.recordRemoval(this); + } else { + e.value = newValue; + e.recordAccess(this); + } + return newValue; + } + prev = e; + e = next; + } + + return null; + } + + @Override + public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry<K,V> prev = (Entry<K,V>)table[i]; + Entry<K,V> e = prev; + + while (e != null) { + Entry<K,V> next = e.next; + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + V newValue = remappingFunction.apply(key, oldValue); + if (newValue != oldValue) { + modCount++; + if (newValue == null) { + size--; + if (prev == e) + table[i] = next; + else + prev.next = next; + e.recordRemoval(this); + } else { + e.value = newValue; + e.recordAccess(this); + } + } + return newValue; + } + prev = e; + e = next; + } + + V newValue = remappingFunction.apply(key, null); + if (newValue != null) { + modCount++; + addEntry(hash, key, newValue, i); + } + + return newValue; + } + + @Override + public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } + int hash = (key == null) ? 0 : hash(key); + int i = indexFor(hash, table.length); + @SuppressWarnings("unchecked") + Entry<K,V> prev = (Entry<K,V>)table[i]; + Entry<K,V> e = prev; + + while (e != null) { + Entry<K,V> next = e.next; + if (e.hash == hash && Objects.equals(e.key, key)) { + V oldValue = e.value; + V newValue = remappingFunction.apply(oldValue, value); + modCount++; + if (newValue == null) { + size--; + if (prev == e) + table[i] = next; + else + prev.next = next; + e.recordRemoval(this); + } else { + e.value = newValue; + e.recordAccess(this); + } + return newValue; + } + prev = e; + e = next; + } + + if (value != null) { + modCount++; + addEntry(hash, key, value, i); + } + + return value; + } + + // end of optimized implementations of default methods in Map + /** * Removes and returns the entry associated with the specified key * in the HashMap. Returns null if the HashMap contains no mapping @@ -697,8 +963,8 @@ return containsNullValue(); Entry<?,?>[] tab = table; - for (int i = 0; i < tab.length ; i++) - for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) + for (int i = 0; i < tab.length; i++) + for (Entry<?,?> e = tab[i]; e != null; e = e.next) if (value.equals(e.value)) return true; return false; @@ -709,8 +975,8 @@ */ private boolean containsNullValue() { Entry<?,?>[] tab = table; - for (int i = 0; i < tab.length ; i++) - for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) + for (int i = 0; i < tab.length; i++) + for (Entry<?,?> e = tab[i]; e != null; e = e.next) if (e.value == null) return true; return false;
--- a/src/share/classes/java/util/Hashtable.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/Hashtable.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,11 @@ */ package java.util; + import java.io.*; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.BiFunction; /** * This class implements a hash table, which maps keys to values. Any @@ -455,6 +459,26 @@ } } + private void addEntry(int hash, K key, V value, int index) { + modCount++; + + Entry<?,?> tab[] = table; + if (count >= threshold) { + // Rehash the table if the threshold is exceeded + rehash(); + + tab = table; + hash = hash(key); + index = (hash & 0x7FFFFFFF) % tab.length; + } + + // Creates the new entry. + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>) tab[index]; + tab[index] = new Entry<>(hash, key, value, e); + count++; + } + /** * Maps the specified <code>key</code> to the specified * <code>value</code> in this hashtable. Neither the key nor the @@ -492,21 +516,7 @@ } } - modCount++; - if (count >= threshold) { - // Rehash the table if the threshold is exceeded - rehash(); - - tab = table; - hash = hash(key); - index = (hash & 0x7FFFFFFF) % tab.length; - } - - // Creates the new entry. - @SuppressWarnings("unchecked") - Entry<K,V> e = (Entry<K,V>)tab[index]; - tab[index] = new Entry<>(hash, key, value, e); - count++; + addEntry(hash, key, value, index); return null; } @@ -892,6 +902,239 @@ return h; } + @Override + public synchronized V getOrDefault(Object key, V defaultValue) { + V result = get(key); + return (null == result) ? defaultValue : result; + } + + @Override + public synchronized void forEach(BiConsumer<? super K, ? super V> action) { + Objects.requireNonNull(action); // explicit check required in case + // table is empty. + Entry<?,?>[] tab = table; + for (Entry<?,?> entry : tab) { + while (entry != null) { + action.accept((K)entry.key, (V)entry.value); + entry = entry.next; + } + } + } + + @Override + public synchronized void replaceAll( + BiFunction<? super K, ? super V, ? extends V> function) { + Map.super.replaceAll(function); + } + + @Override + public synchronized V putIfAbsent(K key, V value) { + Objects.requireNonNull(value); + + // Makes sure the key is not already in the hashtable. + Entry<?,?> tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry<K,V> entry = (Entry<K,V>)tab[index]; + for (; entry != null; entry = entry.next) { + if ((entry.hash == hash) && entry.key.equals(key)) { + V old = entry.value; + if (old == null) { + entry.value = value; + } + return old; + } + } + + addEntry(hash, key, value, index); + return null; + } + + @Override + public synchronized boolean remove(Object key, Object value) { + Objects.requireNonNull(value); + + Entry<?,?> tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)tab[index]; + for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { + if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) { + modCount++; + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + e.value = null; + return true; + } + } + return false; + } + + @Override + public synchronized boolean replace(K key, V oldValue, V newValue) { + Entry<?,?> tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)tab[index]; + for (; e != null; e = e.next) { + if ((e.hash == hash) && e.key.equals(key)) { + if (e.value.equals(oldValue)) { + e.value = newValue; + return true; + } else { + return false; + } + } + } + return false; + } + + @Override + public synchronized V replace(K key, V value) { + Entry<?,?> tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)tab[index]; + for (; e != null; e = e.next) { + if ((e.hash == hash) && e.key.equals(key)) { + V oldValue = e.value; + e.value = value; + return oldValue; + } + } + return null; + } + + @Override + public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { + Objects.requireNonNull(mappingFunction); + + Entry<?,?> tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)tab[index]; + for (; e != null; e = e.next) { + if (e.hash == hash && e.key.equals(key)) { + // Hashtable not accept null value + return e.value; + } + } + + V newValue = mappingFunction.apply(key); + if (newValue != null) { + addEntry(hash, key, newValue, index); + } + + return newValue; + } + + @Override + public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + Objects.requireNonNull(remappingFunction); + + Entry<?,?> tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)tab[index]; + for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { + if (e.hash == hash && e.key.equals(key)) { + V newValue = remappingFunction.apply(key, e.value); + if (newValue == null) { + modCount++; + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + } else { + e.value = newValue; + } + return newValue; + } + } + return null; + } + + @Override + public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + Objects.requireNonNull(remappingFunction); + + Entry<?,?> tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)tab[index]; + for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { + if (e.hash == hash && Objects.equals(e.key, key)) { + V newValue = remappingFunction.apply(key, e.value); + if (newValue == null) { + modCount++; + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + } else { + e.value = newValue; + } + return newValue; + } + } + + V newValue = remappingFunction.apply(key, null); + if (newValue != null) { + addEntry(hash, key, newValue, index); + } + + return newValue; + } + + @Override + public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { + Objects.requireNonNull(remappingFunction); + + Entry<?,?> tab[] = table; + int hash = hash(key); + int index = (hash & 0x7FFFFFFF) % tab.length; + @SuppressWarnings("unchecked") + Entry<K,V> e = (Entry<K,V>)tab[index]; + for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) { + if (e.hash == hash && e.key.equals(key)) { + V newValue = remappingFunction.apply(e.value, value); + if (newValue == null) { + modCount++; + if (prev != null) { + prev.next = e.next; + } else { + tab[index] = e.next; + } + count--; + } else { + e.value = newValue; + } + return newValue; + } + } + + if (value != null) { + addEntry(hash, key, value, index); + } + + return value; + } + /** * Save the state of the Hashtable to a stream (i.e., serialize it). *
--- a/src/share/classes/java/util/Map.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/Map.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,10 @@ package java.util; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + /** * An object that maps keys to values. A map cannot contain duplicate keys; * each key can map to at most one value. @@ -475,4 +479,613 @@ */ int hashCode(); + // Defaultable methods + + /** + * Returns the value to which the specified key is mapped, + * or {@code defaultValue} if this map contains no mapping + * for the key. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or + * {@code defaultValue} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys + * (<a href="Collection.html#optional-restrictions">optional</a>) + */ + default V getOrDefault(Object key, V defaultValue) { + V v; + return (((v = get(key)) != null) || containsKey(key)) + ? v + : defaultValue; + } + + /** + * Performs the given action on each entry in this map, in the order entries + * are returned by an entry set iterator (which may be unspecified), until + * all entries have been processed or the action throws an {@code Exception}. + * Exceptions thrown by the action are relayed to the caller. + * + * <p>The default implementation should be overridden by implementations if + * they can provide a more performant implementation than an iterator-based + * one. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec The default implementation is equivalent to, for this + * {@code map}: + * <pre> {@code + * for ((Map.Entry<K, V> entry : map.entrySet()) + * action.accept(entry.getKey(), entry.getValue()); + * }</pre> + * + * @param action The action to be performed for each entry + * @throws NullPointerException if the specified action is null + * @throws ConcurrentModificationException if an entry is found to be + * removed during iteration + * @since 1.8 + */ + default void forEach(BiConsumer<? super K, ? super V> action) { + Objects.requireNonNull(action); + for (Map.Entry<K, V> entry : entrySet()) { + K k; + V v; + try { + k = entry.getKey(); + v = entry.getValue(); + } catch(IllegalStateException ise) { + throw new ConcurrentModificationException(ise); + } + action.accept(k, v); + } + } + + /** + * Replaces each entry's value with the result of invoking the given + * function on that entry, in the order entries are returned by an entry + * set iterator, until all entries have been processed or the function + * throws an exception. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * <p>The default implementation is equivalent to, for this {@code map}: + * <pre> {@code + * for ((Map.Entry<K, V> entry : map.entrySet()) + * entry.setValue(function.apply(entry.getKey(), entry.getValue())); + * }</pre> + * + * @param function the function to apply to each entry + * @throws UnsupportedOperationException if the {@code set} operation + * is not supported by this map's entry set iterator. + * @throws ClassCastException if the class of a replacement value + * prevents it from being stored in this map + * @throws NullPointerException if the specified function is null, or the + * specified replacement value is null, and this map does not permit null + * values + * @throws ClassCastException if a replacement value is of an inappropriate + * type for this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if function or a replacement value is null, + * and this map does not permit null keys or values + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws IllegalArgumentException if some property of a replacement value + * prevents it from being stored in this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ConcurrentModificationException if an entry is found to be + * removed during iteration + * @since 1.8 + */ + default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { + Objects.requireNonNull(function); + for (Map.Entry<K, V> entry : entrySet()) { + K k; + V v; + try { + k = entry.getKey(); + v = entry.getValue(); + } catch(IllegalStateException ise) { + throw new ConcurrentModificationException(ise); + } + entry.setValue(function.apply(k, v)); + } + } + + /** + * If the specified key is not already associated with a value (or is mapped + * to {@code null}) associates it with the given value and returns + * {@code null}, else returns the current value. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * The default implementation is equivalent to, for this {@code + * map}: + * + * <pre> {@code + * if (map.get(key) == null) + * return map.put(key, value); + * else + * return map.get(key); + * }</pre> + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * {@code 1} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ClassCastException if the key or value is of an inappropriate + * type for this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ConcurrentModificationException if a modification of the map is + * detected during insertion of the value. + * @since 1.8 + */ + default V putIfAbsent(K key, V value) { + V v = get(key); + if (v == null) { + if (put(key, value) != null) { + throw new ConcurrentModificationException(); + } + } + + return v; + } + + /** + * Removes the entry for the specified key only if it is currently + * mapped to the specified value. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + * <pre> {@code + * if (map.containsKey(key) && Objects.equals(map.get(key), value)) { + * map.remove(key); + * return true; + * } else + * return false; + * }</pre> + * + * @param key key with which the specified value is associated + * @param value value expected to be associated with the specified key + * @return {@code true} if the value was removed + * @throws UnsupportedOperationException if the {@code remove} operation + * is not supported by this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ClassCastException if the key or value is of an inappropriate + * type for this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @since 1.8 + */ + default boolean remove(Object key, Object value) { + Object curValue = get(key); + if (!Objects.equals(curValue, value) || + (curValue == null && !containsKey(key))) { + return false; + } + remove(key); + return true; + } + + /** + * Replaces the entry for the specified key only if currently + * mapped to the specified value. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + * <pre> {@code + * if (map.containsKey(key) && Objects.equals(map.get(key), value)) { + * map.put(key, newValue); + * return true; + * } else + * return false; + * }</pre> + * + * @param key key with which the specified value is associated + * @param oldValue value expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return {@code true} if the value was replaced + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ClassCastException if the class of a specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if a specified key or value is null, + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of a specified key + * or value prevents it from being stored in this map + * @since 1.8 + */ + default boolean replace(K key, V oldValue, V newValue) { + Object curValue = get(key); + if (!Objects.equals(curValue, oldValue) || + (curValue == null && !containsKey(key))) { + return false; + } + put(key, newValue); + return true; + } + + /** + * Replaces the entry for the specified key only if it is + * currently mapped to some value. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + * <pre> {@code + * if (map.containsKey(key)) { + * return map.put(key, value); + * } else + * return null; + * }</pre> + * + * @param key key with which the specified value is associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * {@code null} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @since 1.8 + */ + default V replace(K key, V value) { + return containsKey(key) ? put(key, value) : null; + } + + /** + * If the specified key is not already associated with a value (or + * is mapped to {@code null}), attempts to compute its value using + * the given mapping function and enters it into this map unless + * {@code null}. + * + * <p>If the function returns {@code null} no mapping is recorded. If + * the function itself throws an (unchecked) exception, the + * exception is rethrown, and no mapping is recorded. The most + * common usage is to construct a new object serving as an initial + * mapped value or memoized result, as in: + * + * <pre> {@code + * map.computeIfAbsent(key, k -> new Value(f(k))); + * }</pre> + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. Any class that permits null values must document + * whether and how this method distinguishes absence from null mappings. + * + * @implSpec + * The default implementation is equivalent to the following + * steps for this {@code map}, then returning the current value or + * {@code null} if now absent: + * + * <pre> {@code + * if (map.get(key) == null) { + * V newValue = mappingFunction.apply(key); + * if (newValue != null) + * map.putIfAbsent(key, newValue); + * } + * }</pre> + * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * mappingFunction is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @since 1.8 + */ + default V computeIfAbsent(K key, + Function<? super K, ? extends V> mappingFunction) { + V v, newValue; + return ((v = get(key)) == null && + (newValue = mappingFunction.apply(key)) != null && + (v = putIfAbsent(key, newValue)) == null) ? newValue : v; + } + + /** + * If the value for the specified key is present and non-null, attempts to + * compute a new mapping given the key and its current mapped value. + * + * <p>If the function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception is + * rethrown, and the current mapping is left unchanged. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. Any class that permits null values must document + * whether and how this method distinguishes absence from null mappings. + * + * @implSpec + * The default implementation is equivalent to performing the + * following steps for this {@code map}, then returning the + * current value or {@code null} if now absent: + * + * <pre> {@code + * if (map.get(key) != null) { + * V oldValue = map.get(key); + * V newValue = remappingFunction.apply(key, oldValue); + * if (newValue != null) + * map.replace(key, oldValue, newValue); + * else + * map.remove(key, oldValue); + * } + * }</pre> + * + * In concurrent contexts, the default implementation may retry + * these steps when multiple threads attempt updates. + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * remappingFunction is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @since 1.8 + */ + default V computeIfPresent(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + V oldValue; + while ((oldValue = get(key)) != null) { + V newValue = remappingFunction.apply(key, oldValue); + if (newValue != null) { + if (replace(key, oldValue, newValue)) + return newValue; + } else if (remove(key, oldValue)) + return null; + } + return oldValue; + } + + /** + * Attempts to compute a mapping for the specified key and its + * current mapped value (or {@code null} if there is no current + * mapping). For example, to either create or append a {@code + * String msg} to a value mapping: + * + * <pre> {@code + * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre> + * (Method {@link #merge merge()} is often simpler to use for such purposes.) + * + * <p>If the function returns {@code null}, the mapping is removed (or + * remains absent if initially absent). If the function itself throws an + * (unchecked) exception, the exception is rethrown, and the current mapping + * is left unchanged. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. Any class that permits null values must document + * whether and how this method distinguishes absence from null mappings. + * + * @implSpec + * The default implementation is equivalent to performing the following + * steps for this {@code map}, then returning the current value or + * {@code null} if absent: + * + * <pre> {@code + * V oldValue = map.get(key); + * V newValue = remappingFunction.apply(key, oldValue); + * if (oldValue != null ) { + * if (newValue != null) + * map.replace(key, oldValue, newValue); + * else + * map.remove(key, oldValue); + * } else { + * if (newValue != null) + * map.putIfAbsent(key, newValue); + * else + * return null; + * } + * }</pre> + * + * In concurrent contexts, the default implementation may retry + * these steps when multiple threads attempt updates. + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * remappingFunction is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @since 1.8 + */ + default V compute(K key, + BiFunction<? super K, ? super V, ? extends V> remappingFunction) { + V oldValue = get(key); + for (;;) { + V newValue = remappingFunction.apply(key, oldValue); + if (oldValue != null) { + if (newValue != null) { + if (replace(key, oldValue, newValue)) + return newValue; + } else if (remove(key, oldValue)) { + return null; + } + oldValue = get(key); + } else { + if (newValue != null) { + if ((oldValue = putIfAbsent(key, newValue)) == null) + return newValue; + } else { + return null; + } + } + } + } + + /** + * If the specified key is not already associated with a value or is + * associated with null, associates it with the given value. + * Otherwise, replaces the value with the results of the given + * remapping function, or removes if the result is {@code null}. This + * method may be of use when combining multiple mapped values for a key. + * For example, to either create or append a {@code String msg} to a + * value mapping: + * + * <pre> {@code + * map.merge(key, msg, String::concat) + * }</pre> + * + * <p>If the function returns {@code null}, the mapping is removed (or + * remains absent if initially absent). If the function itself throws an + * (unchecked) exception, the exception is rethrown, and the current mapping + * is left unchanged. + * + * <p>The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. Any class that permits null values must document + * whether and how this method distinguishes absence from null mappings. + * + * @implSpec + * The default implementation is equivalent to performing the + * following steps for this {@code map}, then returning the + * current value or {@code null} if absent: + * + * <pre> {@code + * V oldValue = map.get(key); + * V newValue = (oldValue == null) ? value : + * remappingFunction.apply(oldValue, value); + * if (newValue == null) + * map.remove(key, oldValue); + * else if (oldValue == null) + * map.putIfAbsent(key, newValue); + * else + * map.replace(key, oldValue, newValue); + * }</pre> + * + * In concurrent contexts, the default implementation may retry + * these steps when multiple threads attempt updates. + * + * @param key key with which the specified value is to be associated + * @param value the value to use if absent + * @param remappingFunction the function to recompute a value if present + * @return the new value associated with the specified key, or null if none + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (<a href="Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * remappingFunction is null + * @since 1.8 + */ + default V merge(K key, V value, + BiFunction<? super V, ? super V, ? extends V> remappingFunction) { + V oldValue = get(key); + for (;;) { + if (oldValue != null) { + V newValue = remappingFunction.apply(oldValue, value); + if (newValue != null) { + if (replace(key, oldValue, newValue)) + return newValue; + } else if (remove(key, oldValue)) { + return null; + } + oldValue = get(key); + } else { + if (value == null) { + return null; + } + + if ((oldValue = putIfAbsent(key, value)) == null) { + return value; + } + } + } + } }
--- a/src/share/classes/java/util/ResourceBundle.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/ResourceBundle.java Wed Apr 17 02:53:02 2013 -0700 @@ -57,6 +57,8 @@ import java.util.jar.JarEntry; import java.util.spi.ResourceBundleControlProvider; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; import sun.util.locale.BaseLocale; import sun.util.locale.LocaleObjectCache; @@ -440,14 +442,10 @@ /* * Automatic determination of the ClassLoader to be used to load - * resources on behalf of the client. N.B. The client is getLoader's - * caller's caller. + * resources on behalf of the client. */ - private static ClassLoader getLoader() { - Class<?>[] stack = getClassContext(); - /* Magic number 2 identifies our caller's caller */ - Class<?> c = stack[2]; - ClassLoader cl = (c == null) ? null : c.getClassLoader(); + private static ClassLoader getLoader(Class<?> caller) { + ClassLoader cl = caller == null ? null : caller.getClassLoader(); if (cl == null) { // When the caller's loader is the boot class loader, cl is null // here. In that case, ClassLoader.getSystemClassLoader() may @@ -461,8 +459,6 @@ return cl; } - private static native Class<?>[] getClassContext(); - /** * A wrapper of ClassLoader.getSystemClassLoader(). */ @@ -746,11 +742,11 @@ * if no resource bundle for the specified base name can be found * @return a resource bundle for the given base name and the default locale */ + @CallerSensitive public static final ResourceBundle getBundle(String baseName) { return getBundleImpl(baseName, Locale.getDefault(), - /* must determine loader here, else we break stack invariant */ - getLoader(), + getLoader(Reflection.getCallerClass()), getDefaultControl(baseName)); } @@ -788,11 +784,11 @@ * needed. * @since 1.6 */ + @CallerSensitive public static final ResourceBundle getBundle(String baseName, Control control) { return getBundleImpl(baseName, Locale.getDefault(), - /* must determine loader here, else we break stack invariant */ - getLoader(), + getLoader(Reflection.getCallerClass()), control); } @@ -817,12 +813,12 @@ * if no resource bundle for the specified base name can be found * @return a resource bundle for the given base name and locale */ + @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale locale) { return getBundleImpl(baseName, locale, - /* must determine loader here, else we break stack invariant */ - getLoader(), + getLoader(Reflection.getCallerClass()), getDefaultControl(baseName)); } @@ -863,11 +859,11 @@ * needed. * @since 1.6 */ + @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale targetLocale, Control control) { return getBundleImpl(baseName, targetLocale, - /* must determine loader here, else we break stack invariant */ - getLoader(), + getLoader(Reflection.getCallerClass()), control); } @@ -1721,8 +1717,9 @@ * @since 1.6 * @see ResourceBundle.Control#getTimeToLive(String,Locale) */ + @CallerSensitive public static final void clearCache() { - clearCache(getLoader()); + clearCache(getLoader(Reflection.getCallerClass())); } /**
--- a/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Wed Apr 17 02:53:02 2013 -0700 @@ -34,6 +34,7 @@ */ package java.util.concurrent; +import java.io.ObjectInputStream; import java.util.concurrent.locks.*; import java.util.*; import java.io.Serializable; @@ -1483,7 +1484,23 @@ @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - s.defaultReadObject(); + // Don't call defaultReadObject() + ObjectInputStream.GetField oisFields = s.readFields(); + final Segment<K,V>[] oisSegments = (Segment<K,V>[])oisFields.get("segments", null); + + final int ssize = oisSegments.length; + if (ssize < 1 || ssize > MAX_SEGMENTS + || (ssize & (ssize-1)) != 0 ) // ssize not power of two + throw new java.io.InvalidObjectException("Bad number of segments:" + + ssize); + int sshift = 0, ssizeTmp = ssize; + while (ssizeTmp > 1) { + ++sshift; + ssizeTmp >>>= 1; + } + UNSAFE.putIntVolatile(this, SEGSHIFT_OFFSET, 32 - sshift); + UNSAFE.putIntVolatile(this, SEGMASK_OFFSET, ssize - 1); + UNSAFE.putObjectVolatile(this, SEGMENTS_OFFSET, oisSegments); // set hashMask UNSAFE.putIntVolatile(this, HASHSEED_OFFSET, @@ -1517,6 +1534,9 @@ private static final long TBASE; private static final int TSHIFT; private static final long HASHSEED_OFFSET; + private static final long SEGSHIFT_OFFSET; + private static final long SEGMASK_OFFSET; + private static final long SEGMENTS_OFFSET; static { int ss, ts; @@ -1530,6 +1550,12 @@ ss = UNSAFE.arrayIndexScale(sc); HASHSEED_OFFSET = UNSAFE.objectFieldOffset( ConcurrentHashMap.class.getDeclaredField("hashSeed")); + SEGSHIFT_OFFSET = UNSAFE.objectFieldOffset( + ConcurrentHashMap.class.getDeclaredField("segmentShift")); + SEGMASK_OFFSET = UNSAFE.objectFieldOffset( + ConcurrentHashMap.class.getDeclaredField("segmentMask")); + SEGMENTS_OFFSET = UNSAFE.objectFieldOffset( + ConcurrentHashMap.class.getDeclaredField("segments")); } catch (Exception e) { throw new Error(e); }
--- a/src/share/classes/java/util/concurrent/ConcurrentMap.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/concurrent/ConcurrentMap.java Wed Apr 17 02:53:02 2013 -0700 @@ -38,7 +38,7 @@ /** * A {@link java.util.Map} providing additional atomic - * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods. + * {@code putIfAbsent}, {@code remove}, and {@code replace} methods. * * <p>Memory consistency effects: As with other concurrent * collections, actions in a thread prior to placing an object into a @@ -57,6 +57,21 @@ * @param <V> the type of mapped values */ public interface ConcurrentMap<K, V> extends Map<K, V> { + + /** + * {@inheritDoc} + * + * @implNote This implementation assumes that the ConcurrentMap cannot + * contain null values and get() returning null unambiguously means the key + * is absent. Implementations which support null values must override this + * default implementation. + */ + @Override + default V getOrDefault(Object key, V defaultValue) { + V v; + return ((v = get(key)) != null) ? v : defaultValue; + } + /** * If the specified key is not already associated * with a value, associate it with the given value. @@ -91,7 +106,7 @@ * Removes the entry for a key only if currently mapped to a given value. * This is equivalent to * <pre> {@code - * if (map.containsKey(key) && map.get(key).equals(value)) { + * if (map.containsKey(key) && Objects.equals(map.get(key), value)) { * map.remove(key); * return true; * } else @@ -101,8 +116,8 @@ * * @param key key with which the specified value is associated * @param value value expected to be associated with the specified key - * @return <tt>true</tt> if the value was removed - * @throws UnsupportedOperationException if the <tt>remove</tt> operation + * @return {@code true} if the value was removed + * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this map * @throws ClassCastException if the key or value is of an inappropriate * type for this map @@ -117,7 +132,7 @@ * Replaces the entry for a key only if currently mapped to a given value. * This is equivalent to * <pre> {@code - * if (map.containsKey(key) && map.get(key).equals(oldValue)) { + * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) { * map.put(key, newValue); * return true; * } else @@ -128,8 +143,8 @@ * @param key key with which the specified value is associated * @param oldValue value expected to be associated with the specified key * @param newValue value to be associated with the specified key - * @return <tt>true</tt> if the value was replaced - * @throws UnsupportedOperationException if the <tt>put</tt> operation + * @return {@code true} if the value was replaced + * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map * @throws ClassCastException if the class of a specified key or value * prevents it from being stored in this map @@ -154,11 +169,11 @@ * @param key key with which the specified value is associated * @param value value to be associated with the specified key * @return the previous value associated with the specified key, or - * <tt>null</tt> if there was no mapping for the key. - * (A <tt>null</tt> return can also indicate that the map - * previously associated <tt>null</tt> with the key, + * {@code null} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, * if the implementation supports null values.) - * @throws UnsupportedOperationException if the <tt>put</tt> operation + * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map
--- a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Wed Apr 17 02:53:02 2013 -0700 @@ -37,6 +37,9 @@ import java.util.function.IntUnaryOperator; import java.util.function.IntBinaryOperator; import sun.misc.Unsafe; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.AccessController; @@ -77,8 +80,9 @@ * or the field is inaccessible to the caller according to Java language * access control */ + @CallerSensitive public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { - return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName); + return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass()); } /** @@ -365,9 +369,11 @@ private final Class<T> tclass; private final Class<?> cclass; - AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName) { + AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, + final String fieldName, + final Class<?> caller) + { final Field field; - final Class<?> caller; final int modifiers; try { field = AccessController.doPrivileged( @@ -376,7 +382,6 @@ return tclass.getDeclaredField(fieldName); } }); - caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers);
--- a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Wed Apr 17 02:53:02 2013 -0700 @@ -37,6 +37,9 @@ import java.util.function.LongUnaryOperator; import java.util.function.LongBinaryOperator; import sun.misc.Unsafe; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.AccessController; @@ -77,11 +80,13 @@ * or the field is inaccessible to the caller according to Java language * access control */ + @CallerSensitive public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { + Class<?> caller = Reflection.getCallerClass(); if (AtomicLong.VM_SUPPORTS_LONG_CAS) - return new CASUpdater<U>(tclass, fieldName); + return new CASUpdater<U>(tclass, fieldName, caller); else - return new LockedUpdater<U>(tclass, fieldName); + return new LockedUpdater<U>(tclass, fieldName, caller); } /** @@ -365,9 +370,8 @@ private final Class<T> tclass; private final Class<?> cclass; - CASUpdater(final Class<T> tclass, final String fieldName) { + CASUpdater(final Class<T> tclass, final String fieldName, final Class<?> caller) { final Field field; - final Class<?> caller; final int modifiers; try { field = AccessController.doPrivileged( @@ -376,7 +380,6 @@ return tclass.getDeclaredField(fieldName); } }); - caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); @@ -490,9 +493,8 @@ private final Class<T> tclass; private final Class<?> cclass; - LockedUpdater(final Class<T> tclass, final String fieldName) { + LockedUpdater(final Class<T> tclass, final String fieldName, final Class<?> caller) { Field field = null; - Class<?> caller = null; int modifiers = 0; try { field = AccessController.doPrivileged( @@ -501,7 +503,6 @@ return tclass.getDeclaredField(fieldName); } }); - caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers);
--- a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Wed Apr 17 02:53:02 2013 -0700 @@ -37,6 +37,9 @@ import java.util.function.UnaryOperator; import java.util.function.BinaryOperator; import sun.misc.Unsafe; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.AccessController; @@ -96,10 +99,12 @@ * or the field is inaccessible to the caller according to Java language * access control */ + @CallerSensitive public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) { return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass, vclass, - fieldName); + fieldName, + Reflection.getCallerClass()); } /** @@ -297,10 +302,11 @@ AtomicReferenceFieldUpdaterImpl(final Class<T> tclass, Class<V> vclass, - final String fieldName) { + final String fieldName, + final Class<?> caller) + { final Field field; final Class<?> fieldClass; - final Class<?> caller; final int modifiers; try { field = AccessController.doPrivileged( @@ -309,7 +315,6 @@ return tclass.getDeclaredField(fieldName); } }); - caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers);
--- a/src/share/classes/java/util/logging/Logger.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/java/util/logging/Logger.java Wed Apr 17 02:53:02 2013 -0700 @@ -36,6 +36,8 @@ import java.util.ResourceBundle; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; /** * A Logger object is used to log messages for a specific @@ -333,13 +335,10 @@ } } - private static Logger demandLogger(String name, String resourceBundleName) { + private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { LogManager manager = LogManager.getLogManager(); SecurityManager sm = System.getSecurityManager(); if (sm != null && !SystemLoggerHelper.disableCallerCheck) { - // 0: Reflection 1: Logger.demandLogger 2: Logger.getLogger 3: caller - final int SKIP_FRAMES = 3; - Class<?> caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES); if (caller.getClassLoader() == null) { return manager.demandSystemLogger(name, resourceBundleName); } @@ -377,6 +376,7 @@ // Synchronization is not required here. All synchronization for // adding a new Logger object is handled by LogManager.addLogger(). + @CallerSensitive public static Logger getLogger(String name) { // This method is intentionally not a wrapper around a call // to getLogger(name, resourceBundleName). If it were then @@ -388,7 +388,7 @@ // would throw an IllegalArgumentException in the second call // because the wrapper would result in an attempt to replace // the existing "resourceBundleForFoo" with null. - return demandLogger(name, null); + return demandLogger(name, null, Reflection.getCallerClass()); } /** @@ -434,8 +434,9 @@ // Synchronization is not required here. All synchronization for // adding a new Logger object is handled by LogManager.addLogger(). + @CallerSensitive public static Logger getLogger(String name, String resourceBundleName) { - Logger result = demandLogger(name, resourceBundleName); + Logger result = demandLogger(name, resourceBundleName, Reflection.getCallerClass()); // MissingResourceException or IllegalArgumentException can be // thrown by setupResourceInfo().
--- a/src/share/classes/javax/script/ScriptEngineManager.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/javax/script/ScriptEngineManager.java Wed Apr 17 02:53:02 2013 -0700 @@ -28,6 +28,7 @@ import java.security.*; import java.util.ServiceLoader; import java.util.ServiceConfigurationError; +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; @@ -60,9 +61,10 @@ * * @see java.lang.Thread#getContextClassLoader */ + @CallerSensitive public ScriptEngineManager() { ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader(); - if (canCallerAccessLoader(ctxtLoader)) { + if (canCallerAccessLoader(ctxtLoader, Reflection.getCallerClass())) { if (DEBUG) System.out.println("using " + ctxtLoader); init(ctxtLoader); } else { @@ -419,10 +421,10 @@ /** Global bindings associated with script engines created by this manager. */ private Bindings globalScope; - private boolean canCallerAccessLoader(ClassLoader loader) { + private boolean canCallerAccessLoader(ClassLoader loader, Class<?> caller) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - ClassLoader callerLoader = getCallerClassLoader(); + ClassLoader callerLoader = getClassLoader(caller); if (!sun.misc.VM.isSystemDomainLoader(callerLoader)) { if (loader != callerLoader || !isAncestor(loader, callerLoader)) { try { @@ -438,10 +440,9 @@ return true; } - // Note that this code is same as ClassLoader.getCallerClassLoader(). + // Note that this code is same as ClassLoader.getClassLoader(). // But, that method is package private and hence we can't call here. - private ClassLoader getCallerClassLoader() { - Class<?> caller = Reflection.getCallerClass(3); + private ClassLoader getClassLoader(Class<?> caller) { if (caller == null) { return null; }
--- a/src/share/classes/sun/awt/EmbeddedFrame.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/awt/EmbeddedFrame.java Wed Apr 17 02:53:02 2013 -0700 @@ -539,7 +539,7 @@ public void toBack() {} public void updateFocusableWindowState() {} public void updateAlwaysOnTop() {} - public void setAlwaysOnTop(boolean alwaysOnTop) {} + public void updateAlwaysOnTopState() {} public Component getGlobalHeavyweightFocusOwner() { return null; } public void setBoundsPrivate(int x, int y, int width, int height) { setBounds(x, y, width, height, SET_BOUNDS);
--- a/src/share/classes/sun/awt/datatransfer/TransferableProxy.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/awt/datatransfer/TransferableProxy.java Wed Apr 17 02:53:02 2013 -0700 @@ -102,11 +102,11 @@ protected final boolean isLocal; } -class ClassLoaderObjectOutputStream extends ObjectOutputStream { +final class ClassLoaderObjectOutputStream extends ObjectOutputStream { private final Map<Set<String>, ClassLoader> map = new HashMap<Set<String>, ClassLoader>(); - public ClassLoaderObjectOutputStream(OutputStream os) throws IOException { + ClassLoaderObjectOutputStream(OutputStream os) throws IOException { super(os); } @@ -140,16 +140,16 @@ map.put(s, classLoader); } - public Map<Set<String>, ClassLoader> getClassLoaderMap() { + Map<Set<String>, ClassLoader> getClassLoaderMap() { return new HashMap(map); } } -class ClassLoaderObjectInputStream extends ObjectInputStream { +final class ClassLoaderObjectInputStream extends ObjectInputStream { private final Map<Set<String>, ClassLoader> map; - public ClassLoaderObjectInputStream(InputStream is, - Map<Set<String>, ClassLoader> map) + ClassLoaderObjectInputStream(InputStream is, + Map<Set<String>, ClassLoader> map) throws IOException { super(is); if (map == null) { @@ -166,8 +166,11 @@ s.add(className); ClassLoader classLoader = map.get(s); - - return Class.forName(className, false, classLoader); + if (classLoader != null) { + return Class.forName(className, false, classLoader); + } else { + return super.resolveClass(classDesc); + } } protected Class<?> resolveProxyClass(String[] interfaces) @@ -179,6 +182,9 @@ } ClassLoader classLoader = map.get(s); + if (classLoader == null) { + return super.resolveProxyClass(interfaces); + } // The code below is mostly copied from the superclass. ClassLoader nonPublicLoader = null;
--- a/src/share/classes/sun/awt/image/ByteComponentRaster.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/awt/image/ByteComponentRaster.java Wed Apr 17 02:53:02 2013 -0700 @@ -868,6 +868,15 @@ * or if data buffer has not enough capacity. */ protected final void verify() { + /* Need to re-verify the dimensions since a sample model may be + * specified to the constructor + */ + if (width <= 0 || height <= 0 || + height > (Integer.MAX_VALUE / width)) + { + throw new RasterFormatException("Invalid raster dimension"); + } + for (int i = 0; i < dataOffsets.length; i++) { if (dataOffsets[i] < 0) { throw new RasterFormatException("Data offsets for band " + i @@ -905,13 +914,14 @@ lastPixelOffset += lastScanOffset; for (int i = 0; i < numDataElements; i++) { - size = lastPixelOffset + dataOffsets[i]; if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { throw new RasterFormatException("Incorrect band offset: " + dataOffsets[i]); } + size = lastPixelOffset + dataOffsets[i]; + if (size > maxSize) { maxSize = size; }
--- a/src/share/classes/sun/awt/image/BytePackedRaster.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/awt/image/BytePackedRaster.java Wed Apr 17 02:53:02 2013 -0700 @@ -1368,11 +1368,35 @@ throw new RasterFormatException("Data offsets must be >= 0"); } + /* Need to re-verify the dimensions since a sample model may be + * specified to the constructor + */ + if (width <= 0 || height <= 0 || + height > (Integer.MAX_VALUE / width)) + { + throw new RasterFormatException("Invalid raster dimension"); + } + + + /* + * pixelBitstride was verified in constructor, so just make + * sure that it is safe to multiply it by width. + */ + if ((width - 1) > Integer.MAX_VALUE / pixelBitStride) { + throw new RasterFormatException("Invalid raster dimension"); + } + + if (scanlineStride < 0 || + scanlineStride > (Integer.MAX_VALUE / height)) + { + throw new RasterFormatException("Invalid scanline stride"); + } + int lastbit = (dataBitOffset + (height-1) * scanlineStride * 8 + (width-1) * pixelBitStride + pixelBitStride - 1); - if (lastbit / 8 >= data.length) { + if (lastbit < 0 || lastbit / 8 >= data.length) { throw new RasterFormatException("raster dimensions overflow " + "array bounds"); }
--- a/src/share/classes/sun/awt/image/ImageRepresentation.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/awt/image/ImageRepresentation.java Wed Apr 17 02:53:02 2013 -0700 @@ -333,10 +333,10 @@ hints = h; } - private native void setICMpixels(int x, int y, int w, int h, int[] lut, + private native boolean setICMpixels(int x, int y, int w, int h, int[] lut, byte[] pix, int off, int scansize, IntegerComponentRaster ict); - private native int setDiffICM(int x, int y, int w, int h, int[] lut, + private native boolean setDiffICM(int x, int y, int w, int h, int[] lut, int transPix, int numLut, IndexColorModel icm, byte[] pix, int off, int scansize, ByteComponentRaster bct, int chanOff); @@ -426,10 +426,10 @@ IndexColorModel icm = (IndexColorModel) model; ByteComponentRaster bct = (ByteComponentRaster) biRaster; int numlut = numSrcLUT; - if (setDiffICM(x, y, w, h, srcLUT, srcLUTtransIndex, + if (!setDiffICM(x, y, w, h, srcLUT, srcLUTtransIndex, numSrcLUT, icm, pix, off, scansize, bct, - bct.getDataOffset(0)) == 0) { + bct.getDataOffset(0))) { convertToRGB(); } else { @@ -470,9 +470,14 @@ if (s_useNative) { // Note that setICMpixels modifies the raster directly // so we must mark it as changed afterwards - setICMpixels(x, y, w, h, srcLUT, pix, off, scansize, - iraster); - iraster.markDirty(); + if (setICMpixels(x, y, w, h, srcLUT, pix, off, scansize, + iraster)) + { + iraster.markDirty(); + } else { + abort(); + return; + } } else { int[] storage = new int[w*h];
--- a/src/share/classes/sun/awt/image/IntegerComponentRaster.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/awt/image/IntegerComponentRaster.java Wed Apr 17 02:53:02 2013 -0700 @@ -208,7 +208,7 @@ " SinglePixelPackedSampleModel"); } - verify(false); + verify(); } @@ -629,16 +629,26 @@ } /** - * Verify that the layout parameters are consistent with - * the data. If strictCheck - * is false, this method will check for ArrayIndexOutOfBounds conditions. If - * strictCheck is true, this method will check for additional error - * conditions such as line wraparound (width of a line greater than - * the scanline stride). - * @return String Error string, if the layout is incompatible with - * the data. Otherwise returns null. + * Verify that the layout parameters are consistent with the data. + * + * The method verifies whether scanline stride and pixel stride do not + * cause an integer overflow during calculation of a position of the pixel + * in data buffer. It also verifies whether the data buffer has enough data + * to correspond the raster layout attributes. + * + * @throws RasterFormatException if an integer overflow is detected, + * or if data buffer has not enough capacity. */ - private void verify (boolean strictCheck) { + protected final void verify() { + /* Need to re-verify the dimensions since a sample model may be + * specified to the constructor + */ + if (width <= 0 || height <= 0 || + height > (Integer.MAX_VALUE / width)) + { + throw new RasterFormatException("Invalid raster dimension"); + } + if (dataOffsets[0] < 0) { throw new RasterFormatException("Data offset ("+dataOffsets[0]+ ") must be >= 0"); @@ -647,17 +657,46 @@ int maxSize = 0; int size; - for (int i=0; i < numDataElements; i++) { - size = (height-1)*scanlineStride + (width-1)*pixelStride + - dataOffsets[i]; + // we can be sure that width and height are greater than 0 + if (scanlineStride < 0 || + scanlineStride > (Integer.MAX_VALUE / height)) + { + // integer overflow + throw new RasterFormatException("Incorrect scanline stride: " + + scanlineStride); + } + int lastScanOffset = (height - 1) * scanlineStride; + + if (pixelStride < 0 || + pixelStride > (Integer.MAX_VALUE / width)) + { + // integer overflow + throw new RasterFormatException("Incorrect pixel stride: " + + pixelStride); + } + int lastPixelOffset = (width - 1) * pixelStride; + + if (lastPixelOffset > (Integer.MAX_VALUE - lastScanOffset)) { + // integer overflow + throw new RasterFormatException("Incorrect raster attributes"); + } + lastPixelOffset += lastScanOffset; + + for (int i = 0; i < numDataElements; i++) { + if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { + throw new RasterFormatException("Incorrect band offset: " + + dataOffsets[i]); + } + + size = lastPixelOffset + dataOffsets[i]; + if (size > maxSize) { maxSize = size; } } if (data.length < maxSize) { - throw new RasterFormatException("Data array too small (should be "+ - maxSize - +" but is "+data.length+" )"); + throw new RasterFormatException("Data array too small (should be " + + maxSize + " )"); } }
--- a/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java Wed Apr 17 02:53:02 2013 -0700 @@ -151,7 +151,7 @@ throw new RasterFormatException("IntegerInterleavedRasters must have"+ " SinglePixelPackedSampleModel"); } - verify(false); + verify(); } @@ -540,31 +540,6 @@ return createCompatibleWritableRaster(width,height); } - /** - * Verify that the layout parameters are consistent with - * the data. If strictCheck - * is false, this method will check for ArrayIndexOutOfBounds conditions. If - * strictCheck is true, this method will check for additional error - * conditions such as line wraparound (width of a line greater than - * the scanline stride). - * @return String Error string, if the layout is incompatible with - * the data. Otherwise returns null. - */ - private void verify (boolean strictCheck) { - int maxSize = 0; - int size; - - size = (height-1)*scanlineStride + (width-1) + dataOffsets[0]; - if (size > maxSize) { - maxSize = size; - } - if (data.length < maxSize) { - throw new RasterFormatException("Data array too small (should be "+ - maxSize - +" but is "+data.length+" )"); - } - } - public String toString() { return new String ("IntegerInterleavedRaster: width = "+width +" height = " + height
--- a/src/share/classes/sun/awt/image/ShortComponentRaster.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/awt/image/ShortComponentRaster.java Wed Apr 17 02:53:02 2013 -0700 @@ -802,6 +802,15 @@ * or if data buffer has not enough capacity. */ protected final void verify() { + /* Need to re-verify the dimensions since a sample model may be + * specified to the constructor + */ + if (width <= 0 || height <= 0 || + height > (Integer.MAX_VALUE / width)) + { + throw new RasterFormatException("Invalid raster dimension"); + } + for (int i = 0; i < dataOffsets.length; i++) { if (dataOffsets[i] < 0) { throw new RasterFormatException("Data offsets for band " + i @@ -839,12 +848,13 @@ lastPixelOffset += lastScanOffset; for (int i = 0; i < numDataElements; i++) { - size = lastPixelOffset + dataOffsets[i]; if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { throw new RasterFormatException("Incorrect band offset: " + dataOffsets[i]); } + size = lastPixelOffset + dataOffsets[i]; + if (size > maxSize) { maxSize = size; }
--- a/src/share/classes/sun/font/CMap.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/font/CMap.java Wed Apr 17 02:53:02 2013 -0700 @@ -841,7 +841,6 @@ CMapFormat6(ByteBuffer bbuffer, int offset, char[] xlat) { - System.err.println("WARNING: CMapFormat8 is untested."); bbuffer.position(offset+6); CharBuffer buffer = bbuffer.asCharBuffer(); firstCode = buffer.get(); @@ -884,7 +883,6 @@ CMapFormat8(ByteBuffer bbuffer, int offset, char[] xlat) { - System.err.println("WARNING: CMapFormat8 is untested."); bbuffer.position(12); bbuffer.get(is32); nGroups = bbuffer.getInt(); @@ -915,7 +913,6 @@ CMapFormat10(ByteBuffer bbuffer, int offset, char[] xlat) { - System.err.println("WARNING: CMapFormat10 is untested."); firstCode = bbuffer.getInt() & INTMASK; entryCount = bbuffer.getInt() & INTMASK; bbuffer.position(offset+20);
--- a/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Wed Apr 17 02:53:02 2013 -0700 @@ -85,45 +85,72 @@ private boolean imageAtOnce = false; Object dataArray; - private LCMSImageLayout(int np, int pixelType, int pixelSize) { + private int dataArrayLength; /* in bytes */ + + private LCMSImageLayout(int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this.pixelType = pixelType; width = np; height = 1; - nextRowOffset = np * pixelSize; + nextRowOffset = safeMult(pixelSize, np); offset = 0; } private LCMSImageLayout(int width, int height, int pixelType, - int pixelSize) { + int pixelSize) + throws ImageLayoutException + { this.pixelType = pixelType; this.width = width; this.height = height; - nextRowOffset = width * pixelSize; + nextRowOffset = safeMult(pixelSize, width); offset = 0; } - public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) { + + public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this(np, pixelType, pixelSize); dataType = DT_BYTE; dataArray = data; + dataArrayLength = data.length; + + verify(); } - public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) { + public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this(np, pixelType, pixelSize); dataType = DT_SHORT; dataArray = data; + dataArrayLength = 2 * data.length; + + verify(); } - public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) { + public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this(np, pixelType, pixelSize); dataType = DT_INT; dataArray = data; + dataArrayLength = 4 * data.length; + + verify(); } - public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) { + public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this(np, pixelType, pixelSize); dataType = DT_DOUBLE; dataArray = data; + dataArrayLength = 8 * data.length; + + verify(); } private LCMSImageLayout() { @@ -132,7 +159,7 @@ /* This method creates a layout object for given image. * Returns null if the image is not supported by current implementation. */ - public static LCMSImageLayout createImageLayout(BufferedImage image) { + public static LCMSImageLayout createImageLayout(BufferedImage image) throws ImageLayoutException { LCMSImageLayout l = new LCMSImageLayout(); switch (image.getType()) { @@ -193,9 +220,10 @@ do { IntegerComponentRaster intRaster = (IntegerComponentRaster) image.getRaster(); - l.nextRowOffset = intRaster.getScanlineStride() * 4; - l.offset = intRaster.getDataOffset(0) * 4; + l.nextRowOffset = safeMult(4, intRaster.getScanlineStride()); + l.offset = safeMult(4, intRaster.getDataOffset(0)); l.dataArray = intRaster.getDataStorage(); + l.dataArrayLength = 4 * intRaster.getDataStorage().length; l.dataType = DT_INT; if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) { @@ -213,6 +241,7 @@ int firstBand = image.getSampleModel().getNumBands() - 1; l.offset = byteRaster.getDataOffset(firstBand); l.dataArray = byteRaster.getDataStorage(); + l.dataArrayLength = byteRaster.getDataStorage().length; l.dataType = DT_BYTE; if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) { l.imageAtOnce = true; @@ -225,6 +254,7 @@ ByteComponentRaster byteRaster = (ByteComponentRaster) image.getRaster(); l.nextRowOffset = byteRaster.getScanlineStride(); + l.dataArrayLength = byteRaster.getDataStorage().length; l.offset = byteRaster.getDataOffset(0); l.dataArray = byteRaster.getDataStorage(); l.dataType = DT_BYTE; @@ -239,9 +269,10 @@ do { ShortComponentRaster shortRaster = (ShortComponentRaster) image.getRaster(); - l.nextRowOffset = shortRaster.getScanlineStride() * 2; - l.offset = shortRaster.getDataOffset(0) * 2; + l.nextRowOffset = safeMult(2, shortRaster.getScanlineStride()); + l.offset = safeMult(2, shortRaster.getDataOffset(0)); l.dataArray = shortRaster.getDataStorage(); + l.dataArrayLength = 2 * shortRaster.getDataStorage().length; l.dataType = DT_SHORT; if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) { @@ -252,6 +283,7 @@ default: return null; } + l.verify(); return l; } @@ -293,6 +325,46 @@ } } + private void verify() throws ImageLayoutException { + + if (offset < 0 || offset >= dataArrayLength) { + throw new ImageLayoutException("Invalid image layout"); + } + + int lastPixelOffset = safeMult(nextRowOffset, (height - 1)); + + lastPixelOffset = safeAdd(lastPixelOffset, (width - 1)); + + int off = safeAdd(offset, lastPixelOffset); + + if (off < 0 || off >= dataArrayLength) { + throw new ImageLayoutException("Invalid image layout"); + } + } + + static int safeAdd(int a, int b) throws ImageLayoutException { + long res = a; + res += b; + if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) { + throw new ImageLayoutException("Invalid image layout"); + } + return (int)res; + } + + static int safeMult(int a, int b) throws ImageLayoutException { + long res = a; + res *= b; + if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) { + throw new ImageLayoutException("Invalid image layout"); + } + return (int)res; + } + + public static class ImageLayoutException extends Exception { + public ImageLayoutException(String message) { + super(message); + } + } public static LCMSImageLayout createImageLayout(Raster r) { LCMSImageLayout l = new LCMSImageLayout(); if (r instanceof ByteComponentRaster) {
--- a/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Wed Apr 17 02:53:02 2013 -0700 @@ -51,6 +51,7 @@ import java.awt.image.ComponentSampleModel; import sun.java2d.cmm.*; import sun.java2d.cmm.lcms.*; +import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException; public class LCMSTransform implements ColorTransform { @@ -162,15 +163,19 @@ public void colorConvert(BufferedImage src, BufferedImage dst) { LCMSImageLayout srcIL, dstIL; + try { - dstIL = LCMSImageLayout.createImageLayout(dst); + dstIL = LCMSImageLayout.createImageLayout(dst); - if (dstIL != null) { - srcIL = LCMSImageLayout.createImageLayout(src); - if (srcIL != null) { - doTransform(srcIL, dstIL); - return; + if (dstIL != null) { + srcIL = LCMSImageLayout.createImageLayout(src); + if (srcIL != null) { + doTransform(srcIL, dstIL); + return; + } } + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert images"); } Raster srcRas = src.getRaster(); @@ -228,14 +233,18 @@ } int idx; // TODO check for src npixels = dst npixels - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumInComponents()); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert images"); + } // process each scanline for (int y = 0; y < h; y++) { // convert src scanline @@ -284,16 +293,19 @@ alpha = new float[w]; } int idx; - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); - + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert images"); + } // process each scanline for (int y = 0; y < h; y++) { // convert src scanline @@ -402,16 +414,19 @@ short[] srcLine = new short[w * srcNumBands]; short[] dstLine = new short[w * dstNumBands]; int idx; - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); - + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert rasters"); + } // process each scanline for (int y = 0; y < h; y++, ys++, yd++) { // get src scanline @@ -502,15 +517,18 @@ byte[] dstLine = new byte[w * dstNumBands]; int idx; // TODO check for src npixels = dst npixels - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumInComponents()); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); - + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert rasters"); + } // process each scanline for (int y = 0; y < h; y++, ys++, yd++) { // get src scanline @@ -542,16 +560,20 @@ short[] srcLine = new short[w * srcNumBands]; short[] dstLine = new short[w * dstNumBands]; int idx; - srcIL = new LCMSImageLayout( - srcLine, srcLine.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); + + try { + srcIL = new LCMSImageLayout( + srcLine, srcLine.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); - + dstIL = new LCMSImageLayout( + dstLine, dstLine.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert rasters"); + } // process each scanline for (int y = 0; y < h; y++, ys++, yd++) { // get src scanline @@ -592,19 +614,23 @@ dst = new short [(src.length/getNumInComponents())*getNumOutComponents()]; } - LCMSImageLayout srcIL = new LCMSImageLayout( - src, src.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); + try { + LCMSImageLayout srcIL = new LCMSImageLayout( + src, src.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); - LCMSImageLayout dstIL = new LCMSImageLayout( - dst, dst.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); + LCMSImageLayout dstIL = new LCMSImageLayout( + dst, dst.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); - doTransform(srcIL, dstIL); + doTransform(srcIL, dstIL); - return dst; + return dst; + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert data"); + } } public byte[] colorConvert(byte[] src, byte[] dst) { @@ -612,18 +638,22 @@ dst = new byte [(src.length/getNumInComponents())*getNumOutComponents()]; } - LCMSImageLayout srcIL = new LCMSImageLayout( - src, src.length/getNumInComponents(), - LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumInComponents()); + try { + LCMSImageLayout srcIL = new LCMSImageLayout( + src, src.length/getNumInComponents(), + LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumInComponents()); - LCMSImageLayout dstIL = new LCMSImageLayout( - dst, dst.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); + LCMSImageLayout dstIL = new LCMSImageLayout( + dst, dst.length/getNumOutComponents(), + LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | + LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); - doTransform(srcIL, dstIL); + doTransform(srcIL, dstIL); - return dst; + return dst; + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert data"); + } } }
--- a/src/share/classes/sun/misc/Unsafe.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/misc/Unsafe.java Wed Apr 17 02:53:02 2013 -0700 @@ -28,6 +28,9 @@ import java.security.*; import java.lang.reflect.*; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + /** * A collection of methods for performing low-level, unsafe operations. @@ -80,9 +83,10 @@ * <code>checkPropertiesAccess</code> method doesn't allow * access to the system properties. */ + @CallerSensitive public static Unsafe getUnsafe() { - Class<?> cc = sun.reflect.Reflection.getCallerClass(2); - if (!VM.isSystemDomainLoader(cc.getClassLoader())) + Class<?> caller = Reflection.getCallerClass(); + if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; } @@ -817,8 +821,6 @@ ClassLoader loader, ProtectionDomain protectionDomain); - public native Class<?> defineClass(String name, byte[] b, int off, int len); - /** * Define a class but do not make it known to the class loader or system dictionary. * <p>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/reflect/CallerSensitive.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.reflect; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +/** + * A method annotated @CallerSensitive is sensitive to its calling class, + * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass}, + * or via some equivalent. + * + * @author John R. Rose + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({CONSTRUCTOR, METHOD}) +public @interface CallerSensitive { +}
--- a/src/share/classes/sun/reflect/Reflection.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/reflect/Reflection.java Wed Apr 17 02:53:02 2013 -0700 @@ -51,16 +51,11 @@ methodFilterMap = new HashMap<>(); } - /** Returns the class of the method <code>realFramesToSkip</code> - frames up the stack (zero-based), ignoring frames associated - with java.lang.reflect.Method.invoke() and its implementation. - The first frame is that associated with this method, so - <code>getCallerClass(0)</code> returns the Class object for - sun.reflect.Reflection. Frames associated with - java.lang.reflect.Method.invoke() and its implementation are - completely ignored and do not count toward the number of "real" - frames skipped. */ - public static native Class<?> getCallerClass(int realFramesToSkip); + /** Returns the class of the caller of the method calling this method, + ignoring frames associated with java.lang.reflect.Method.invoke() + and its implementation. */ + @CallerSensitive + public static native Class<?> getCallerClass(); /** Retrieves the access flags written to the class file. For inner classes these flags may differ from those returned by @@ -321,4 +316,27 @@ } return newMembers; } + + /** + * Tests if the given method is caller-sensitive and the declaring class + * is defined by either the bootstrap class loader or extension class loader. + */ + public static boolean isCallerSensitive(Method m) { + final ClassLoader loader = m.getDeclaringClass().getClassLoader(); + if (sun.misc.VM.isSystemDomainLoader(loader) || isExtClassLoader(loader)) { + return m.isAnnotationPresent(CallerSensitive.class); + } + return false; + } + + private static boolean isExtClassLoader(ClassLoader loader) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + while (cl != null) { + if (cl.getParent() == null && cl == loader) { + return true; + } + cl = cl.getParent(); + } + return false; + } }
--- a/src/share/classes/sun/reflect/misc/MethodUtil.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/reflect/misc/MethodUtil.java Wed Apr 17 02:53:02 2013 -0700 @@ -46,8 +46,28 @@ class Trampoline { + static { + if (Trampoline.class.getClassLoader() == null) { + throw new Error( + "Trampoline must not be defined by the bootstrap classloader"); + } + } + + private static void ensureInvocableMethod(Method m) + throws InvocationTargetException + { + Class<?> clazz = m.getDeclaringClass(); + if (clazz.equals(AccessController.class) || + clazz.equals(Method.class) || + clazz.getName().startsWith("java.lang.invoke.")) + throw new InvocationTargetException( + new UnsupportedOperationException("invocation not supported")); + } + private static Object invoke(Method m, Object obj, Object[] params) - throws InvocationTargetException, IllegalAccessException { + throws InvocationTargetException, IllegalAccessException + { + ensureInvocableMethod(m); return m.invoke(obj, params); } } @@ -251,16 +271,6 @@ */ public static Object invoke(Method m, Object obj, Object[] params) throws InvocationTargetException, IllegalAccessException { - if (m.getDeclaringClass().equals(AccessController.class) || - (m.getDeclaringClass().equals(java.lang.invoke.MethodHandles.class) - && m.getName().equals("lookup")) || - (m.getDeclaringClass().equals(java.lang.invoke.MethodHandles.Lookup.class) - && (m.getName().startsWith("find") || - m.getName().startsWith("bind") || - m.getName().startsWith("unreflect"))) || - m.getDeclaringClass().equals(Method.class)) - throw new InvocationTargetException( - new UnsupportedOperationException("invocation not supported")); try { return bounce.invoke(null, new Object[] {m, obj, params}); } catch (InvocationTargetException ie) { @@ -293,10 +303,10 @@ Method.class, Object.class, Object[].class }; Method b = t.getDeclaredMethod("invoke", types); - ((AccessibleObject)b).setAccessible(true); - return b; - } - }); + b.setAccessible(true); + return b; + } + }); } catch (Exception e) { throw new InternalError("bouncer cannot be found", e); }
--- a/src/share/classes/sun/rmi/server/MarshalInputStream.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/rmi/server/MarshalInputStream.java Wed Apr 17 02:53:02 2013 -0700 @@ -55,13 +55,19 @@ public class MarshalInputStream extends ObjectInputStream { /** - * value of "java.rmi.server.useCodebaseOnly" property, + * Value of "java.rmi.server.useCodebaseOnly" property, * as cached at class initialization time. + * + * The default value is true. That is, the value is true + * if the property is absent or is not equal to "false". + * The value is only false when the property is present + * and is equal to "false". */ private static final boolean useCodebaseOnlyProperty = - java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "java.rmi.server.useCodebaseOnly")).booleanValue(); + ! java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction( + "java.rmi.server.useCodebaseOnly", "true")) + .equalsIgnoreCase("false"); /** table to hold sun classes to which access is explicitly permitted */ protected static Map<String, Class<?>> permittedSunClasses
--- a/src/share/classes/sun/security/krb5/KrbApReq.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/KrbApReq.java Wed Apr 17 02:53:02 2013 -0700 @@ -204,7 +204,7 @@ int usage) throws KrbException, IOException { - ctime = new KerberosTime(KerberosTime.NOW); + ctime = KerberosTime.now(); init(options, tgs_creds.ticket, tgs_creds.key, @@ -287,14 +287,14 @@ authenticator = new Authenticator(temp2); ctime = authenticator.ctime; cusec = authenticator.cusec; - authenticator.ctime.setMicroSeconds(authenticator.cusec); + authenticator.ctime = + authenticator.ctime.withMicroSeconds(authenticator.cusec); if (!authenticator.cname.equals(enc_ticketPart.cname)) { throw new KrbApErrException(Krb5.KRB_AP_ERR_BADMATCH); } - KerberosTime currTime = new KerberosTime(KerberosTime.NOW); - if (!authenticator.ctime.inClockSkew(currTime)) + if (!authenticator.ctime.inClockSkew()) throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); // start to check if it is a replay attack. @@ -304,7 +304,7 @@ if (table.get(time, authenticator.cname.toString()) != null) { throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT); } else { - table.put(client, time, currTime.getTime()); + table.put(client, time, System.currentTimeMillis()); } if (initiator != null) { @@ -329,7 +329,7 @@ // else // save authenticator to check for later - KerberosTime now = new KerberosTime(KerberosTime.NOW); + KerberosTime now = KerberosTime.now(); if ((enc_ticketPart.starttime != null && enc_ticketPart.starttime.greaterThanWRTClockSkew(now)) ||
--- a/src/share/classes/sun/security/krb5/KrbAppMessage.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/KrbAppMessage.java Wed Apr 17 02:53:02 2013 -0700 @@ -71,12 +71,18 @@ } if (packetTimestamp != null) { - packetTimestamp.setMicroSeconds(packetUsec); - if (!packetTimestamp.inClockSkew()) + if (packetUsec != null) { + packetTimestamp = + packetTimestamp.withMicroSeconds(packetUsec.intValue()); + } + if (!packetTimestamp.inClockSkew()) { throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); - } else - if (timestampRequired) + } + } else { + if (timestampRequired) { throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); + } + } // XXX check replay cache // if (rcache.repeated(packetTimestamp, packetUsec, packetSAddress))
--- a/src/share/classes/sun/security/krb5/KrbCred.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/KrbCred.java Wed Apr 17 02:53:02 2013 -0700 @@ -103,7 +103,7 @@ delegatedCreds.renewTill, tgService, delegatedCreds.cAddr); - timeStamp = new KerberosTime(KerberosTime.NOW); + timeStamp = KerberosTime.now(); KrbCredInfo[] credInfos = {credInfo}; EncKrbCredPart encPart = new EncKrbCredPart(credInfos,
--- a/src/share/classes/sun/security/krb5/KrbTgsReq.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/KrbTgsReq.java Wed Apr 17 02:53:02 2013 -0700 @@ -147,8 +147,7 @@ princName = cname; servName = sname; - ctime = new KerberosTime(KerberosTime.NOW); - + ctime = KerberosTime.now(); // check if they are valid arguments. The optional fields // should be consistent with settings in KDCOptions.
--- a/src/share/classes/sun/security/krb5/internal/KerberosTime.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/internal/KerberosTime.java Wed Apr 17 02:53:02 2013 -0700 @@ -30,18 +30,20 @@ package sun.security.krb5.internal; -import java.util.TimeZone; -import sun.security.util.*; +import sun.security.krb5.Asn1Exception; import sun.security.krb5.Config; import sun.security.krb5.KrbException; -import sun.security.krb5.Asn1Exception; +import sun.security.util.DerInputStream; +import sun.security.util.DerOutputStream; +import sun.security.util.DerValue; + +import java.io.IOException; +import java.util.Calendar; import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Calendar; -import java.io.IOException; +import java.util.TimeZone; /** - * Implements the ASN.1 KerberosTime type. + * Implements the ASN.1 KerberosTime type. This is an immutable class. * * <xmp> * KerberosTime ::= GeneralizedTime -- with no fractional seconds @@ -62,55 +64,38 @@ * same class can be used as a precise timestamp in Authenticator etc. */ -public class KerberosTime implements Cloneable { +public class KerberosTime { - private long kerberosTime; // milliseconds since epoch, a Date.getTime() value - private int microSeconds; // the last three digits of the microsecond value + private final long kerberosTime; // milliseconds since epoch, Date.getTime() + private final int microSeconds; // last 3 digits of the real microsecond // The time when this class is loaded. Used in setNow() private static long initMilli = System.currentTimeMillis(); private static long initMicro = System.nanoTime() / 1000; - private static long syncTime; private static boolean DEBUG = Krb5.DEBUG; - public static final boolean NOW = true; - public static final boolean UNADJUSTED_NOW = false; - - public KerberosTime(long time) { - kerberosTime = time; - } - + // Do not make this public. It's a little confusing that micro + // is only the last 3 digits of microsecond. private KerberosTime(long time, int micro) { kerberosTime = time; microSeconds = micro; } - public Object clone() { - return new KerberosTime(kerberosTime, microSeconds); + /** + * Creates a KerberosTime object from milliseconds since epoch. + */ + public KerberosTime(long time) { + this(time, 0); } // This constructor is used in the native code // src/windows/native/sun/security/krb5/NativeCreds.c public KerberosTime(String time) throws Asn1Exception { - kerberosTime = toKerberosTime(time); - } - - /** - * Constructs a KerberosTime object. - * @param encoding a DER-encoded data. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - public KerberosTime(DerValue encoding) throws Asn1Exception, IOException { - GregorianCalendar calendar = new GregorianCalendar(); - Date temp = encoding.getGeneralizedTime(); - kerberosTime = temp.getTime(); + this(toKerberosTime(time), 0); } private static long toKerberosTime(String time) throws Asn1Exception { - // this method only used by KerberosTime class. - // ASN.1 GeneralizedTime format: // "19700101000000Z" @@ -133,30 +118,34 @@ Integer.parseInt(time.substring(8, 10)), Integer.parseInt(time.substring(10, 12)), Integer.parseInt(time.substring(12, 14))); + return calendar.getTimeInMillis(); + } - //The Date constructor assumes the setting are local relative - //and converts the time to UTC before storing it. Since we - //want the internal representation to correspond to local - //and not UTC time we subtract the UTC time offset. - return (calendar.getTime().getTime()); - + /** + * Creates a KerberosTime object from a Date object. + */ + public KerberosTime(Date time) { + this(time.getTime(), 0); } - // should be moved to sun.security.krb5.util class - public static String zeroPad(String s, int length) { - StringBuffer temp = new StringBuffer(s); - while (temp.length() < length) - temp.insert(0, '0'); - return temp.toString(); - } - - public KerberosTime(Date time) { - kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L); - } - - public KerberosTime(boolean initToNow) { - if (initToNow) { - setNow(); + /** + * Creates a KerberosTime object for now. It uses System.nanoTime() + * to get a more precise time than "new Date()". + */ + public static KerberosTime now() { + long newMilli = System.currentTimeMillis(); + long newMicro = System.nanoTime() / 1000; + long microElapsed = newMicro - initMicro; + long calcMilli = initMilli + microElapsed/1000; + if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) { + if (DEBUG) { + System.out.println("System time adjusted"); + } + initMilli = newMilli; + initMicro = newMicro; + return new KerberosTime(newMilli, 0); + } else { + return new KerberosTime(calcMilli, (int)(microElapsed % 1000)); } } @@ -169,13 +158,13 @@ calendar.clear(); calendar.setTimeInMillis(kerberosTime); - return zeroPad(Integer.toString(calendar.get(Calendar.YEAR)), 4) + - zeroPad(Integer.toString(calendar.get(Calendar.MONTH) + 1), 2) + - zeroPad(Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)), 2) + - zeroPad(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)), 2) + - zeroPad(Integer.toString(calendar.get(Calendar.MINUTE)), 2) + - zeroPad(Integer.toString(calendar.get(Calendar.SECOND)), 2) + 'Z'; - + return String.format("%04d%02d%02d%02d%02d%02dZ", + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH) + 1, + calendar.get(Calendar.DAY_OF_MONTH), + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + calendar.get(Calendar.SECOND)); } /** @@ -194,40 +183,8 @@ return kerberosTime; } - - public void setTime(Date time) { - kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L); - microSeconds = 0; - } - - public void setTime(long time) { - kerberosTime = time; - microSeconds = 0; - } - public Date toDate() { - Date temp = new Date(kerberosTime); - temp.setTime(temp.getTime()); - return temp; - } - - public void setNow() { - long newMilli = System.currentTimeMillis(); - long newMicro = System.nanoTime() / 1000; - long microElapsed = newMicro - initMicro; - long calcMilli = initMilli + microElapsed/1000; - if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) { - if (DEBUG) { - System.out.println("System time adjusted"); - } - initMilli = newMilli; - initMicro = newMicro; - setTime(newMilli); - microSeconds = 0; - } else { - setTime(calcMilli); - microSeconds = (int)(microElapsed % 1000); - } + return new Date(kerberosTime); } public int getMicroSeconds() { @@ -235,45 +192,25 @@ return temp_long.intValue() + microSeconds; } - public void setMicroSeconds(int usec) { - microSeconds = usec % 1000; - Integer temp_int = new Integer(usec); - long temp_long = temp_int.longValue() / 1000L; - kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long; + /** + * Returns a new KerberosTime object with the original seconds + * and the given microseconds. + */ + public KerberosTime withMicroSeconds(int usec) { + return new KerberosTime( + kerberosTime - kerberosTime%1000L + usec/1000L, + usec%1000); } - public void setMicroSeconds(Integer usec) { - if (usec != null) { - microSeconds = usec.intValue() % 1000; - long temp_long = usec.longValue() / 1000L; - kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long; - } - } - - public boolean inClockSkew(int clockSkew) { - KerberosTime now = new KerberosTime(KerberosTime.NOW); - - if (java.lang.Math.abs(kerberosTime - now.kerberosTime) > - clockSkew * 1000L) - return false; - return true; + private boolean inClockSkew(int clockSkew) { + return java.lang.Math.abs(kerberosTime - System.currentTimeMillis()) + <= clockSkew * 1000L; } public boolean inClockSkew() { return inClockSkew(getDefaultSkew()); } - public boolean inClockSkew(int clockSkew, KerberosTime now) { - if (java.lang.Math.abs(kerberosTime - now.kerberosTime) > - clockSkew * 1000L) - return false; - return true; - } - - public boolean inClockSkew(KerberosTime time) { - return inClockSkew(getDefaultSkew(), time); - } - public boolean greaterThanWRTClockSkew(KerberosTime time, int clockSkew) { if ((kerberosTime - time.kerberosTime) > clockSkew * 1000L) return true; @@ -317,24 +254,22 @@ return temp_long.intValue(); } - public void setSeconds(int sec) { - Integer temp_int = new Integer(sec); - kerberosTime = temp_int.longValue() * 1000L; - } - /** * Parse (unmarshal) a kerberostime from a DER input stream. This form * parsing might be used when expanding a value which is part of * a constructed sequence and uses explicitly tagged type. * * @exception Asn1Exception on error. - * @param data the Der input stream value, which contains one or more marshaled value. + * @param data the Der input stream value, which contains + * one or more marshaled value. * @param explicitTag tag number. * @param optional indicates if this data field is optional * @return an instance of KerberosTime. * */ - public static KerberosTime parse(DerInputStream data, byte explicitTag, boolean optional) throws Asn1Exception, IOException { + public static KerberosTime parse( + DerInputStream data, byte explicitTag, boolean optional) + throws Asn1Exception, IOException { if ((optional) && (((byte)data.peekByte() & (byte)0x1F)!= explicitTag)) return null; DerValue der = data.getDerValue(); @@ -343,7 +278,8 @@ } else { DerValue subDer = der.getData().getDerValue(); - return new KerberosTime(subDer); + Date temp = subDer.getGeneralizedTime(); + return new KerberosTime(temp.getTime(), 0); } }
--- a/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java Wed Apr 17 02:53:02 2013 -0700 @@ -187,14 +187,10 @@ kcred.pname = (PrincipalName)pname.clone(); if (flags != null) kcred.flags = (TicketFlags)flags.clone(); - if (authtime != null) - kcred.authtime = (KerberosTime)authtime.clone(); - if (starttime != null) - kcred.starttime = (KerberosTime)starttime.clone(); - if (endtime != null) - kcred.endtime = (KerberosTime)endtime.clone(); - if (renewTill != null) - kcred.renewTill = (KerberosTime)renewTill.clone(); + kcred.authtime = authtime; + kcred.starttime = starttime; + kcred.endtime = endtime; + kcred.renewTill = renewTill; if (sname != null) kcred.sname = (PrincipalName)sname.clone(); if (caddr != null)
--- a/src/share/classes/sun/security/krb5/internal/LastReqEntry.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/internal/LastReqEntry.java Wed Apr 17 02:53:02 2013 -0700 @@ -90,7 +90,7 @@ public Object clone() { LastReqEntry newEntry = new LastReqEntry(); newEntry.lrType = lrType; - newEntry.lrValue = (KerberosTime)lrValue.clone(); + newEntry.lrValue = lrValue; return newEntry; } }
--- a/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java Wed Apr 17 02:53:02 2013 -0700 @@ -65,7 +65,7 @@ } public PAEncTSEnc() { - KerberosTime now = new KerberosTime(KerberosTime.NOW); + KerberosTime now = KerberosTime.now(); pATimeStamp = now; pAUSec = new Integer(now.getMicroSeconds()); }
--- a/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java Wed Apr 17 02:53:02 2013 -0700 @@ -68,14 +68,11 @@ sname = (PrincipalName) new_sname.clone(); key = (EncryptionKey) new_key.clone(); - authtime = (KerberosTime) new_authtime.clone(); - if (new_starttime != null) { - starttime = (KerberosTime) new_starttime.clone(); - } - endtime = (KerberosTime) new_endtime.clone(); - if (new_renewTill != null) { - renewTill = (KerberosTime) new_renewTill.clone(); - } + authtime = new_authtime; + starttime = new_starttime; + endtime = new_endtime; + renewTill = new_renewTill; + if (new_caddr != null) { caddr = (HostAddresses) new_caddr.clone(); } @@ -104,14 +101,11 @@ ticket = (Ticket) kdcRep.ticket.clone(); key = (EncryptionKey) kdcRep.encKDCRepPart.key.clone(); flags = (TicketFlags) kdcRep.encKDCRepPart.flags.clone(); - authtime = (KerberosTime) kdcRep.encKDCRepPart.authtime.clone(); - if (kdcRep.encKDCRepPart.starttime != null) { - starttime = (KerberosTime) kdcRep.encKDCRepPart.starttime.clone(); - } - endtime = (KerberosTime) kdcRep.encKDCRepPart.endtime.clone(); - if (kdcRep.encKDCRepPart.renewTill != null) { - renewTill = (KerberosTime) kdcRep.encKDCRepPart.renewTill.clone(); - } + authtime = kdcRep.encKDCRepPart.authtime; + starttime = kdcRep.encKDCRepPart.starttime; + endtime = kdcRep.encKDCRepPart.endtime; + renewTill = kdcRep.encKDCRepPart.renewTill; + sname = (PrincipalName) kdcRep.encKDCRepPart.sname.clone(); caddr = (HostAddresses) kdcRep.encKDCRepPart.caddr.clone(); secondTicket = (Ticket) new_secondTicket.clone(); @@ -128,18 +122,10 @@ sname = (PrincipalName) kdcRep.encKDCRepPart.sname.clone(); cname = (PrincipalName) kdcRep.cname.clone(); key = (EncryptionKey) kdcRep.encKDCRepPart.key.clone(); - authtime = (KerberosTime) kdcRep.encKDCRepPart.authtime.clone(); - if (kdcRep.encKDCRepPart.starttime != null) { - starttime = (KerberosTime) kdcRep.encKDCRepPart.starttime.clone(); - } else { - starttime = null; - } - endtime = (KerberosTime) kdcRep.encKDCRepPart.endtime.clone(); - if (kdcRep.encKDCRepPart.renewTill != null) { - renewTill = (KerberosTime) kdcRep.encKDCRepPart.renewTill.clone(); - } else { - renewTill = null; - } + authtime = kdcRep.encKDCRepPart.authtime; + starttime = kdcRep.encKDCRepPart.starttime; + endtime = kdcRep.encKDCRepPart.endtime; + renewTill = kdcRep.encKDCRepPart.renewTill; // if (kdcRep.msgType == Krb5.KRB_AS_REP) { // isEncInSKey = false; // secondTicket = null;
--- a/src/share/classes/sun/security/provider/SHA2.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/provider/SHA2.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ i2bBig4((int)bitsProcessed, buffer, 60); implCompress(buffer, 0); - i2bBig(state, 0, out, ofs, 32); + i2bBig(state, 0, out, ofs, engineGetDigestLength()); } /**
--- a/src/share/classes/sun/security/util/UntrustedCertificates.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/classes/sun/security/util/UntrustedCertificates.java Wed Apr 17 02:53:02 2013 -0700 @@ -843,5 +843,52 @@ "zCOfhbsRWdMLYepauaNZOIMZXmFwcrIl0TGMkTAtATz+XmZc\n" + "-----END CERTIFICATE-----"); + // + // Revoked code signing certificate w/ a stolen key issued by GoDaddy + // used to sign malware + // + + // Subject: CN=CLEARESULT CONSULTING INC., OU=Corporate IT, + // O=CLEARESULT CONSULTING INC., L=Austin, ST=TX, C=US + // Issuer: SERIALNUMBER=07969287, + // CN=Go Daddy Secure Certification Authority, + // OU=http://certificates.godaddy.com/repository, + // O="GoDaddy.com, Inc.", + // L=Scottsdale, + // ST=Arizona, + // C=US + // Serial: 2b:73:43:2a:a8:4f:44 + add("clearesult-consulting-inc-2AA84F44", + "-----BEGIN CERTIFICATE-----\n" + + "MIIFYjCCBEqgAwIBAgIHK3NDKqhPRDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" + + "BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY\n" + + "BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm\n" + + "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5\n" + + "IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky\n" + + "ODcwHhcNMTIwMjE1MjEwOTA2WhcNMTQwMjE1MjEwOTA2WjCBjDELMAkGA1UEBgwC\n" + + "VVMxCzAJBgNVBAgMAlRYMQ8wDQYDVQQHDAZBdXN0aW4xIzAhBgNVBAoMGkNMRUFS\n" + + "RVNVTFQgQ09OU1VMVElORyBJTkMuMRUwEwYDVQQLDAxDb3Jwb3JhdGUgSVQxIzAh\n" + + "BgNVBAMMGkNMRUFSRVNVTFQgQ09OU1VMVElORyBJTkMuMIIBIjANBgkqhkiG9w0B\n" + + "AQEFAAOCAQ8AMIIBCgKCAQEAtIOjCKeAicull+7ZIzt0/4ya3IeXUFlfypqKMLkU\n" + + "IbKjn0P5uMj6VE3rlbZr44RCegxvdnR6umBh1c0ZXoN3o+yc0JKcKcLiApmJJ277\n" + + "p7IbLwYDhBXRQNoIJm187IOMRPIxsKN4hL91txn9jGBmW+9zKlJlNhR5R7vjwU2E\n" + + "jrH/6oqsc9EM2yYpfjlNv6+3jSwAYZCkSWr+27PQOV+YHKmIxtJjX0upFz5FdIrV\n" + + "9CCX+L2Kji1THOkSgG4QTbYxmEcHqGViWz8hXLeNXjcbEsPuIiAu3hknxRHfUTE/\n" + + "U0Lh0Ug1e3LrJu+WnxM2SmUY4krsZ22c0yWUW9hzWITIjQIDAQABo4IBhzCCAYMw\n" + + "DwYDVR0TAQH/BAUwAwEBADATBgNVHSUEDDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8E\n" + + "BAMCB4AwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5LmNvbS9n\n" + + "ZHM1LTE2LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcCMDkwNwYIKwYBBQUH\n" + + "AgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS8w\n" + + "gYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRk\n" + + "eS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdvZGFkZHku\n" + + "Y29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSMEGDAWgBT9\n" + + "rGEyk2xF1uLuhV+auud2mWjM5zAdBgNVHQ4EFgQUDtdeKqeN2QkcbEp1HovFieNB\n" + + "XiowDQYJKoZIhvcNAQEFBQADggEBAD74Agw5tvi2aBl4/f/s7/VE/BClzDsKMb9K\n" + + "v9qpeC45ZA/jelxV11HKbQnVF194gDb7D2H9OsAsRUy8HVKbXEcc/8dKvwOqb+BC\n" + + "2i/EmfjLgmCfezNFtLq8xcPxF3zIRc44vPrK0z4YZsaHdH+yTEJ51p5EMdTqaLaP\n" + + "4n5m8LX3RfqlQB9dYFe6dUoYZjKm9d/pIRww3VqfOzjl42Edi1w6dWmBVMx1NZuR\n" + + "DBabJH1vJ9Gd+KwxMCmBZ6pQPl28JDimhJhI2LNqU349uADQVV0HJosddN/ARyyI\n" + + "LSIQO7BnNVKVG9Iujf33bvPNeg0qNz5qw+rKKq97Pqeum+L5oKU=\n" + + "-----END CERTIFICATE-----"); } }
--- a/src/share/javavm/export/jvm.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/javavm/export/jvm.h Wed Apr 17 02:53:02 2013 -0700 @@ -350,16 +350,21 @@ /* * java.lang.Class and java.lang.ClassLoader */ + +#define JVM_DEPTH -1 + /* - * Returns the class in which the code invoking the native method - * belongs. + * Returns the immediate caller class of the native method invoking + * JVM_GetCallerClass. The Method.invoke and other frames due to + * reflection machinery are skipped. * - * Note that in JDK 1.1, native methods did not create a frame. - * In 1.2, they do. Therefore native methods like Class.forName - * can no longer look at the current frame for the caller class. + * The depth parameter must be -1 (JVM_DEPTH). The caller is expected + * to be marked with sun.reflect.CallerSensitive. The JVM will throw + * an error if it is not marked propertly. */ JNIEXPORT jclass JNICALL -JVM_GetCallerClass(JNIEnv *env, int n); +JVM_GetCallerClass(JNIEnv *env, int depth); + /* * Find primitive classes
--- a/src/share/lib/security/java.security-linux Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/lib/security/java.security-linux Wed Apr 17 02:53:02 2013 -0700 @@ -177,23 +177,36 @@ # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ jdk.internal.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools. + # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when @@ -205,23 +218,36 @@ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ jdk.internal.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools. + # # Determines whether this properties file can be appended to # or overridden on the command line via -Djava.security.properties
--- a/src/share/lib/security/java.security-macosx Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/lib/security/java.security-macosx Wed Apr 17 02:53:02 2013 -0700 @@ -178,17 +178,29 @@ # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ jdk.internal.,\ @@ -207,17 +219,29 @@ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ jdk.internal.,\
--- a/src/share/lib/security/java.security-solaris Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/lib/security/java.security-solaris Wed Apr 17 02:53:02 2013 -0700 @@ -179,17 +179,29 @@ # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ jdk.internal.,\ @@ -207,17 +219,29 @@ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ jdk.internal.,\
--- a/src/share/lib/security/java.security-windows Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/lib/security/java.security-windows Wed Apr 17 02:53:02 2013 -0700 @@ -178,22 +178,35 @@ # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ jdk.internal.,\ jdk.nashorn.internal.,\ - jdk.nashorn.tools. + jdk.nashorn.tools.,\ + com.sun.java.accessibility. # # List of comma-separated packages that start with or equal this string @@ -206,22 +219,35 @@ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.bind.,\ - com.sun.xml.internal.org.jvnet.staxex.,\ - com.sun.xml.internal.ws.,\ + com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.proxy.,\ - com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ jdk.internal.,\ jdk.nashorn.internal.,\ - jdk.nashorn.tools. + jdk.nashorn.tools.,\ + com.sun.java.accessibility. # # Determines whether this properties file can be appended to
--- a/src/share/native/java/lang/ClassLoader.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/java/lang/ClassLoader.c Wed Apr 17 02:53:02 2013 -0700 @@ -492,24 +492,6 @@ (*env)->ReleaseStringUTFChars(env, name, cname); return res; } - -JNIEXPORT jobject JNICALL -Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index) -{ - jobjectArray jcallerStack; - int len; - - jcallerStack = JVM_GetClassContext(env); - if ((*env)->ExceptionCheck(env)) { - return NULL; - } - len = (*env)->GetArrayLength(env, jcallerStack); - if (index < len) { - return (*env)->GetObjectArrayElement(env, jcallerStack, index); - } - return NULL; -} - /* * Class: java_lang_ClassLoader_NativeLibrary * Method: findBuiltinLib
--- a/src/share/native/java/lang/ResourceBundle.c Tue Apr 16 05:32:39 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "jni.h" -#include "jvm.h" - -#include "java_util_ResourceBundle.h" - -JNIEXPORT jobjectArray JNICALL -Java_java_util_ResourceBundle_getClassContext(JNIEnv *env, jobject this) -{ - return JVM_GetClassContext(env); -}
--- a/src/share/native/java/lang/SecurityManager.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/java/lang/SecurityManager.c Wed Apr 17 02:53:02 2013 -0700 @@ -29,7 +29,6 @@ #include "java_lang_SecurityManager.h" #include "java_lang_ClassLoader.h" -#include "java_util_ResourceBundle.h" /* * Make sure a security manager instance is initialized.
--- a/src/share/native/java/net/InetAddress.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/java/net/InetAddress.c Wed Apr 17 02:53:02 2013 -0700 @@ -33,8 +33,11 @@ */ jclass ia_class; -jfieldID ia_addressID; -jfieldID ia_familyID; +jclass iac_class; +jfieldID ia_holderID; +jfieldID iac_addressID; +jfieldID iac_familyID; +jfieldID iac_hostNameID; jfieldID ia_preferIPv6AddressID; /* @@ -48,10 +51,18 @@ CHECK_NULL(c); ia_class = (*env)->NewGlobalRef(env, c); CHECK_NULL(ia_class); - ia_addressID = (*env)->GetFieldID(env, ia_class, "address", "I"); - CHECK_NULL(ia_addressID); - ia_familyID = (*env)->GetFieldID(env, ia_class, "family", "I"); - CHECK_NULL(ia_familyID); + c = (*env)->FindClass(env,"java/net/InetAddress$InetAddressHolder"); + CHECK_NULL(c); + iac_class = (*env)->NewGlobalRef(env, c); + ia_holderID = (*env)->GetFieldID(env, ia_class, "holder", "Ljava/net/InetAddress$InetAddressHolder;"); + CHECK_NULL(ia_holderID); ia_preferIPv6AddressID = (*env)->GetStaticFieldID(env, ia_class, "preferIPv6Address", "Z"); CHECK_NULL(ia_preferIPv6AddressID); + + iac_addressID = (*env)->GetFieldID(env, iac_class, "address", "I"); + CHECK_NULL(iac_addressID); + iac_familyID = (*env)->GetFieldID(env, iac_class, "family", "I"); + CHECK_NULL(iac_familyID); + iac_hostNameID = (*env)->GetFieldID(env, iac_class, "hostName", "Ljava/lang/String;"); + CHECK_NULL(iac_hostNameID); }
--- a/src/share/native/java/net/net_util.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/java/net/net_util.c Wed Apr 17 02:53:02 2013 -0700 @@ -84,6 +84,58 @@ } } +/* The address, and family fields used to be in InetAddress + * but are now in an implementation object. So, there is an extra + * level of indirection to access them now. + */ + +extern jclass iac_class; +extern jfieldID ia_holderID; +extern jfieldID iac_addressID; +extern jfieldID iac_familyID; + +void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + (*env)->SetIntField(env, holder, iac_addressID, address); +} + +void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + (*env)->SetIntField(env, holder, iac_familyID, family); +} + +void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + (*env)->SetObjectField(env, holder, iac_hostNameID, host); +} + +int getInetAddress_addr(JNIEnv *env, jobject iaObj) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + return (*env)->GetIntField(env, holder, iac_addressID); +} + +int getInetAddress_family(JNIEnv *env, jobject iaObj) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + return (*env)->GetIntField(env, holder, iac_familyID); +} + +jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { + jobject holder; + init(env); + holder = (*env)->GetObjectField(env, iaObj, ia_holderID); + return (*env)->GetObjectField(env, holder, iac_hostNameID); +} + JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { jobject iaObj; @@ -110,8 +162,8 @@ iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); CHECK_NULL_RETURN(iaObj, NULL); address = NET_IPv4MappedToIPv4(caddr); - (*env)->SetIntField(env, iaObj, ia_addressID, address); - (*env)->SetIntField(env, iaObj, ia_familyID, IPv4); + setInetAddress_addr(env, iaObj, address); + setInetAddress_family(env, iaObj, IPv4); } else { static jclass inet6Cls = 0; jint scope; @@ -131,7 +183,7 @@ (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress); - (*env)->SetIntField(env, iaObj, ia_familyID, IPv6); + setInetAddress_family(env, iaObj, IPv6); scope = getScopeID(him); (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope); if (scope > 0) @@ -153,9 +205,8 @@ } iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); CHECK_NULL_RETURN(iaObj, NULL); - (*env)->SetIntField(env, iaObj, ia_familyID, IPv4); - (*env)->SetIntField(env, iaObj, ia_addressID, - ntohl(him4->sin_addr.s_addr)); + setInetAddress_family(env, iaObj, IPv4); + setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr)); *port = ntohs(him4->sin_port); } return iaObj; @@ -167,8 +218,7 @@ jint family = AF_INET; #ifdef AF_INET6 - family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? - AF_INET : AF_INET6; + family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; if (him->sa_family == AF_INET6) { #ifdef WIN32 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; @@ -183,7 +233,7 @@ return JNI_FALSE; } addrNew = NET_IPv4MappedToIPv4(caddrNew); - addrCur = (*env)->GetIntField(env, iaObj, ia_addressID); + addrCur = getInetAddress_addr(env, iaObj); if (addrNew == addrCur) { return JNI_TRUE; } else { @@ -215,7 +265,7 @@ return JNI_FALSE; } addrNew = ntohl(him4->sin_addr.s_addr); - addrCur = (*env)->GetIntField(env, iaObj, ia_addressID); + addrCur = getInetAddress_addr(env, iaObj); if (addrNew == addrCur) { return JNI_TRUE; } else {
--- a/src/share/native/java/net/net_util.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/java/net/net_util.h Wed Apr 17 02:53:02 2013 -0700 @@ -53,10 +53,18 @@ * i.e. psi_timeoutID is PlainSocketImpl's timeout field's ID. */ extern jclass ia_class; -extern jfieldID ia_addressID; -extern jfieldID ia_familyID; +extern jfieldID iac_addressID; +extern jfieldID iac_familyID; +extern jfieldID iac_hostNameID; extern jfieldID ia_preferIPv6AddressID; +extern void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address); +extern void setInetAddress_family(JNIEnv *env, jobject iaObj, int family); +extern void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject h); +extern int getInetAddress_addr(JNIEnv *env, jobject iaObj); +extern int getInetAddress_family(JNIEnv *env, jobject iaObj); +extern jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj); + extern jclass ia4_class; extern jmethodID ia4_ctrID;
--- a/src/share/native/sun/awt/image/awt_ImageRep.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/awt/image/awt_ImageRep.c Wed Apr 17 02:53:02 2013 -0700 @@ -45,6 +45,53 @@ # define TRUE 1 #endif +#define CHECK_STRIDE(yy, hh, ss) \ + if ((ss) != 0) { \ + int limit = 0x7fffffff / ((ss) > 0 ? (ss) : -(ss)); \ + if (limit < (yy) || limit < ((yy) + (hh) - 1)) { \ + /* integer oveflow */ \ + return JNI_FALSE; \ + } \ + } \ + +#define CHECK_SRC() \ + do { \ + int pixeloffset; \ + if (off < 0 || off >= srcDataLength) { \ + return JNI_FALSE; \ + } \ + CHECK_STRIDE(0, h, scansize); \ + \ + /* check scansize */ \ + pixeloffset = scansize * (h - 1); \ + if ((w - 1) > (0x7fffffff - pixeloffset)) { \ + return JNI_FALSE; \ + } \ + pixeloffset += (w - 1); \ + \ + if (off > (0x7fffffff - pixeloffset)) { \ + return JNI_FALSE; \ + } \ + } while (0) \ + +#define CHECK_DST(xx, yy) \ + do { \ + int soffset = (yy) * sStride; \ + int poffset = (xx) * pixelStride; \ + if (poffset > (0x7fffffff - soffset)) { \ + return JNI_FALSE; \ + } \ + poffset += soffset; \ + if (dstDataOff > (0x7fffffff - poffset)) { \ + return JNI_FALSE; \ + } \ + poffset += dstDataOff; \ + \ + if (poffset < 0 || poffset >= dstDataLength) { \ + return JNI_FALSE; \ + } \ + } while (0) \ + static jfieldID s_JnumSrcLUTID; static jfieldID s_JsrcLUTtransIndexID; @@ -58,7 +105,7 @@ /* * This routine is used to draw ICM pixels into a default color model */ -JNIEXPORT void JNICALL +JNIEXPORT jboolean JNICALL Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls, jint x, jint y, jint w, jint h, jintArray jlut, @@ -67,7 +114,10 @@ jobject jict) { unsigned char *srcData = NULL; + jint srcDataLength; int *dstData; + jint dstDataLength; + jint dstDataOff; int *dstP, *dstyP; unsigned char *srcyP, *srcP; int *srcLUT = NULL; @@ -80,12 +130,20 @@ if (JNU_IsNull(env, jlut)) { JNU_ThrowNullPointerException(env, "NullPointerException"); - return; + return JNI_FALSE; } if (JNU_IsNull(env, jpix)) { JNU_ThrowNullPointerException(env, "NullPointerException"); - return; + return JNI_FALSE; + } + + if (x < 0 || w < 1 || (0x7fffffff - x) < w) { + return JNI_FALSE; + } + + if (y < 0 || h < 1 || (0x7fffffff - y) < h) { + return JNI_FALSE; } sStride = (*env)->GetIntField(env, jict, g_ICRscanstrID); @@ -93,10 +151,47 @@ joffs = (*env)->GetObjectField(env, jict, g_ICRdataOffsetsID); jdata = (*env)->GetObjectField(env, jict, g_ICRdataID); + if (JNU_IsNull(env, jdata)) { + /* no destination buffer */ + return JNI_FALSE; + } + + if (JNU_IsNull(env, joffs) || (*env)->GetArrayLength(env, joffs) < 1) { + /* invalid data offstes in raster */ + return JNI_FALSE; + } + + srcDataLength = (*env)->GetArrayLength(env, jpix); + dstDataLength = (*env)->GetArrayLength(env, jdata); + + cOffs = (int *) (*env)->GetPrimitiveArrayCritical(env, joffs, NULL); + if (cOffs == NULL) { + JNU_ThrowNullPointerException(env, "Null channel offset array"); + return JNI_FALSE; + } + + dstDataOff = cOffs[0]; + + /* the offset array is not needed anymore and can be released */ + (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT); + joffs = NULL; + cOffs = NULL; + + /* do basic validation: make sure that offsets for + * first pixel and for last pixel are safe to calculate and use */ + CHECK_STRIDE(y, h, sStride); + CHECK_STRIDE(x, w, pixelStride); + + CHECK_DST(x, y); + CHECK_DST(x + w -1, y + h - 1); + + /* check source array */ + CHECK_SRC(); + srcLUT = (int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL); if (srcLUT == NULL) { JNU_ThrowNullPointerException(env, "Null IndexColorModel LUT"); - return; + return JNI_FALSE; } srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix, @@ -104,27 +199,18 @@ if (srcData == NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); JNU_ThrowNullPointerException(env, "Null data array"); - return; - } - - cOffs = (int *) (*env)->GetPrimitiveArrayCritical(env, joffs, NULL); - if (cOffs == NULL) { - (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - JNU_ThrowNullPointerException(env, "Null channel offset array"); - return; + return JNI_FALSE; } dstData = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL); if (dstData == NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT); JNU_ThrowNullPointerException(env, "Null tile data array"); - return; + return JNI_FALSE; } - dstyP = dstData + cOffs[0] + y*sStride + x*pixelStride; + dstyP = dstData + dstDataOff + y*sStride + x*pixelStride; srcyP = srcData + off; for (yIdx = 0; yIdx < h; yIdx++, srcyP += scansize, dstyP+=sStride) { srcP = srcyP; @@ -137,12 +223,12 @@ /* Release the locked arrays */ (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT); + return JNI_TRUE; } -JNIEXPORT jint JNICALL +JNIEXPORT jboolean JNICALL Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, jint x, jint y, jint w, jint h, jintArray jlut, @@ -150,7 +236,7 @@ jobject jicm, jbyteArray jpix, jint off, jint scansize, - jobject jbct, jint chanOff) + jobject jbct, jint dstDataOff) { unsigned int *srcLUT = NULL; unsigned int *newLUT = NULL; @@ -159,6 +245,8 @@ int mapSize; jobject jdata = NULL; jobject jnewlut = NULL; + jint srcDataLength; + jint dstDataLength; unsigned char *srcData; unsigned char *dstData; unsigned char *dataP; @@ -174,14 +262,23 @@ if (JNU_IsNull(env, jlut)) { JNU_ThrowNullPointerException(env, "NullPointerException"); - return 0; + return JNI_FALSE; } if (JNU_IsNull(env, jpix)) { JNU_ThrowNullPointerException(env, "NullPointerException"); - return 0; + return JNI_FALSE; + } + + if (x < 0 || w < 1 || (0x7fffffff - x) < w) { + return JNI_FALSE; } + if (y < 0 || h < 1 || (0x7fffffff - y) < h) { + return JNI_FALSE; + } + + sStride = (*env)->GetIntField(env, jbct, g_BCRscanstrID); pixelStride =(*env)->GetIntField(env, jbct, g_BCRpixstrID); jdata = (*env)->GetObjectField(env, jbct, g_BCRdataID); @@ -193,13 +290,31 @@ of byte data type, so we have to convert the image data to default representation. */ - return 0; + return JNI_FALSE; + } + + if (JNU_IsNull(env, jdata)) { + /* no destination buffer */ + return JNI_FALSE; } + + srcDataLength = (*env)->GetArrayLength(env, jpix); + dstDataLength = (*env)->GetArrayLength(env, jdata); + + CHECK_STRIDE(y, h, sStride); + CHECK_STRIDE(x, w, pixelStride); + + CHECK_DST(x, y); + CHECK_DST(x + w -1, y + h - 1); + + /* check source array */ + CHECK_SRC(); + srcLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL); if (srcLUT == NULL) { /* out of memory error already thrown */ - return 0; + return JNI_FALSE; } newLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jnewlut, @@ -208,7 +323,7 @@ (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); /* out of memory error already thrown */ - return 0; + return JNI_FALSE; } newNumLut = numLut; @@ -219,7 +334,7 @@ (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jnewlut, newLUT, JNI_ABORT); - return 0; + return JNI_FALSE; } /* Don't need these any more */ @@ -239,7 +354,7 @@ NULL); if (srcData == NULL) { /* out of memory error already thrown */ - return 0; + return JNI_FALSE; } dstData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jdata, @@ -247,10 +362,10 @@ if (dstData == NULL) { (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); /* out of memory error already thrown */ - return 0; + return JNI_FALSE; } - ydataP = dstData + chanOff + y*sStride + x*pixelStride; + ydataP = dstData + dstDataOff + y*sStride + x*pixelStride; ypixP = srcData + off; for (i=0; i < h; i++) { @@ -268,7 +383,7 @@ (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT); - return 1; + return JNI_TRUE; } static int compareLUTs(unsigned int *lut1, int numLut1, int transIdx,
--- a/src/share/native/sun/awt/image/awt_parseImage.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/awt/image/awt_parseImage.c Wed Apr 17 02:53:02 2013 -0700 @@ -34,6 +34,7 @@ #include "java_awt_color_ColorSpace.h" #include "awt_Mlib.h" #include "safe_alloc.h" +#include "safe_math.h" static int setHints(JNIEnv *env, BufImageS_t *imageP);
--- a/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Wed Apr 17 02:53:02 2013 -0700 @@ -57,8 +57,8 @@ #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* Cached Java method ids */ -static jmethodID ImageInputStream_readID; -static jmethodID ImageInputStream_skipBytesID; +static jmethodID JPEGImageReader_readInputDataID; +static jmethodID JPEGImageReader_skipInputBytesID; static jmethodID JPEGImageReader_warningOccurredID; static jmethodID JPEGImageReader_warningWithMessageID; static jmethodID JPEGImageReader_setImageDataID; @@ -66,7 +66,7 @@ static jmethodID JPEGImageReader_pushBackID; static jmethodID JPEGImageReader_passStartedID; static jmethodID JPEGImageReader_passCompleteID; -static jmethodID ImageOutputStream_writeID; +static jmethodID JPEGImageWriter_writeOutputDataID; static jmethodID JPEGImageWriter_warningOccurredID; static jmethodID JPEGImageWriter_warningWithMessageID; static jmethodID JPEGImageWriter_writeMetadataID; @@ -923,7 +923,7 @@ RELEASE_ARRAYS(env, data, src->next_input_byte); ret = (*env)->CallIntMethod(env, sb->stream, - ImageInputStream_readID, + JPEGImageReader_readInputDataID, sb->hstreamBuffer, 0, sb->bufferLength); if ((*env)->ExceptionOccurred(env) @@ -1013,7 +1013,7 @@ } ret = (*env)->CallIntMethod(env, sb->stream, - ImageInputStream_readID, + JPEGImageReader_readInputDataID, sb->hstreamBuffer, offset, buflen); if ((*env)->ExceptionOccurred(env) @@ -1107,7 +1107,7 @@ RELEASE_ARRAYS(env, data, src->next_input_byte); ret = (*env)->CallLongMethod(env, sb->stream, - ImageInputStream_skipBytesID, + JPEGImageReader_skipInputBytesID, (jlong) num_bytes); if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, data, &(src->next_input_byte))) { @@ -1382,13 +1382,13 @@ jclass qTableClass, jclass huffClass) { - ImageInputStream_readID = (*env)->GetMethodID(env, - ImageInputStreamClass, - "read", + JPEGImageReader_readInputDataID = (*env)->GetMethodID(env, + cls, + "readInputData", "([BII)I"); - ImageInputStream_skipBytesID = (*env)->GetMethodID(env, - ImageInputStreamClass, - "skipBytes", + JPEGImageReader_skipInputBytesID = (*env)->GetMethodID(env, + cls, + "skipInputBytes", "(J)J"); JPEGImageReader_warningOccurredID = (*env)->GetMethodID(env, cls, @@ -1531,8 +1531,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setSource (JNIEnv *env, jobject this, - jlong ptr, - jobject source) { + jlong ptr) { imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); j_common_ptr cinfo; @@ -1546,7 +1545,7 @@ cinfo = data->jpegObj; - imageio_set_stream(env, cinfo, data, source); + imageio_set_stream(env, cinfo, data, this); imageio_init_source((j_decompress_ptr) cinfo); } @@ -2291,7 +2290,7 @@ (*env)->CallVoidMethod(env, sb->stream, - ImageOutputStream_writeID, + JPEGImageWriter_writeOutputDataID, sb->hstreamBuffer, 0, sb->bufferLength); @@ -2328,7 +2327,7 @@ (*env)->CallVoidMethod(env, sb->stream, - ImageOutputStream_writeID, + JPEGImageWriter_writeOutputDataID, sb->hstreamBuffer, 0, datacount); @@ -2366,13 +2365,12 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initWriterIDs (JNIEnv *env, jclass cls, - jclass IOSClass, jclass qTableClass, jclass huffClass) { - ImageOutputStream_writeID = (*env)->GetMethodID(env, - IOSClass, - "write", + JPEGImageWriter_writeOutputDataID = (*env)->GetMethodID(env, + cls, + "writeOutputData", "([BII)V"); JPEGImageWriter_warningOccurredID = (*env)->GetMethodID(env, @@ -2496,8 +2494,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest (JNIEnv *env, jobject this, - jlong ptr, - jobject destination) { + jlong ptr) { imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); j_compress_ptr cinfo; @@ -2511,7 +2508,7 @@ cinfo = (j_compress_ptr) data->jpegObj; - imageio_set_stream(env, data->jpegObj, data, destination); + imageio_set_stream(env, data->jpegObj, data, this); // Don't call the init method, as that depends on pinned arrays
--- a/src/share/native/sun/awt/medialib/awt_ImagingLib.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/awt/medialib/awt_ImagingLib.c Wed Apr 17 02:53:02 2013 -0700 @@ -42,6 +42,7 @@ #include "awt_Mlib.h" #include "gdefs.h" #include "safe_alloc.h" +#include "safe_math.h" /*************************************************************************** * Definitions * @@ -1993,13 +1994,23 @@ unsigned char *dP = dataP; #define NUM_LINES 10 int numLines = NUM_LINES; - int nbytes = rasterP->width*4*NUM_LINES; + /* it is safe to calculate the scan length, because width has been verified + * on creation of the mlib image + */ + int scanLength = rasterP->width * 4; + + int nbytes = 0; + if (!SAFE_TO_MULT(numLines, scanLength)) { + return -1; + } + + nbytes = numLines * scanLength; for (y=0; y < rasterP->height; y+=numLines) { /* getData, one scanline at a time */ if (y+numLines > rasterP->height) { numLines = rasterP->height - y; - nbytes = rasterP->width*4*numLines; + nbytes = numLines * scanLength; } jpixels = (*env)->CallObjectMethod(env, imageP->jimage, g_BImgGetRGBMID, 0, y, @@ -2129,8 +2140,14 @@ if (cvtToDefault) { int status = 0; *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height); + if (*mlibImagePP == NULL) { + return -1; + } cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP); - /* Make sure the image is cleared */ + /* Make sure the image is cleared. + * NB: the image dimension is already verified, so we can + * safely calculate the length of the buffer. + */ memset(cDataP, 0, width*height*4); if (!isSrc) { @@ -2380,6 +2397,9 @@ case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES: *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands, width, height); + if (*mlibImagePP == NULL) { + return -1; + } if (!isSrc) return 0; cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP); return expandPackedBCR(env, rasterP, -1, cDataP); @@ -2388,6 +2408,9 @@ if (rasterP->sppsm.maxBitSize <= 8) { *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands, width, height); + if (*mlibImagePP == NULL) { + return -1; + } if (!isSrc) return 0; cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP); return expandPackedSCR(env, rasterP, -1, cDataP); @@ -2397,6 +2420,9 @@ if (rasterP->sppsm.maxBitSize <= 8) { *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands, width, height); + if (*mlibImagePP == NULL) { + return -1; + } if (!isSrc) return 0; cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP); return expandPackedICR(env, rasterP, -1, cDataP);
--- a/src/share/native/sun/awt/medialib/mlib_ImageCreate.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/awt/medialib/mlib_ImageCreate.c Wed Apr 17 02:53:02 2013 -0700 @@ -120,6 +120,7 @@ #include "mlib_image.h" #include "mlib_ImageRowTable.h" #include "mlib_ImageCreate.h" +#include "safe_math.h" /***************************************************************/ mlib_image* mlib_ImageSet(mlib_image *image, @@ -247,28 +248,50 @@ return NULL; }; + if (!SAFE_TO_MULT(width, channels)) { + return NULL; + } + + wb = width * channels; + switch (type) { case MLIB_DOUBLE: - wb = width * channels * 8; + if (!SAFE_TO_MULT(wb, 8)) { + return NULL; + } + wb *= 8; break; case MLIB_FLOAT: case MLIB_INT: - wb = width * channels * 4; + if (!SAFE_TO_MULT(wb, 4)) { + return NULL; + } + wb *= 4; break; case MLIB_USHORT: case MLIB_SHORT: - wb = width * channels * 2; + if (!SAFE_TO_MULT(wb, 4)) { + return NULL; + } + wb *= 2; break; case MLIB_BYTE: - wb = width * channels; + // wb is ready break; case MLIB_BIT: - wb = (width * channels + 7) / 8; + if (!SAFE_TO_ADD(7, wb)) { + return NULL; + } + wb = (wb + 7) / 8; break; default: return NULL; } + if (!SAFE_TO_MULT(wb, height)) { + return NULL; + } + data = mlib_malloc(wb * height); if (data == NULL) { return NULL;
--- a/src/share/native/sun/awt/medialib/safe_alloc.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/awt/medialib/safe_alloc.h Wed Apr 17 02:53:02 2013 -0700 @@ -41,10 +41,4 @@ (((w) > 0) && ((h) > 0) && ((sz) > 0) && \ (((0xffffffffu / ((juint)(w))) / ((juint)(h))) > ((juint)(sz)))) -#define SAFE_TO_MULT(a, b) \ - (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b))) - -#define SAFE_TO_ADD(a, b) \ - (((a) >= 0) && ((b) >= 0) && ((0x7fffffff - (a)) > (b))) - #endif // __SAFE_ALLOC_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/awt/medialib/safe_math.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef __SAFE_MATH_H__ +#define __SAFE_MATH_H__ + +#define SAFE_TO_MULT(a, b) \ + (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b))) + +#define SAFE_TO_ADD(a, b) \ + (((a) >= 0) && ((b) >= 0) && ((0x7fffffff - (a)) > (b))) + +#endif // __SAFE_MATH_H__
--- a/src/share/native/sun/font/FontInstanceAdapter.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/FontInstanceAdapter.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -66,8 +66,21 @@ yScalePixelsToUnits = upem / yppem; }; + const void *FontInstanceAdapter::getFontTable(LETag tableTag) const { + size_t ignored = 0; + return getFontTable(tableTag, ignored); +} + +static const LETag cacheMap[LAYOUTCACHE_ENTRIES] = { + GPOS_TAG, GDEF_TAG, GSUB_TAG, MORT_TAG, MORX_TAG, KERN_TAG +}; + +const void *FontInstanceAdapter::getFontTable(LETag tableTag, size_t &length) const +{ + length = 0; + if (!layoutTables) { // t1 font return 0; } @@ -75,14 +88,19 @@ // cache in font's pscaler object // font disposer will handle for us - switch(tableTag) { - case GSUB_TAG: if (layoutTables->gsub_len != -1) return (void*)layoutTables->gsub; break; - case GPOS_TAG: if (layoutTables->gpos_len != -1) return (void*)layoutTables->gpos; break; - case GDEF_TAG: if (layoutTables->gdef_len != -1) return (void*)layoutTables->gdef; break; - case MORT_TAG: if (layoutTables->mort_len != -1) return (void*)layoutTables->mort; break; - case KERN_TAG: if (layoutTables->kern_len != -1) return (void*)layoutTables->kern; break; - default: - //fprintf(stderr, "unexpected table request from font instance adapter: %x\n", tableTag); + int cacheIdx; + for (cacheIdx=0;cacheIdx<LAYOUTCACHE_ENTRIES;cacheIdx++) { + if (tableTag==cacheMap[cacheIdx]) break; + } + + if (cacheIdx<LAYOUTCACHE_ENTRIES) { // if found + if (layoutTables->entries[cacheIdx].len != -1) { + length = layoutTables->entries[cacheIdx].len; + return layoutTables->entries[cacheIdx].ptr; + } + } else { + //fprintf(stderr, "unexpected table request from font instance adapter: %x\n", tableTag); + // (don't load any other tables) return 0; } @@ -96,16 +114,13 @@ env->GetByteArrayRegion(tableBytes, 0, len, result); } - switch(tableTag) { - case GSUB_TAG: layoutTables->gsub = (void*)result; layoutTables->gsub_len = len; break; - case GPOS_TAG: layoutTables->gpos = (void*)result; layoutTables->gpos_len = len; break; - case GDEF_TAG: layoutTables->gdef = (void*)result; layoutTables->gdef_len = len; break; - case MORT_TAG: layoutTables->mort = (void*)result; layoutTables->mort_len = len; break; - case KERN_TAG: layoutTables->kern = (void*)result; layoutTables->kern_len = len; break; - default: break; + if (cacheIdx<LAYOUTCACHE_ENTRIES) { // if cacheable table + layoutTables->entries[cacheIdx].len = len; + layoutTables->entries[cacheIdx].ptr = (const void*)result; } - return (void*)result; + length = len; + return (const void*)result; }; LEGlyphID FontInstanceAdapter::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const
--- a/src/share/native/sun/font/FontInstanceAdapter.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/FontInstanceAdapter.h Wed Apr 17 02:53:02 2013 -0700 @@ -86,6 +86,7 @@ // tables are cached with the native font scaler data // only supports gsub, gpos, gdef, mort tables at present virtual const void *getFontTable(LETag tableTag) const; + virtual const void *getFontTable(LETag tableTag, size_t &len) const; virtual void *getKernPairs() const { return layoutTables->kernPairs;
--- a/src/share/native/sun/font/fontscalerdefs.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/fontscalerdefs.h Wed Apr 17 02:53:02 2013 -0700 @@ -120,20 +120,19 @@ #define GPOS_TAG 0x47504F53 /* 'GPOS' */ #define GDEF_TAG 0x47444546 /* 'GDEF' */ #define MORT_TAG 0x6D6F7274 /* 'mort' */ +#define MORX_TAG 0x6D6F7278 /* 'morx' */ #define KERN_TAG 0x6B65726E /* 'kern' */ +typedef struct TTLayoutTableCacheEntry { + const void* ptr; + int len; +} TTLayoutTableCacheEntry; + +#define LAYOUTCACHE_ENTRIES 6 + typedef struct TTLayoutTableCache { - void* gsub; - void* gpos; - void* gdef; - void* mort; - void* kern; - void* kernPairs; - int gsub_len; - int gpos_len; - int gdef_len; - int mort_len; - int kern_len; + TTLayoutTableCacheEntry entries[LAYOUTCACHE_ENTRIES]; + void* kernPairs; } TTLayoutTableCache; #include "sunfontids.h"
--- a/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -39,19 +39,20 @@ U_NAMESPACE_BEGIN -le_uint32 AlternateSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 AlternateSubstitutionSubtable::process(const LEReferenceTo<AlternateSubstitutionSubtable> &base, + GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { // NOTE: For now, we'll just pick the first alternative... LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); - if (coverageIndex >= 0) { + if (coverageIndex >= 0 && LE_SUCCESS(success)) { le_uint16 altSetCount = SWAPW(alternateSetCount); if (coverageIndex < altSetCount) { Offset alternateSetTableOffset = SWAPW(alternateSetTableOffsetArray[coverageIndex]); - const AlternateSetTable *alternateSetTable = - (const AlternateSetTable *) ((char *) this + alternateSetTableOffset); + const LEReferenceTo<AlternateSetTable> alternateSetTable(base, success, + (const AlternateSetTable *) ((char *) this + alternateSetTableOffset)); TTGlyphID alternate = SWAPW(alternateSetTable->alternateArray[0]); if (filter == NULL || filter->accept(LE_SET_GLYPH(glyph, alternate))) {
--- a/src/share/native/sun/font/layout/AlternateSubstSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/AlternateSubstSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -51,13 +51,17 @@ TTGlyphID alternateArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(AlternateSetTable, alternateArray) + struct AlternateSubstitutionSubtable : GlyphSubstitutionSubtable { le_uint16 alternateSetCount; Offset alternateSetTableOffsetArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LEReferenceTo<AlternateSubstitutionSubtable> &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; +LE_VAR_ARRAY(AlternateSubstitutionSubtable, alternateSetTableOffsetArray) + U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -26,7 +26,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -58,15 +58,18 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine) -ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) +ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, + le_int32 languageCode, le_int32 typoFlags, + const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, + LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) { fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount); fFeatureOrder = TRUE; } -ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, +ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, + le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success) { @@ -88,8 +91,9 @@ // Input: characters // Output: characters, char indices, tags // Returns: output character count -le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, - LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) +le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, + le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, + LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; @@ -137,32 +141,30 @@ return; } - if (fGPOSTable != NULL) { + if (!fGPOSTable.isEmpty()) { OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); - } else if (fGDEFTable != NULL) { - GDEFMarkFilter filter(fGDEFTable); - + } else if (!fGDEFTable.isEmpty()) { + GDEFMarkFilter filter(fGDEFTable, success); adjustMarkGlyphs(glyphStorage, &filter, success); } else { - GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; - GDEFMarkFilter filter(gdefTable); + LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen); + GDEFMarkFilter filter(gdefTable, success); adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); } } UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) - : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success) + : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success) { fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; - - fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); + /* OpenTypeLayoutEngine will allocate a substitution filter */ } UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() { - delete fSubstitutionFilter; + /* OpenTypeLayoutEngine will cleanup the substitution filter */ } // "glyphs", "indices" -> glyphs, indices @@ -233,7 +235,7 @@ return; } - GDEFMarkFilter filter(fGDEFTable); + GDEFMarkFilter filter(fGDEFTable, success); adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); }
--- a/src/share/native/sun/font/layout/ArabicLayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ArabicLayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -75,7 +75,7 @@ * @internal */ ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known
--- a/src/share/native/sun/font/layout/ArabicShaping.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ArabicShaping.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -58,14 +58,16 @@ */ ArabicShaping::ShapeType ArabicShaping::getShapeType(LEUnicode c) { - const ClassDefinitionTable *joiningTypes = (const ClassDefinitionTable *) ArabicShaping::shapingTypeTable; - le_int32 joiningType = joiningTypes->getGlyphClass(c); + LEErrorCode success = LE_NO_ERROR; + const LEReferenceTo<ClassDefinitionTable> joiningTypes((const ClassDefinitionTable *) ArabicShaping::shapingTypeTable, + ArabicShaping::shapingTypeTableLen); + le_int32 joiningType = joiningTypes->getGlyphClass(joiningTypes, c, success); - if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT) { - return ArabicShaping::shapeTypes[joiningType]; - } + if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT && LE_SUCCESS(success)) { + return ArabicShaping::shapeTypes[joiningType]; + } - return ArabicShaping::ST_NOSHAPE_NONE; + return ArabicShaping::ST_NOSHAPE_NONE; } #define isolFeatureTag LE_ISOL_FEATURE_TAG
--- a/src/share/native/sun/font/layout/ArabicShaping.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ArabicShaping.h Wed Apr 17 02:53:02 2013 -0700 @@ -93,6 +93,8 @@ static ShapeType getShapeType(LEUnicode c); static const le_uint8 shapingTypeTable[]; + static const size_t shapingTypeTableLen; + static const ShapeType shapeTypes[]; static void adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage);
--- a/src/share/native/sun/font/layout/AttachmentPosnSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/AttachmentPosnSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -52,14 +52,14 @@ Offset markArrayOffset; Offset baseArrayOffset; - inline le_int32 getBaseCoverage(LEGlyphID baseGlyphId) const; + inline le_int32 getBaseCoverage(const LETableReference &base, LEGlyphID baseGlyphId, LEErrorCode &success) const; le_uint32 process(GlyphIterator *glyphIterator) const; }; -inline le_int32 AttachmentPositioningSubtable::getBaseCoverage(LEGlyphID baseGlyphID) const +inline le_int32 AttachmentPositioningSubtable::getBaseCoverage(const LETableReference &base, LEGlyphID baseGlyphID, LEErrorCode &success) const { - return getGlyphCoverage(baseCoverageTableOffset, baseGlyphID); + return getGlyphCoverage(base, baseCoverageTableOffset, baseGlyphID, success); } U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/CanonData.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/CanonData.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -3641,4 +3641,9 @@ 0x00, 0xE6, 0xD2, 0x42, 0xD2, 0x44, 0x00, 0xE6 }; + +const size_t CanonShaping::glyphSubstitutionTableLen = sizeof(glyphSubstitutionTable)/sizeof(glyphSubstitutionTable[0]); + +const size_t CanonShaping::glyphDefinitionTableLen = sizeof(glyphDefinitionTable)/sizeof(glyphDefinitionTable[0]); + U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/CanonShaping.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/CanonShaping.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -59,15 +59,15 @@ void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft, LEUnicode *outChars, LEGlyphStorage &glyphStorage) { - const GlyphDefinitionTableHeader *gdefTable = (const GlyphDefinitionTableHeader *) glyphDefinitionTable; - const ClassDefinitionTable *classTable = gdefTable->getMarkAttachClassDefinitionTable(); + LEErrorCode success = LE_NO_ERROR; + LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen); + LEReferenceTo<ClassDefinitionTable> classTable = gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success); le_int32 *combiningClasses = LE_NEW_ARRAY(le_int32, charCount); le_int32 *indices = LE_NEW_ARRAY(le_int32, charCount); - LEErrorCode status = LE_NO_ERROR; le_int32 i; for (i = 0; i < charCount; i += 1) { - combiningClasses[i] = classTable->getGlyphClass((LEGlyphID) inChars[i]); + combiningClasses[i] = classTable->getGlyphClass(classTable, (LEGlyphID) inChars[i], success); indices[i] = i; } @@ -96,7 +96,7 @@ le_int32 index = indices[i]; outChars[i] = inChars[index]; - glyphStorage.setCharIndex(out, index, status); + glyphStorage.setCharIndex(out, index, success); } LE_DELETE_ARRAY(indices);
--- a/src/share/native/sun/font/layout/CanonShaping.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/CanonShaping.h Wed Apr 17 02:53:02 2013 -0700 @@ -42,7 +42,9 @@ { public: static const le_uint8 glyphSubstitutionTable[]; + static const size_t glyphSubstitutionTableLen; static const le_uint8 glyphDefinitionTable[]; + static const size_t glyphDefinitionTableLen; static void reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft, LEUnicode *outChars, LEGlyphStorage &glyphStorage);
--- a/src/share/native/sun/font/layout/ClassDefinitionTables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ClassDefinitionTables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -37,24 +37,51 @@ U_NAMESPACE_BEGIN -le_int32 ClassDefinitionTable::getGlyphClass(LEGlyphID glyphID) const +le_int32 ClassDefinitionTable::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const { + LEReferenceTo<ClassDefinitionTable> thisRef(base, success); + if (LE_FAILURE(success)) return 0; + + switch(SWAPW(classFormat)) { + case 0: + return 0; + + case 1: + { + const LEReferenceTo<ClassDefFormat1Table> f1Table(thisRef, success); + return f1Table->getGlyphClass(f1Table, glyphID, success); + } + + case 2: + { + const LEReferenceTo<ClassDefFormat2Table> f2Table(thisRef, success); + return f2Table->getGlyphClass(f2Table, glyphID, success); + } + + default: + return 0; + } +} + +le_bool ClassDefinitionTable::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const +{ + LEReferenceTo<ClassDefinitionTable> thisRef(base, success); + if (LE_FAILURE(success)) return 0; + switch(SWAPW(classFormat)) { case 0: return 0; case 1: { - const ClassDefFormat1Table *f1Table = (const ClassDefFormat1Table *) this; - - return f1Table->getGlyphClass(glyphID); + const LEReferenceTo<ClassDefFormat1Table> f1Table(thisRef, success); + return f1Table->hasGlyphClass(f1Table, glyphClass, success); } case 2: { - const ClassDefFormat2Table *f2Table = (const ClassDefFormat2Table *) this; - - return f2Table->getGlyphClass(glyphID); + const LEReferenceTo<ClassDefFormat2Table> f2Table(thisRef, success); + return f2Table->hasGlyphClass(f2Table, glyphClass, success); } default: @@ -62,51 +89,32 @@ } } -le_bool ClassDefinitionTable::hasGlyphClass(le_int32 glyphClass) const +le_int32 ClassDefFormat1Table::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const { - switch(SWAPW(classFormat)) { - case 0: - return 0; - - case 1: - { - const ClassDefFormat1Table *f1Table = (const ClassDefFormat1Table *) this; - - return f1Table->hasGlyphClass(glyphClass); - } + if(LE_FAILURE(success)) return 0; - case 2: - { - const ClassDefFormat2Table *f2Table = (const ClassDefFormat2Table *) this; - - return f2Table->hasGlyphClass(glyphClass); - } - - default: - return 0; - } -} - -le_int32 ClassDefFormat1Table::getGlyphClass(LEGlyphID glyphID) const -{ + le_uint16 count = SWAPW(glyphCount); + LEReferenceToArrayOf<le_uint16> classValueArrayRef(base, success, &classValueArray[0], count); TTGlyphID ttGlyphID = (TTGlyphID) LE_GET_GLYPH(glyphID); TTGlyphID firstGlyph = SWAPW(startGlyph); - TTGlyphID lastGlyph = firstGlyph + SWAPW(glyphCount); + TTGlyphID lastGlyph = firstGlyph + count; - if (ttGlyphID >= firstGlyph && ttGlyphID < lastGlyph) { - return SWAPW(classValueArray[ttGlyphID - firstGlyph]); + if (LE_SUCCESS(success) && ttGlyphID >= firstGlyph && ttGlyphID < lastGlyph) { + return SWAPW( classValueArrayRef(ttGlyphID - firstGlyph, success) ); } return 0; } -le_bool ClassDefFormat1Table::hasGlyphClass(le_int32 glyphClass) const +le_bool ClassDefFormat1Table::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const { - le_uint16 count = SWAPW(glyphCount); + if(LE_FAILURE(success)) return 0; + le_uint16 count = SWAPW(glyphCount); + LEReferenceToArrayOf<le_uint16> classValueArrayRef(base, success, &classValueArray[0], count); int i; - for (i = 0; i < count; i += 1) { - if (SWAPW(classValueArray[i]) == glyphClass) { + for (i = 0; LE_SUCCESS(success)&& (i < count); i += 1) { + if (SWAPW(classValueArrayRef(i,success)) == glyphClass) { return TRUE; } } @@ -114,27 +122,31 @@ return FALSE; } -le_int32 ClassDefFormat2Table::getGlyphClass(LEGlyphID glyphID) const +le_int32 ClassDefFormat2Table::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const { + if(LE_FAILURE(success)) return 0; TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyphID); le_uint16 rangeCount = SWAPW(classRangeCount); + LEReferenceToArrayOf<GlyphRangeRecord> classRangeRecordArrayRef(base, success, &classRangeRecordArray[0], rangeCount); le_int32 rangeIndex = - OpenTypeUtilities::getGlyphRangeIndex(ttGlyph, classRangeRecordArray, rangeCount); + OpenTypeUtilities::getGlyphRangeIndex(ttGlyph, classRangeRecordArrayRef, success); - if (rangeIndex < 0) { + if (rangeIndex < 0 || LE_FAILURE(success)) { return 0; } - return SWAPW(classRangeRecordArray[rangeIndex].rangeValue); + return SWAPW(classRangeRecordArrayRef(rangeIndex, success).rangeValue); } -le_bool ClassDefFormat2Table::hasGlyphClass(le_int32 glyphClass) const +le_bool ClassDefFormat2Table::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const { + if(LE_FAILURE(success)) return 0; le_uint16 rangeCount = SWAPW(classRangeCount); + LEReferenceToArrayOf<GlyphRangeRecord> classRangeRecordArrayRef(base, success, &classRangeRecordArray[0], rangeCount); int i; - for (i = 0; i < rangeCount; i += 1) { - if (SWAPW(classRangeRecordArray[i].rangeValue) == glyphClass) { + for (i = 0; i < rangeCount && LE_SUCCESS(success); i += 1) { + if (SWAPW(classRangeRecordArrayRef(i,success).rangeValue) == glyphClass) { return TRUE; } }
--- a/src/share/native/sun/font/layout/ClassDefinitionTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ClassDefinitionTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -46,8 +46,20 @@ { le_uint16 classFormat; - le_int32 getGlyphClass(LEGlyphID glyphID) const; - le_bool hasGlyphClass(le_int32 glyphClass) const; + le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const; + le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const; + + le_int32 getGlyphClass(LEGlyphID glyphID) const { + LETableReference base((const le_uint8*)this); + LEErrorCode ignored = LE_NO_ERROR; + return getGlyphClass(base,glyphID,ignored); + } + + le_bool hasGlyphClass(le_int32 glyphClass) const { + LETableReference base((const le_uint8*)this); + LEErrorCode ignored = LE_NO_ERROR; + return hasGlyphClass(base,glyphClass,ignored); + } }; struct ClassDefFormat1Table : ClassDefinitionTable @@ -56,9 +68,11 @@ le_uint16 glyphCount; le_uint16 classValueArray[ANY_NUMBER]; - le_int32 getGlyphClass(LEGlyphID glyphID) const; - le_bool hasGlyphClass(le_int32 glyphClass) const; + le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const; + le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const; }; +LE_VAR_ARRAY(ClassDefFormat1Table, classValueArray) + struct ClassRangeRecord { @@ -72,9 +86,10 @@ le_uint16 classRangeCount; GlyphRangeRecord classRangeRecordArray[ANY_NUMBER]; - le_int32 getGlyphClass(LEGlyphID glyphID) const; - le_bool hasGlyphClass(le_int32 glyphClass) const; + le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const; + le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const; }; +LE_VAR_ARRAY(ClassDefFormat2Table, classRangeRecordArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/ContextualGlyphInsertion.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ContextualGlyphInsertion.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -49,6 +49,11 @@ { }; +struct ContextualGlyphInsertionHeader2 : MorphStateTableHeader2 +{ + le_uint32 insertionTableOffset; +}; + enum ContextualGlyphInsertionFlags { cgiSetMark = 0x8000, @@ -61,11 +66,17 @@ cgiMarkedInsertCountMask = 0x001F }; -struct LigatureSubstitutionStateEntry : StateEntry +struct ContextualGlyphInsertionStateEntry : StateEntry { ByteOffset currentInsertionListOffset; ByteOffset markedInsertionListOffset; }; +struct ContextualGlyphInsertionStateEntry2 : StateEntry2 +{ + le_uint16 currentInsertionListIndex; + le_uint16 markedInsertionListIndex; +}; + U_NAMESPACE_END #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,139 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphInsertionProcessor2) + +ContextualGlyphInsertionProcessor2::ContextualGlyphInsertionProcessor2( + const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor2(morphSubtableHeader, success) +{ + contextualGlyphHeader = LEReferenceTo<ContextualGlyphInsertionHeader2>(morphSubtableHeader, success); + if(LE_FAILURE(success) || !contextualGlyphHeader.isValid()) return; + le_uint32 insertionTableOffset = SWAPL(contextualGlyphHeader->insertionTableOffset); + insertionTable = LEReferenceToArrayOf<le_uint16>(stHeader, success, insertionTableOffset, LE_UNBOUNDED_ARRAY); + entryTable = LEReferenceToArrayOf<ContextualGlyphInsertionStateEntry2>(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); +} + +ContextualGlyphInsertionProcessor2::~ContextualGlyphInsertionProcessor2() +{ +} + +void ContextualGlyphInsertionProcessor2::beginStateTable() +{ + markGlyph = 0; +} + +void ContextualGlyphInsertionProcessor2::doInsertion(LEGlyphStorage &glyphStorage, + le_int16 atGlyph, + le_int16 &index, + le_int16 count, + le_bool /* isKashidaLike */, + le_bool isBefore, + LEErrorCode &success) { + LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(atGlyph, count + 1, success); + + if(LE_FAILURE(success) || insertGlyphs==NULL) { + return; + } + + // Note: Kashida vs Split Vowel seems to only affect selection and highlighting. + // We note the flag, but do not layout different. + // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6mort.html + + le_int16 targetIndex = 0; + if(isBefore) { + // insert at beginning + insertGlyphs[targetIndex++] = glyphStorage[atGlyph]; + } else { + // insert at end + insertGlyphs[count] = glyphStorage[atGlyph]; + } + + while(count--) { + insertGlyphs[targetIndex++] = insertionTable.getObject(index++, success); + } + glyphStorage.applyInsertions(); +} + +le_uint16 ContextualGlyphInsertionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, + EntryTableIndex2 index, LEErrorCode &success) +{ + const ContextualGlyphInsertionStateEntry2 *entry = entryTable.getAlias(index, success); + + if(LE_FAILURE(success)) return 0; // TODO- which state? + + le_uint16 newState = SWAPW(entry->newStateIndex); + le_uint16 flags = SWAPW(entry->flags); + + le_int16 markIndex = SWAPW(entry->markedInsertionListIndex); + if (markIndex > 0) { + le_int16 count = (flags & cgiMarkedInsertCountMask) >> 5; + le_bool isKashidaLike = (flags & cgiMarkedIsKashidaLike); + le_bool isBefore = (flags & cgiMarkInsertBefore); + doInsertion(glyphStorage, markGlyph, markIndex, count, isKashidaLike, isBefore, success); + } + + le_int16 currIndex = SWAPW(entry->currentInsertionListIndex); + if (currIndex > 0) { + le_int16 count = flags & cgiCurrentInsertCountMask; + le_bool isKashidaLike = (flags & cgiCurrentIsKashidaLike); + le_bool isBefore = (flags & cgiCurrentInsertBefore); + doInsertion(glyphStorage, currGlyph, currIndex, count, isKashidaLike, isBefore, success); + } + + if (flags & cgiSetMark) { + markGlyph = currGlyph; + } + + if (!(flags & cgiDontAdvance)) { + currGlyph += dir; + } + + return newState; +} + +void ContextualGlyphInsertionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,106 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 2013 - All Rights Reserved + * + */ + +#ifndef __CONTEXTUALGLYPHINSERTIONPROCESSOR2_H +#define __CONTEXTUALGLYPHINSERTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "ContextualGlyphInsertion.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class ContextualGlyphInsertionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, + le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success); + + virtual void endStateTable(); + + ContextualGlyphInsertionProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + virtual ~ContextualGlyphInsertionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + ContextualGlyphInsertionProcessor2(); + + /** + * Perform the actual insertion + * @param atGlyph index of glyph to insert at + * @param index index into the insertionTable (in/out) + * @param count number of insertions + * @param isKashidaLike Kashida like (vs Split Vowel like). No effect currently. + * @param isBefore if true, insert extra glyphs before the marked glyph + */ + void doInsertion(LEGlyphStorage &glyphStorage, + le_int16 atGlyph, + le_int16 &index, + le_int16 count, + le_bool isKashidaLike, + le_bool isBefore, + LEErrorCode &success); + + +protected: + le_int32 markGlyph; + LEReferenceToArrayOf<le_uint16> insertionTable; + LEReferenceToArrayOf<ContextualGlyphInsertionStateEntry2> entryTable; + LEReferenceTo<ContextualGlyphInsertionHeader2> contextualGlyphHeader; +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -43,13 +43,18 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphSubstitutionProcessor) -ContextualGlyphSubstitutionProcessor::ContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader) - : StateTableProcessor(morphSubtableHeader) +ContextualGlyphSubstitutionProcessor::ContextualGlyphSubstitutionProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor(morphSubtableHeader, success), entryTable(), contextualGlyphSubstitutionHeader(morphSubtableHeader, success) { - contextualGlyphSubstitutionHeader = (const ContextualGlyphSubstitutionHeader *) morphSubtableHeader; - substitutionTableOffset = SWAPW(contextualGlyphSubstitutionHeader->substitutionTableOffset); + contextualGlyphSubstitutionHeader.orphan(); + substitutionTableOffset = SWAPW(contextualGlyphSubstitutionHeader->substitutionTableOffset); + - entryTable = (const ContextualGlyphSubstitutionStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset); + entryTable = LEReferenceToArrayOf<ContextualGlyphSubstitutionStateEntry>(stateTableHeader, success, + (const ContextualGlyphSubstitutionStateEntry*)(&stateTableHeader->stHeader), + entryTableOffset, LE_UNBOUNDED_ARRAY); + int16Table = LEReferenceToArrayOf<le_int16>(stateTableHeader, success, (const le_int16*)(&stateTableHeader->stHeader), + 0, LE_UNBOUNDED_ARRAY); // rest of the table as le_int16s } ContextualGlyphSubstitutionProcessor::~ContextualGlyphSubstitutionProcessor() @@ -63,27 +68,26 @@ ByteOffset ContextualGlyphSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index) { - const ContextualGlyphSubstitutionStateEntry *entry = &entryTable[index]; - ByteOffset newState = SWAPW(entry->newStateOffset); - le_int16 flags = SWAPW(entry->flags); - WordOffset markOffset = SWAPW(entry->markOffset); - WordOffset currOffset = SWAPW(entry->currOffset); - - if (markOffset != 0) { - const le_int16 *table = (const le_int16 *) ((char *) &stateTableHeader->stHeader + markOffset * 2); - LEGlyphID mGlyph = glyphStorage[markGlyph]; - TTGlyphID newGlyph = SWAPW(table[LE_GET_GLYPH(mGlyph)]); + LEErrorCode success = LE_NO_ERROR; + const ContextualGlyphSubstitutionStateEntry *entry = entryTable.getAlias(index, success); + ByteOffset newState = SWAPW(entry->newStateOffset); + le_int16 flags = SWAPW(entry->flags); + WordOffset markOffset = SWAPW(entry->markOffset); + WordOffset currOffset = SWAPW(entry->currOffset); - glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph); - } + if (markOffset != 0 && LE_SUCCESS(success)) { + LEGlyphID mGlyph = glyphStorage[markGlyph]; + TTGlyphID newGlyph = SWAPW(int16Table.getObject(markOffset + LE_GET_GLYPH(mGlyph), success)); // whew. + + glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph); + } - if (currOffset != 0) { - const le_int16 *table = (const le_int16 *) ((char *) &stateTableHeader->stHeader + currOffset * 2); - LEGlyphID thisGlyph = glyphStorage[currGlyph]; - TTGlyphID newGlyph = SWAPW(table[LE_GET_GLYPH(thisGlyph)]); + if (currOffset != 0) { + LEGlyphID thisGlyph = glyphStorage[currGlyph]; + TTGlyphID newGlyph = SWAPW(int16Table.getObject(currOffset + LE_GET_GLYPH(thisGlyph), success)); // whew. - glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph); - } + glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } if (flags & cgsSetMark) { markGlyph = currGlyph;
--- a/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h Wed Apr 17 02:53:02 2013 -0700 @@ -56,7 +56,7 @@ virtual void endStateTable(); - ContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader); + ContextualGlyphSubstitutionProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~ContextualGlyphSubstitutionProcessor(); /** @@ -78,11 +78,11 @@ protected: ByteOffset substitutionTableOffset; - const ContextualGlyphSubstitutionStateEntry *entryTable; - + LEReferenceToArrayOf<ContextualGlyphSubstitutionStateEntry> entryTable; + LEReferenceToArrayOf<le_int16> int16Table; le_int32 markGlyph; - const ContextualGlyphSubstitutionHeader *contextualGlyphSubstitutionHeader; + LEReferenceTo<ContextualGlyphSubstitutionHeader> contextualGlyphSubstitutionHeader; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,170 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphSubstProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphSubstitutionProcessor2) + +ContextualGlyphSubstitutionProcessor2::ContextualGlyphSubstitutionProcessor2( + const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor2(morphSubtableHeader, success), contextualGlyphHeader(morphSubtableHeader, success) +{ + if(LE_FAILURE(success)) return; + le_uint32 perGlyphTableOffset = SWAPL(contextualGlyphHeader->perGlyphTableOffset); + perGlyphTable = LEReferenceToArrayOf<le_uint32> (stHeader, success, perGlyphTableOffset, LE_UNBOUNDED_ARRAY); + entryTable = LEReferenceToArrayOf<ContextualGlyphStateEntry2>(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); +} + +ContextualGlyphSubstitutionProcessor2::~ContextualGlyphSubstitutionProcessor2() +{ +} + +void ContextualGlyphSubstitutionProcessor2::beginStateTable() +{ + markGlyph = 0; +} + +le_uint16 ContextualGlyphSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, + EntryTableIndex2 index, LEErrorCode &success) +{ + if(LE_FAILURE(success)) return 0; + const ContextualGlyphStateEntry2 *entry = entryTable.getAlias(index, success); + if(LE_FAILURE(success)) return 0; + le_uint16 newState = SWAPW(entry->newStateIndex); + le_uint16 flags = SWAPW(entry->flags); + le_int16 markIndex = SWAPW(entry->markIndex); + le_int16 currIndex = SWAPW(entry->currIndex); + + if (markIndex != -1) { + le_uint32 offset = SWAPL(perGlyphTable(markIndex, success)); + LEGlyphID mGlyph = glyphStorage[markGlyph]; + TTGlyphID newGlyph = lookup(offset, mGlyph, success); + glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph); + } + + if (currIndex != -1) { + le_uint32 offset = SWAPL(perGlyphTable(currIndex, success)); + LEGlyphID thisGlyph = glyphStorage[currGlyph]; + TTGlyphID newGlyph = lookup(offset, thisGlyph, success); + glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + + if (flags & cgsSetMark) { + markGlyph = currGlyph; + } + + if (!(flags & cgsDontAdvance)) { + currGlyph += dir; + } + + return newState; +} + +TTGlyphID ContextualGlyphSubstitutionProcessor2::lookup(le_uint32 offset, LEGlyphID gid, LEErrorCode &success) +{ + TTGlyphID newGlyph = 0xFFFF; + if(LE_FAILURE(success)) return newGlyph; + LEReferenceTo<LookupTable> lookupTable(perGlyphTable, success, offset); + if(LE_FAILURE(success)) return newGlyph; + le_int16 format = SWAPW(lookupTable->format); + + switch (format) { + case ltfSimpleArray: { +#ifdef TEST_FORMAT + // Disabled pending for design review + LEReferenceTo<SimpleArrayLookupTable> lookupTable0(lookupTable, success); + LEReferenceToArrayOf<LookupValue> valueArray(lookupTable0, success, &lookupTable0->valueArray[0], LE_UNBOUNDED_ARRAY); + if(LE_FAILURE(success)) return newGlyph; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + newGlyph = SWAPW(lookupTable0->valueArray(glyphCode, success)); +#endif + break; + } + case ltfSegmentSingle: { +#ifdef TEST_FORMAT + // Disabled pending for design review + LEReferenceTo<SegmentSingleLookupTable> lookupTable2 = (SegmentSingleLookupTable *) lookupTable; + const LookupSegment *segment = lookupTable2->lookupSegment(lookupTable2->segments, gid); + if (segment != NULL) { + newGlyph = SWAPW(segment->value); + } +#endif + break; + } + case ltfSegmentArray: { + //printf("Context Lookup Table Format4: specific interpretation needed!\n"); + break; + } + case ltfSingleTable: + { +#ifdef TEST_FORMAT + // Disabled pending for design review + LEReferenceTo<SingleTableLookupTable> lookupTable6 = (SingleTableLookupTable *) lookupTable; + const LEReferenceTo<LookupSingle> segment = lookupTable6->lookupSingle(lookupTable6->entries, gid); + if (segment != NULL) { + newGlyph = SWAPW(segment->value); + } +#endif + break; + } + case ltfTrimmedArray: { + LEReferenceTo<TrimmedArrayLookupTable> lookupTable8(lookupTable, success); + if (LE_FAILURE(success)) return newGlyph; + TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph); + TTGlyphID glyphCount = SWAPW(lookupTable8->glyphCount); + TTGlyphID lastGlyph = firstGlyph + glyphCount; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) { + LEReferenceToArrayOf<LookupValue> valueArray(lookupTable8, success, &lookupTable8->valueArray[0], glyphCount); + newGlyph = SWAPW(valueArray(glyphCode - firstGlyph, success)); + } + } + default: + break; + } + return newGlyph; +} + +void ContextualGlyphSubstitutionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,92 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __CONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H +#define __CONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "ContextualGlyphSubstitution.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class ContextualGlyphSubstitutionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success); + + virtual void endStateTable(); + + ContextualGlyphSubstitutionProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + virtual ~ContextualGlyphSubstitutionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + ContextualGlyphSubstitutionProcessor2(); + TTGlyphID lookup(le_uint32 offset, LEGlyphID gid, LEErrorCode &success); + +protected: + LEReferenceToArrayOf<le_uint32> perGlyphTable; + LEReferenceToArrayOf<ContextualGlyphStateEntry2> entryTable; + + le_int16 perGlyphTableFormat; + le_int32 markGlyph; + + LEReferenceTo<ContextualGlyphHeader2> contextualGlyphHeader; + +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/ContextualGlyphSubstitution.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ContextualGlyphSubstitution.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -49,6 +49,11 @@ ByteOffset substitutionTableOffset; }; +struct ContextualGlyphHeader2 : MorphStateTableHeader2 +{ + le_uint32 perGlyphTableOffset; // no more substitution tables +}; + enum ContextualGlyphSubstitutionFlags { cgsSetMark = 0x8000, @@ -62,5 +67,11 @@ WordOffset currOffset; }; +struct ContextualGlyphStateEntry2 : StateEntry2 +{ + le_uint16 markIndex; + le_uint16 currIndex; +}; + U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -217,7 +217,7 @@ } LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); if (coverageIndex >= 0) { le_uint16 srSetCount = SWAPW(subRuleSetCount); @@ -266,7 +266,7 @@ } LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); if (coverageIndex >= 0) { const ClassDefinitionTable *classDefinitionTable = @@ -394,7 +394,7 @@ } LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); if (coverageIndex >= 0) { le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); @@ -465,7 +465,7 @@ } LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); if (coverageIndex >= 0) { const ClassDefinitionTable *backtrackClassDefinitionTable =
--- a/src/share/native/sun/font/layout/ContextualSubstSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ContextualSubstSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -43,6 +43,7 @@ #include "GlyphSubstitutionTables.h" #include "GlyphIterator.h" #include "LookupProcessor.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -88,6 +89,8 @@ le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ContextualSubstitutionFormat1Subtable, subRuleSetTableOffsetArray) + struct SubRuleSetTable { @@ -95,6 +98,7 @@ Offset subRuleTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SubRuleSetTable, subRuleTableOffsetArray) // NOTE: Multiple variable size arrays!! struct SubRuleTable @@ -104,6 +108,7 @@ TTGlyphID inputGlyphArray[ANY_NUMBER]; //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SubRuleTable, inputGlyphArray) struct ContextualSubstitutionFormat2Subtable : ContextualSubstitutionSubtable { @@ -113,12 +118,16 @@ le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ContextualSubstitutionFormat2Subtable, subClassSetTableOffsetArray) + struct SubClassSetTable { le_uint16 subClassRuleCount; Offset subClassRuleTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SubClassSetTable, subClassRuleTableOffsetArray) + // NOTE: Multiple variable size arrays!! struct SubClassRuleTable @@ -128,6 +137,8 @@ le_uint16 classArray[ANY_NUMBER]; //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SubClassRuleTable, classArray) + // NOTE: This isn't a subclass of GlyphSubstitutionSubtable 'cause // it has an array of coverage tables instead of a single coverage table... @@ -143,6 +154,7 @@ le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ContextualSubstitutionFormat3Subtable, coverageTableOffsetArray) struct ChainingContextualSubstitutionSubtable : ContextualSubstitutionBase { @@ -156,6 +168,8 @@ le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ChainingContextualSubstitutionFormat1Subtable, chainSubRuleSetTableOffsetArray) + struct ChainSubRuleSetTable { @@ -163,6 +177,7 @@ Offset chainSubRuleTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainSubRuleSetTable, chainSubRuleTableOffsetArray) // NOTE: Multiple variable size arrays!! struct ChainSubRuleTable @@ -176,6 +191,7 @@ //le_uint16 substCount; //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainSubRuleTable, backtrackGlyphArray) struct ChainingContextualSubstitutionFormat2Subtable : ChainingContextualSubstitutionSubtable { @@ -187,12 +203,15 @@ le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ChainingContextualSubstitutionFormat2Subtable, chainSubClassSetTableOffsetArray) struct ChainSubClassSetTable { le_uint16 chainSubClassRuleCount; Offset chainSubClassRuleTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainSubClassSetTable, chainSubClassRuleTableOffsetArray) + // NOTE: Multiple variable size arrays!! struct ChainSubClassRuleTable @@ -206,6 +225,7 @@ //le_uint16 substCount; //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainSubClassRuleTable, backtrackClassArray) // NOTE: This isn't a subclass of GlyphSubstitutionSubtable 'cause // it has arrays of coverage tables instead of a single coverage table... @@ -225,6 +245,8 @@ le_uint32 process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; }; +LE_VAR_ARRAY(ChainingContextualSubstitutionFormat3Subtable, backtrackCoverageTableOffsetArray) + U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/CoverageTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/CoverageTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -56,6 +56,8 @@ le_int32 getGlyphCoverage(LEGlyphID glyphID) const; }; +LE_VAR_ARRAY(CoverageFormat1Table, glyphArray) + struct CoverageFormat2Table : CoverageTable { @@ -64,6 +66,7 @@ le_int32 getGlyphCoverage(LEGlyphID glyphID) const; }; +LE_VAR_ARRAY(CoverageFormat2Table, rangeRecordArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -39,10 +39,10 @@ U_NAMESPACE_BEGIN -le_uint32 CursiveAttachmentSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 CursiveAttachmentSubtable::process(const LEReferenceTo<CursiveAttachmentSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID glyphID = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyphID); + le_int32 coverageIndex = getGlyphCoverage(base, glyphID, success); le_uint16 eeCount = SWAPW(entryExitCount); if (coverageIndex < 0 || coverageIndex >= eeCount) { @@ -51,7 +51,7 @@ } LEPoint entryAnchor, exitAnchor; - Offset entryOffset = SWAPW(entryExitRecords[coverageIndex].entryAnchor); + Offset entryOffset = SWAPW(entryExitRecords[coverageIndex].entryAnchor); // TODO Offset exitOffset = SWAPW(entryExitRecords[coverageIndex].exitAnchor); if (entryOffset != 0) {
--- a/src/share/native/sun/font/layout/CursiveAttachmentSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/CursiveAttachmentSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -57,8 +57,9 @@ le_uint16 entryExitCount; EntryExitRecord entryExitRecords[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo<CursiveAttachmentSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; +LE_VAR_ARRAY(CursiveAttachmentSubtable, entryExitRecords) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/DeviceTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/DeviceTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -57,6 +57,7 @@ static const le_uint16 fieldSignBits[]; static const le_uint16 fieldBits[]; }; +LE_VAR_ARRAY(DeviceTable, deltaValues) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/ExtensionSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ExtensionSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -47,6 +47,8 @@ le_uint32 ExtensionSubtable::process(const LookupProcessor *lookupProcessor, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const { + const LEReferenceTo<ExtensionSubtable> thisRef(lookupProcessor->getReference(), success); // create a reference to this + if (LE_FAILURE(success)) { return 0; } @@ -55,9 +57,11 @@ if (elt != lookupType) { le_uint32 extOffset = READ_LONG(extensionOffset); - LookupSubtable *subtable = (LookupSubtable *) ((char *) this + extOffset); + LEReferenceTo<LookupSubtable> subtable(thisRef, success, extOffset); - return lookupProcessor->applySubtable(subtable, elt, glyphIterator, fontInstance, success); + if(LE_SUCCESS(success)) { + return lookupProcessor->applySubtable(subtable, elt, glyphIterator, fontInstance, success); + } } return 0;
--- a/src/share/native/sun/font/layout/Features.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/Features.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -38,19 +38,20 @@ U_NAMESPACE_BEGIN -const FeatureTable *FeatureListTable::getFeatureTable(le_uint16 featureIndex, LETag *featureTag) const +LEReferenceTo<FeatureTable> FeatureListTable::getFeatureTable(const LETableReference &base, le_uint16 featureIndex, LETag *featureTag, LEErrorCode &success) const { - if (featureIndex >= SWAPW(featureCount)) { - return 0; - } + if (featureIndex >= SWAPW(featureCount) || LE_FAILURE(success)) { + return LEReferenceTo<FeatureTable>(); + } Offset featureTableOffset = featureRecordArray[featureIndex].featureTableOffset; *featureTag = SWAPT(featureRecordArray[featureIndex].featureTag); - return (const FeatureTable *) ((char *) this + SWAPW(featureTableOffset)); + return LEReferenceTo<FeatureTable>(base, success, SWAPW(featureTableOffset)); } +#if 0 /* * Note: according to the OpenType Spec. v 1.4, the entries in the Feature * List Table are sorted alphabetically by feature tag; however, there seem @@ -82,5 +83,6 @@ return 0; #endif } +#endif U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/GDEFMarkFilter.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GDEFMarkFilter.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -36,9 +36,12 @@ U_NAMESPACE_BEGIN -GDEFMarkFilter::GDEFMarkFilter(const GlyphDefinitionTableHeader *gdefTable) +GDEFMarkFilter::GDEFMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success) + : classDefTable(gdefTable->getGlyphClassDefinitionTable(gdefTable, success)) { - classDefTable = gdefTable->getGlyphClassDefinitionTable(); + if(!classDefTable.isValid()) { + success = LE_INTERNAL_ERROR; + } } GDEFMarkFilter::~GDEFMarkFilter()
--- a/src/share/native/sun/font/layout/GDEFMarkFilter.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GDEFMarkFilter.h Wed Apr 17 02:53:02 2013 -0700 @@ -46,13 +46,13 @@ class GDEFMarkFilter : public UMemory, public LEGlyphFilter { private: - const GlyphClassDefinitionTable *classDefTable; + const LEReferenceTo<GlyphClassDefinitionTable> classDefTable; GDEFMarkFilter(const GDEFMarkFilter &other); // forbid copying of this class GDEFMarkFilter &operator=(const GDEFMarkFilter &other); // forbid copying of this class public: - GDEFMarkFilter(const GlyphDefinitionTableHeader *gdefTable); + GDEFMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success); virtual ~GDEFMarkFilter(); virtual le_bool accept(LEGlyphID glyph) const;
--- a/src/share/native/sun/font/layout/GXLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GXLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -41,9 +41,10 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GXLayoutEngine) -GXLayoutEngine::GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader *morphTable, LEErrorCode &success) + GXLayoutEngine::GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const LEReferenceTo<MorphTableHeader> &morphTable, LEErrorCode &success) : LayoutEngine(fontInstance, scriptCode, languageCode, 0, success), fMorphTable(morphTable) { + fMorphTable.orphan(); // nothing else to do? } @@ -70,7 +71,7 @@ return 0; } - fMorphTable->process(glyphStorage); + fMorphTable->process(fMorphTable, glyphStorage, success); return count; }
--- a/src/share/native/sun/font/layout/GXLayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GXLayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -74,7 +74,7 @@ * * @internal */ - GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader *morphTable, LEErrorCode &success); + GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const LEReferenceTo<MorphTableHeader> &morphTable, LEErrorCode &success); /** * The destructor, virtual for correct polymorphic invocation. @@ -104,7 +104,7 @@ * * @internal */ - const MorphTableHeader *fMorphTable; + LEReferenceTo<MorphTableHeader> fMorphTable; /** * This method does GX layout using the font's 'mort' table. It converts the
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/GXLayoutEngine2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,91 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "LayoutEngine.h" +#include "GXLayoutEngine2.h" +#include "LEGlyphStorage.h" +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GXLayoutEngine2) + +GXLayoutEngine2::GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const LEReferenceTo<MorphTableHeader2> &morphTable, le_int32 typoFlags, LEErrorCode &success) + : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fMorphTable(morphTable) +{ + // nothing else to do? +} + +GXLayoutEngine2::~GXLayoutEngine2() +{ + reset(); +} + +// apply 'morx' table +le_int32 GXLayoutEngine2::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + if (LE_FAILURE(success)) { + return 0; + } + + if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { + success = LE_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); + + if (LE_FAILURE(success)) { + return 0; + } + + fMorphTable->process(fMorphTable, glyphStorage, fTypoFlags, success); + return count; +} + +// apply positional tables +void GXLayoutEngine2::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/, + LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success) +{ + if (LE_FAILURE(success)) { + return; + } + + if (chars == NULL || offset < 0 || count < 0) { + success = LE_ILLEGAL_ARGUMENT_ERROR; + return; + } + + // FIXME: no positional processing yet... +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/GXLayoutEngine2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,149 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __GXLAYOUTENGINE2_H +#define __GXLAYOUTENGINE2_H + +#include "LETypes.h" +#include "LayoutEngine.h" + +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +class LEFontInstance; +class LEGlyphStorage; + +/** + * This class implements layout for QuickDraw GX or Apple Advanced Typograyph (AAT) + * fonts. A font is a GX or AAT font if it contains a 'mort' table. See Apple's + * TrueType Reference Manual (http://fonts.apple.com/TTRefMan/index.html) for details. + * Information about 'mort' tables is in the chapter titled "Font Files." + * + * @internal + */ +class GXLayoutEngine2 : public LayoutEngine +{ +public: + /** + * This is the main constructor. It constructs an instance of GXLayoutEngine for + * a particular font, script and language. It takes the 'mort' table as a parameter since + * LayoutEngine::layoutEngineFactory has to read the 'mort' table to know that it has a + * GX font. + * + * Note: GX and AAT fonts don't contain any script and language specific tables, so + * the script and language are ignored. + * + * @param fontInstance - the font + * @param scriptCode - the script + * @param langaugeCode - the language + * @param morphTable - the 'mort' table + * @param success - set to an error code if the operation fails + * + * @see LayoutEngine::layoutEngineFactory + * @see ScriptAndLangaugeTags.h for script and language codes + * + * @internal + */ + GXLayoutEngine2(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const LEReferenceTo<MorphTableHeader2> &morphTable, le_int32 typoFlags, LEErrorCode &success); + + /** + * The destructor, virtual for correct polymorphic invocation. + * + * @internal + */ + virtual ~GXLayoutEngine2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +protected: + + /** + * The address of the 'mort' table + * + * @internal + */ + const LEReferenceTo<MorphTableHeader2> fMorphTable; + + /** + * This method does GX layout using the font's 'mort' table. It converts the + * input character codes to glyph indices using mapCharsToGlyphs, and then + * applies the 'mort' table. + * + * Input parameters: + * @param chars - the input character context + * @param offset - the index of the first character to process + * @param count - the number of characters to process + * @param max - the number of characters in the input context + * @param rightToLeft - <code>TRUE</code> if the text is in a right to left directional run + * @param glyphStorage - the glyph storage object. The glyph and char index arrays will be set. + * + * Output parameters: + * @param success - set to an error code if the operation fails + * + * @return the number of glyphs in the glyph index array + * + * @internal + */ + virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, + LEGlyphStorage &glyphStorage, LEErrorCode &success); + + /** + * This method adjusts the glyph positions using the font's + * 'kern', 'trak', 'bsln', 'opbd' and 'just' tables. + * + * Input parameters: + * @param glyphStorage - the object holding the glyph storage. The positions will be updated as needed. + * + * Output parameters: + * @param success - set to an error code if the operation fails + * + * @internal + */ + virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, + LEGlyphStorage &glyphStorage, LEErrorCode &success); + +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/GlyphDefinitionTables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphDefinitionTables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -36,24 +36,36 @@ U_NAMESPACE_BEGIN -const GlyphClassDefinitionTable *GlyphDefinitionTableHeader::getGlyphClassDefinitionTable() const +const LEReferenceTo<GlyphClassDefinitionTable> +GlyphDefinitionTableHeader::getGlyphClassDefinitionTable(const LEReferenceTo<GlyphDefinitionTableHeader>& base, + LEErrorCode &success) const { - return (const GlyphClassDefinitionTable *) ((char *) this + SWAPW(glyphClassDefOffset)); + if(LE_FAILURE(success)) return LEReferenceTo<GlyphClassDefinitionTable>(); + return LEReferenceTo<GlyphClassDefinitionTable>(base, success, SWAPW(glyphClassDefOffset)); } -const AttachmentListTable *GlyphDefinitionTableHeader::getAttachmentListTable() const +const LEReferenceTo<AttachmentListTable> +GlyphDefinitionTableHeader::getAttachmentListTable(const LEReferenceTo<GlyphDefinitionTableHeader>& base, + LEErrorCode &success) const { - return (const AttachmentListTable *) ((char *) this + SWAPW(attachListOffset)); + if(LE_FAILURE(success)) return LEReferenceTo<AttachmentListTable>(); + return LEReferenceTo<AttachmentListTable>(base, success, SWAPW(attachListOffset)); } -const LigatureCaretListTable *GlyphDefinitionTableHeader::getLigatureCaretListTable() const +const LEReferenceTo<LigatureCaretListTable> +GlyphDefinitionTableHeader::getLigatureCaretListTable(const LEReferenceTo<GlyphDefinitionTableHeader>& base, + LEErrorCode &success) const { - return (const LigatureCaretListTable *) ((char *) this + SWAPW(ligCaretListOffset)); + if(LE_FAILURE(success)) return LEReferenceTo<LigatureCaretListTable>(); + return LEReferenceTo<LigatureCaretListTable>(base, success, SWAPW(ligCaretListOffset)); } -const MarkAttachClassDefinitionTable *GlyphDefinitionTableHeader::getMarkAttachClassDefinitionTable() const +const LEReferenceTo<MarkAttachClassDefinitionTable> +GlyphDefinitionTableHeader::getMarkAttachClassDefinitionTable(const LEReferenceTo<GlyphDefinitionTableHeader>& base, + LEErrorCode &success) const { - return (const MarkAttachClassDefinitionTable *) ((char *) this + SWAPW(MarkAttachClassDefOffset)); + if(LE_FAILURE(success)) return LEReferenceTo<MarkAttachClassDefinitionTable>(); + return LEReferenceTo<MarkAttachClassDefinitionTable>(base, success, SWAPW(MarkAttachClassDefOffset)); } U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/GlyphDefinitionTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphDefinitionTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -60,12 +60,14 @@ le_uint16 glyphCount; Offset attachPointTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(AttachmentListTable, attachPointTableOffsetArray) struct AttachPointTable { le_uint16 pointCount; le_uint16 pointIndexArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(AttachPointTable, pointIndexArray) struct LigatureCaretListTable { @@ -73,12 +75,14 @@ le_uint16 ligGlyphCount; Offset ligGlyphTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureCaretListTable, ligGlyphTableOffsetArray) struct LigatureGlyphTable { le_uint16 caretCount; Offset caretValueTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureGlyphTable, caretValueTableOffsetArray) struct CaretValueTable { @@ -111,10 +115,18 @@ Offset ligCaretListOffset; Offset MarkAttachClassDefOffset; - const GlyphClassDefinitionTable *getGlyphClassDefinitionTable() const; - const AttachmentListTable *getAttachmentListTable()const ; - const LigatureCaretListTable *getLigatureCaretListTable() const; - const MarkAttachClassDefinitionTable *getMarkAttachClassDefinitionTable() const; + const LEReferenceTo<GlyphClassDefinitionTable> + getGlyphClassDefinitionTable(const LEReferenceTo<GlyphDefinitionTableHeader>& base, + LEErrorCode &success) const; + const LEReferenceTo<AttachmentListTable> + getAttachmentListTable(const LEReferenceTo<GlyphDefinitionTableHeader>& base, + LEErrorCode &success)const ; + const LEReferenceTo<LigatureCaretListTable> + getLigatureCaretListTable(const LEReferenceTo<GlyphDefinitionTableHeader>& base, + LEErrorCode &success) const; + const LEReferenceTo<MarkAttachClassDefinitionTable> + getMarkAttachClassDefinitionTable(const LEReferenceTo<GlyphDefinitionTableHeader>& base, + LEErrorCode &success) const; }; U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/GlyphIterator.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphIterator.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -41,18 +41,21 @@ U_NAMESPACE_BEGIN GlyphIterator::GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags, - FeatureMask theFeatureMask, const GlyphDefinitionTableHeader *theGlyphDefinitionTableHeader) + FeatureMask theFeatureMask, const LEReferenceTo<GlyphDefinitionTableHeader> &theGlyphDefinitionTableHeader) : direction(1), position(-1), nextLimit(-1), prevLimit(-1), glyphStorage(theGlyphStorage), glyphPositionAdjustments(theGlyphPositionAdjustments), srcIndex(-1), destIndex(-1), lookupFlags(theLookupFlags), featureMask(theFeatureMask), glyphGroup(0), - glyphClassDefinitionTable(NULL), markAttachClassDefinitionTable(NULL) + glyphClassDefinitionTable(), markAttachClassDefinitionTable() { + LEErrorCode success = LE_NO_ERROR; // TODO le_int32 glyphCount = glyphStorage.getGlyphCount(); - if (theGlyphDefinitionTableHeader != NULL) { - glyphClassDefinitionTable = theGlyphDefinitionTableHeader->getGlyphClassDefinitionTable(); - markAttachClassDefinitionTable = theGlyphDefinitionTableHeader->getMarkAttachClassDefinitionTable(); + if (theGlyphDefinitionTableHeader.isValid()) { + glyphClassDefinitionTable = theGlyphDefinitionTableHeader + -> getGlyphClassDefinitionTable(theGlyphDefinitionTableHeader, success); + markAttachClassDefinitionTable = theGlyphDefinitionTableHeader + ->getMarkAttachClassDefinitionTable(theGlyphDefinitionTableHeader, success); } nextLimit = glyphCount; @@ -380,6 +383,7 @@ le_bool GlyphIterator::filterGlyph(le_uint32 index) const { + LEErrorCode success = LE_NO_ERROR; LEGlyphID glyphID = glyphStorage[index]; le_int32 glyphClass = gcdNoGlyphClass; @@ -387,8 +391,8 @@ return TRUE; } - if (glyphClassDefinitionTable != NULL) { - glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphID); + if (glyphClassDefinitionTable.isValid()) { + glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphClassDefinitionTable, glyphID, success); } switch (glyphClass) @@ -410,8 +414,9 @@ le_uint16 markAttachType = (lookupFlags & lfMarkAttachTypeMask) >> lfMarkAttachTypeShift; - if ((markAttachType != 0) && (markAttachClassDefinitionTable != NULL)) { - return markAttachClassDefinitionTable->getGlyphClass(glyphID) != markAttachType; + if ((markAttachType != 0) && (markAttachClassDefinitionTable.isValid())) { + return markAttachClassDefinitionTable + -> getGlyphClass(markAttachClassDefinitionTable, glyphID, success) != markAttachType; } return FALSE; @@ -461,6 +466,7 @@ while (newPosition != nextLimit && delta > 0) { do { newPosition += direction; + //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta); } while (newPosition != nextLimit && filterGlyph(newPosition)); delta -= 1; @@ -468,6 +474,7 @@ position = newPosition; + //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta); return position != nextLimit; } @@ -483,6 +490,7 @@ while (newPosition != prevLimit && delta > 0) { do { newPosition -= direction; + //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta); } while (newPosition != prevLimit && filterGlyph(newPosition)); delta -= 1; @@ -490,6 +498,7 @@ position = newPosition; + //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta); return position != prevLimit; }
--- a/src/share/native/sun/font/layout/GlyphIterator.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphIterator.h Wed Apr 17 02:53:02 2013 -0700 @@ -49,7 +49,7 @@ class GlyphIterator : public UMemory { public: GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags, - FeatureMask theFeatureMask, const GlyphDefinitionTableHeader *theGlyphDefinitionTableHeader); + FeatureMask theFeatureMask, const LEReferenceTo<GlyphDefinitionTableHeader> &theGlyphDefinitionTableHeader); GlyphIterator(GlyphIterator &that); @@ -117,8 +117,8 @@ FeatureMask featureMask; le_int32 glyphGroup; - const GlyphClassDefinitionTable *glyphClassDefinitionTable; - const MarkAttachClassDefinitionTable *markAttachClassDefinitionTable; + LEReferenceTo<GlyphClassDefinitionTable> glyphClassDefinitionTable; + LEReferenceTo<MarkAttachClassDefinitionTable> markAttachClassDefinitionTable; GlyphIterator &operator=(const GlyphIterator &other); // forbid copying of this class };
--- a/src/share/native/sun/font/layout/GlyphLookupTables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphLookupTables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -37,21 +37,22 @@ U_NAMESPACE_BEGIN -le_bool GlyphLookupTableHeader::coversScript(LETag scriptTag) const +le_bool GlyphLookupTableHeader::coversScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const { - const ScriptListTable *scriptListTable = (const ScriptListTable *) ((char *)this + SWAPW(scriptListOffset)); + LEReferenceTo<ScriptListTable> scriptListTable(base, success, SWAPW(scriptListOffset)); - return scriptListOffset != 0 && scriptListTable->findScript(scriptTag) != NULL; + return (scriptListOffset != 0) && scriptListTable->findScript(scriptListTable, scriptTag, success) .isValid(); } -le_bool GlyphLookupTableHeader::coversScriptAndLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch) const +le_bool GlyphLookupTableHeader::coversScriptAndLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const { - const ScriptListTable *scriptListTable = (const ScriptListTable *) ((char *)this + SWAPW(scriptListOffset)); - const LangSysTable *langSysTable = scriptListTable->findLanguage(scriptTag, languageTag, exactMatch); + LEReferenceTo<ScriptListTable> scriptListTable(base, success, SWAPW(scriptListOffset)); + LEReferenceTo<LangSysTable> langSysTable = scriptListTable->findLanguage(scriptListTable, + scriptTag, languageTag, success, exactMatch); // FIXME: could check featureListOffset, lookupListOffset, and lookup count... // Note: don't have to SWAPW langSysTable->featureCount to check for non-zero. - return langSysTable != NULL && langSysTable->featureCount != 0; + return LE_SUCCESS(success)&&langSysTable.isValid() && langSysTable->featureCount != 0; } U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/GlyphLookupTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphLookupTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -49,8 +49,8 @@ Offset featureListOffset; Offset lookupListOffset; - le_bool coversScript(LETag scriptTag) const; - le_bool coversScriptAndLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch = FALSE) const; + le_bool coversScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const; + le_bool coversScriptAndLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch = FALSE) const; }; U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/GlyphPositioningTables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphPositioningTables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -41,16 +41,16 @@ U_NAMESPACE_BEGIN -void GlyphPositioningTableHeader::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, le_bool rightToLeft, +void GlyphPositioningTableHeader::process(const LEReferenceTo<GlyphPositioningTableHeader> &base, LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, le_bool rightToLeft, LETag scriptTag, LETag languageTag, - const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, LEErrorCode &success, + const LEReferenceTo<GlyphDefinitionTableHeader> &glyphDefinitionTableHeader, LEErrorCode &success, const LEFontInstance *fontInstance, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool featureOrder) const { if (LE_FAILURE(success)) { return; } - GlyphPositioningLookupProcessor processor(this, scriptTag, languageTag, featureMap, featureMapCount, featureOrder, success); + GlyphPositioningLookupProcessor processor(base, scriptTag, languageTag, featureMap, featureMapCount, featureOrder, success); if (LE_FAILURE(success)) { return; }
--- a/src/share/native/sun/font/layout/GlyphPositioningTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphPositioningTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -40,6 +40,7 @@ #include "OpenTypeTables.h" #include "Lookups.h" #include "GlyphLookupTables.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -51,9 +52,9 @@ struct GlyphPositioningTableHeader : public GlyphLookupTableHeader { - void process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, + void process(const LEReferenceTo<GlyphPositioningTableHeader> &base, LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, le_bool rightToLeft, LETag scriptTag, LETag languageTag, - const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, LEErrorCode &success, + const LEReferenceTo<GlyphDefinitionTableHeader> &glyphDefinitionTableHeader, LEErrorCode &success, const LEFontInstance *fontInstance, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool featureOrder) const; };
--- a/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -57,7 +57,7 @@ typedef ChainingContextualSubstitutionSubtable ChainingContextualPositioningSubtable; GlyphPositioningLookupProcessor::GlyphPositioningLookupProcessor( - const GlyphPositioningTableHeader *glyphPositioningTableHeader, + const LEReferenceTo<GlyphPositioningTableHeader> &glyphPositioningTableHeader, LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, @@ -65,7 +65,7 @@ le_bool featureOrder, LEErrorCode& success) : LookupProcessor( - (char *) glyphPositioningTableHeader, + glyphPositioningTableHeader, SWAPW(glyphPositioningTableHeader->scriptListOffset), SWAPW(glyphPositioningTableHeader->featureListOffset), SWAPW(glyphPositioningTableHeader->lookupListOffset), @@ -84,7 +84,7 @@ { } -le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, +le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LEReferenceTo<LookupSubtable> &lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const @@ -102,55 +102,55 @@ case gpstSingle: { - const SinglePositioningSubtable *subtable = (const SinglePositioningSubtable *) lookupSubtable; + LEReferenceTo<SinglePositioningSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstPair: { - const PairPositioningSubtable *subtable = (const PairPositioningSubtable *) lookupSubtable; + LEReferenceTo<PairPositioningSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstCursive: { - const CursiveAttachmentSubtable *subtable = (const CursiveAttachmentSubtable *) lookupSubtable; + LEReferenceTo<CursiveAttachmentSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstMarkToBase: { - const MarkToBasePositioningSubtable *subtable = (const MarkToBasePositioningSubtable *) lookupSubtable; + LEReferenceTo<MarkToBasePositioningSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstMarkToLigature: { - const MarkToLigaturePositioningSubtable *subtable = (const MarkToLigaturePositioningSubtable *) lookupSubtable; + LEReferenceTo<MarkToLigaturePositioningSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstMarkToMark: { - const MarkToMarkPositioningSubtable *subtable = (const MarkToMarkPositioningSubtable *) lookupSubtable; + LEReferenceTo<MarkToMarkPositioningSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fontInstance); + delta = subtable->process(subtable, glyphIterator, fontInstance, success); break; } case gpstContext: { - const ContextualPositioningSubtable *subtable = (const ContextualPositioningSubtable *) lookupSubtable; + LEReferenceTo<ContextualPositioningSubtable> subtable(lookupSubtable, success); delta = subtable->process(this, glyphIterator, fontInstance, success); break; @@ -158,7 +158,7 @@ case gpstChainedContext: { - const ChainingContextualPositioningSubtable *subtable = (const ChainingContextualPositioningSubtable *) lookupSubtable; + LEReferenceTo<ChainingContextualPositioningSubtable> subtable(lookupSubtable, success); delta = subtable->process(this, glyphIterator, fontInstance, success); break; @@ -166,7 +166,7 @@ case gpstExtension: { - const ExtensionSubtable *subtable = (const ExtensionSubtable *) lookupSubtable; + LEReferenceTo<ExtensionSubtable> subtable(lookupSubtable, success); delta = subtable->process(this, lookupType, glyphIterator, fontInstance, success); break;
--- a/src/share/native/sun/font/layout/GlyphPosnLookupProc.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphPosnLookupProc.h Wed Apr 17 02:53:02 2013 -0700 @@ -51,7 +51,7 @@ class GlyphPositioningLookupProcessor : public LookupProcessor { public: - GlyphPositioningLookupProcessor(const GlyphPositioningTableHeader *glyphPositioningTableHeader, + GlyphPositioningLookupProcessor(const LEReferenceTo<GlyphPositioningTableHeader> &glyphPositioningTableHeader, LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, @@ -61,7 +61,7 @@ virtual ~GlyphPositioningLookupProcessor(); - virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, + virtual le_uint32 applySubtable(const LEReferenceTo<LookupSubtable> &lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; protected:
--- a/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -51,7 +51,7 @@ U_NAMESPACE_BEGIN GlyphSubstitutionLookupProcessor::GlyphSubstitutionLookupProcessor( - const GlyphSubstitutionTableHeader *glyphSubstitutionTableHeader, + const LEReferenceTo<GlyphSubstitutionTableHeader> &glyphSubstitutionTableHeader, LETag scriptTag, LETag languageTag, const LEGlyphFilter *filter, @@ -60,7 +60,7 @@ le_bool featureOrder, LEErrorCode& success) : LookupProcessor( - (char *) glyphSubstitutionTableHeader, + glyphSubstitutionTableHeader, SWAPW(glyphSubstitutionTableHeader->scriptListOffset), SWAPW(glyphSubstitutionTableHeader->featureListOffset), SWAPW(glyphSubstitutionTableHeader->lookupListOffset), @@ -73,7 +73,7 @@ { } -le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, +le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LEReferenceTo<LookupSubtable> &lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const { if (LE_FAILURE(success)) { @@ -89,39 +89,39 @@ case gsstSingle: { - const SingleSubstitutionSubtable *subtable = (const SingleSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo<SingleSubstitutionSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fFilter); + delta = subtable->process(subtable, glyphIterator, success, fFilter); break; } case gsstMultiple: { - const MultipleSubstitutionSubtable *subtable = (const MultipleSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo<MultipleSubstitutionSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, success, fFilter); + delta = subtable->process(subtable, glyphIterator, success, fFilter); break; } case gsstAlternate: { - const AlternateSubstitutionSubtable *subtable = (const AlternateSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo<AlternateSubstitutionSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fFilter); + delta = subtable->process(subtable, glyphIterator, success, fFilter); break; } case gsstLigature: { - const LigatureSubstitutionSubtable *subtable = (const LigatureSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo<LigatureSubstitutionSubtable> subtable(lookupSubtable, success); - delta = subtable->process(glyphIterator, fFilter); + delta = subtable->process(subtable, glyphIterator, success, fFilter); break; } case gsstContext: { - const ContextualSubstitutionSubtable *subtable = (const ContextualSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo<ContextualSubstitutionSubtable> subtable(lookupSubtable, success); delta = subtable->process(this, glyphIterator, fontInstance, success); break; @@ -129,7 +129,7 @@ case gsstChainingContext: { - const ChainingContextualSubstitutionSubtable *subtable = (const ChainingContextualSubstitutionSubtable *) lookupSubtable; + const LEReferenceTo<ChainingContextualSubstitutionSubtable> subtable(lookupSubtable, success); delta = subtable->process(this, glyphIterator, fontInstance, success); break; @@ -137,7 +137,7 @@ case gsstExtension: { - const ExtensionSubtable *subtable = (const ExtensionSubtable *) lookupSubtable; + const LEReferenceTo<ExtensionSubtable> subtable(lookupSubtable, success); delta = subtable->process(this, lookupType, glyphIterator, fontInstance, success); break;
--- a/src/share/native/sun/font/layout/GlyphSubstLookupProc.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphSubstLookupProc.h Wed Apr 17 02:53:02 2013 -0700 @@ -52,7 +52,7 @@ class GlyphSubstitutionLookupProcessor : public LookupProcessor { public: - GlyphSubstitutionLookupProcessor(const GlyphSubstitutionTableHeader *glyphSubstitutionTableHeader, + GlyphSubstitutionLookupProcessor(const LEReferenceTo<GlyphSubstitutionTableHeader> &glyphSubstitutionTableHeader, LETag scriptTag, LETag languageTag, const LEGlyphFilter *filter, @@ -63,7 +63,7 @@ virtual ~GlyphSubstitutionLookupProcessor(); - virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, + virtual le_uint32 applySubtable(const LEReferenceTo<LookupSubtable> &lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; protected:
--- a/src/share/native/sun/font/layout/GlyphSubstitutionTables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphSubstitutionTables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -42,11 +42,12 @@ U_NAMESPACE_BEGIN -le_int32 GlyphSubstitutionTableHeader::process(LEGlyphStorage &glyphStorage, +le_int32 GlyphSubstitutionTableHeader::process(const LEReferenceTo<GlyphSubstitutionTableHeader> &base, + LEGlyphStorage &glyphStorage, le_bool rightToLeft, LETag scriptTag, LETag languageTag, - const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, + const LEReferenceTo<GlyphDefinitionTableHeader> &glyphDefinitionTableHeader, const LEGlyphFilter *filter, const FeatureMap *featureMap, le_int32 featureMapCount, @@ -57,7 +58,7 @@ return 0; } - GlyphSubstitutionLookupProcessor processor(this, scriptTag, languageTag, filter, featureMap, featureMapCount, featureOrder, success); + GlyphSubstitutionLookupProcessor processor(base, scriptTag, languageTag, filter, featureMap, featureMapCount, featureOrder, success); return processor.process(glyphStorage, NULL, rightToLeft, glyphDefinitionTableHeader, NULL, success); }
--- a/src/share/native/sun/font/layout/GlyphSubstitutionTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/GlyphSubstitutionTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -50,11 +50,12 @@ struct GlyphSubstitutionTableHeader : public GlyphLookupTableHeader { - le_int32 process(LEGlyphStorage &glyphStorage, + le_int32 process(const LEReferenceTo<GlyphSubstitutionTableHeader> &base, + LEGlyphStorage &glyphStorage, le_bool rightToLeft, LETag scriptTag, LETag languageTag, - const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, + const LEReferenceTo<GlyphDefinitionTableHeader> &glyphDefinitionTableHeader, const LEGlyphFilter *filter, const FeatureMap *featureMap, le_int32 featureMapCount,
--- a/src/share/native/sun/font/layout/HanLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/HanLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -64,7 +64,7 @@ #define features (loclFeatureMask) HanOpenTypeLayoutEngine::HanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) { fFeatureMap = featureMap;
--- a/src/share/native/sun/font/layout/HanLayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/HanLayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -73,7 +73,7 @@ * @internal */ HanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTablem, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTablem, LEErrorCode &success); /**
--- a/src/share/native/sun/font/layout/HangulLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/HangulLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -209,7 +209,7 @@ } HangulOpenTypeLayoutEngine::HangulOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 /*languageCode*/, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, korLanguageCode, typoFlags, gsubTable, success) { fFeatureMap = featureMap;
--- a/src/share/native/sun/font/layout/HangulLayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/HangulLayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -79,7 +79,7 @@ * @internal */ HangulOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known
--- a/src/share/native/sun/font/layout/ICUFeatures.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ICUFeatures.h Wed Apr 17 02:53:02 2013 -0700 @@ -54,16 +54,21 @@ le_uint16 lookupCount; le_uint16 lookupListIndexArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(FeatureTable, lookupListIndexArray) struct FeatureListTable { le_uint16 featureCount; FeatureRecord featureRecordArray[ANY_NUMBER]; - const FeatureTable *getFeatureTable(le_uint16 featureIndex, LETag *featureTag) const; + LEReferenceTo<FeatureTable> getFeatureTable(const LETableReference &base, le_uint16 featureIndex, LETag *featureTag, LEErrorCode &success) const; - const FeatureTable *getFeatureTable(LETag featureTag) const; +#if 0 + const LEReferenceTo<FeatureTable> getFeatureTable(const LETableReference &base, LETag featureTag, LEErrorCode &success) const; +#endif }; +LE_VAR_ARRAY(FeatureListTable, featureRecordArray) + U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/IndicClassTables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/IndicClassTables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -186,13 +186,15 @@ }; // FIXME: Should some of the bb's be pb's? (KA, NA, MA, YA, VA, etc. (approx 13)) +// U+C43 and U+C44 are _lm here not _dr. Similar to the situation with U+CC3 and +// U+CC4 in Kannada below. static const IndicClassTable::CharClass teluCharClasses[] = { _xx, _mp, _mp, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _iv, _iv, // 0C00 - 0C0F _iv, _xx, _iv, _iv, _iv, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, // 0C10 - 0C1F _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _bb, // 0C20 - 0C2F _bb, _bb, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _xx, _xx, _xx, _xx, _da, _da, // 0C30 - 0C3F - _da, _dr, _dr, _dr, _dr, _xx, _a1, _da, _s1, _xx, _da, _da, _da, _vr, _xx, _xx, // 0C40 - 0C4F + _da, _dr, _dr, _lm, _lm, _xx, _a1, _da, _s1, _xx, _da, _da, _da, _vr, _xx, _xx, // 0C40 - 0C4F _xx, _xx, _xx, _xx, _xx, _da, _m2, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0C50 - 0C5F _iv, _iv, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx // 0C60 - 0C6F };
--- a/src/share/native/sun/font/layout/IndicLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/IndicLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -50,7 +50,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicOpenTypeLayoutEngine) IndicOpenTypeLayoutEngine::IndicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, le_bool version2, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, le_bool version2, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success), fMPreFixups(NULL) { if ( version2 ) {
--- a/src/share/native/sun/font/layout/IndicLayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/IndicLayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -81,7 +81,7 @@ * @internal */ IndicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, le_bool version2, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, le_bool version2, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known
--- a/src/share/native/sun/font/layout/IndicRearrangement.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/IndicRearrangement.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -49,6 +49,10 @@ { }; +struct IndicRearrangementSubtableHeader2 : MorphStateTableHeader2 +{ +}; + enum IndicRearrangementFlags { irfMarkFirst = 0x8000, @@ -85,6 +89,10 @@ { }; +struct IndicRearrangementStateEntry2 : StateEntry2 +{ +}; + U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/IndicRearrangementProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/IndicRearrangementProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -43,11 +43,14 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor) -IndicRearrangementProcessor::IndicRearrangementProcessor(const MorphSubtableHeader *morphSubtableHeader) - : StateTableProcessor(morphSubtableHeader) + IndicRearrangementProcessor::IndicRearrangementProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor(morphSubtableHeader, success), + indicRearrangementSubtableHeader(morphSubtableHeader, success), + entryTable(stateTableHeader, success, (const IndicRearrangementStateEntry*)(&stateTableHeader->stHeader), + entryTableOffset, LE_UNBOUNDED_ARRAY), + int16Table(stateTableHeader, success, (const le_int16*)entryTable.getAlias(), 0, LE_UNBOUNDED_ARRAY) + { - indicRearrangementSubtableHeader = (const IndicRearrangementSubtableHeader *) morphSubtableHeader; - entryTable = (const IndicRearrangementStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset); } IndicRearrangementProcessor::~IndicRearrangementProcessor() @@ -62,7 +65,8 @@ ByteOffset IndicRearrangementProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index) { - const IndicRearrangementStateEntry *entry = &entryTable[index]; + LEErrorCode success = LE_NO_ERROR; // todo- make a param? + const IndicRearrangementStateEntry *entry = entryTable.getAlias(index,success); ByteOffset newState = SWAPW(entry->newStateOffset); IndicRearrangementFlags flags = (IndicRearrangementFlags) SWAPW(entry->flags);
--- a/src/share/native/sun/font/layout/IndicRearrangementProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/IndicRearrangementProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -58,7 +58,7 @@ void doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const; - IndicRearrangementProcessor(const MorphSubtableHeader *morphSubtableHeader); + IndicRearrangementProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~IndicRearrangementProcessor(); /** @@ -79,8 +79,9 @@ le_int32 firstGlyph; le_int32 lastGlyph; - const IndicRearrangementStateEntry *entryTable; - const IndicRearrangementSubtableHeader *indicRearrangementSubtableHeader; + LEReferenceTo<IndicRearrangementSubtableHeader> indicRearrangementSubtableHeader; + LEReferenceToArrayOf<IndicRearrangementStateEntry> entryTable; + LEReferenceToArrayOf<le_int16> int16Table; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,425 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "IndicRearrangementProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor2) + +IndicRearrangementProcessor2::IndicRearrangementProcessor2( + const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor2(morphSubtableHeader, success), indicRearrangementSubtableHeader(morphSubtableHeader, success), + entryTable(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY) +{ +} + +IndicRearrangementProcessor2::~IndicRearrangementProcessor2() +{ +} + +void IndicRearrangementProcessor2::beginStateTable() +{ + firstGlyph = 0; + lastGlyph = 0; +} + +le_uint16 IndicRearrangementProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, + EntryTableIndex2 index, LEErrorCode &success) +{ + const IndicRearrangementStateEntry2 *entry = entryTable.getAlias(index, success); + if (LE_FAILURE(success)) return 0; // TODO - what to return in bad state? + le_uint16 newState = SWAPW(entry->newStateIndex); // index to the new state + IndicRearrangementFlags flags = (IndicRearrangementFlags) SWAPW(entry->flags); + + if (flags & irfMarkFirst) { + firstGlyph = currGlyph; + } + + if (flags & irfMarkLast) { + lastGlyph = currGlyph; + } + + doRearrangementAction(glyphStorage, (IndicRearrangementVerb) (flags & irfVerbMask)); + + if (!(flags & irfDontAdvance)) { + currGlyph += dir; + } + + return newState; // index to new state +} + +void IndicRearrangementProcessor2::endStateTable() +{ +} + +void IndicRearrangementProcessor2::doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const +{ + LEGlyphID a, b, c, d; + le_int32 ia, ib, ic, id, ix, x; + LEErrorCode success = LE_NO_ERROR; + + switch(verb) + { + case irvNoAction: + break; + + case irvxA: + a = glyphStorage[firstGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + x = firstGlyph + 1; + + while (x <= lastGlyph) { + glyphStorage[x - 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 1, ix, success); + x += 1; + } + + glyphStorage[lastGlyph] = a; + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDx: + d = glyphStorage[lastGlyph]; + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 1; + + while (x >= firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage.setCharIndex(firstGlyph, id, success); + break; + + case irvDxA: + a = glyphStorage[firstGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + x = firstGlyph + 2; + + while (x <= lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + x = firstGlyph + 2; + + while (x <= lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvCDx: + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x >= firstGlyph) { + glyphStorage[x + 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 2, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = c; + glyphStorage[firstGlyph + 1] = d; + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + break; + + case irvDCx: + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x >= firstGlyph) { + glyphStorage[x + 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 2, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[firstGlyph + 1] = c; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + break; + + case irvCDxA: + a = glyphStorage[firstGlyph]; + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x > firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = c; + glyphStorage[firstGlyph + 1] = d; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDCxA: + a = glyphStorage[firstGlyph]; + c = glyphStorage[lastGlyph - 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = lastGlyph - 2; + + while (x > firstGlyph) { + glyphStorage[x + 1] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x + 1, ix, success); + x -= 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[firstGlyph + 1] = c; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = firstGlyph + 2; + + while (x < lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvDxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + d = glyphStorage[lastGlyph]; + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + x = firstGlyph + 2; + + while (x < lastGlyph) { + glyphStorage[x - 2] = glyphStorage[x]; + ix = glyphStorage.getCharIndex(x, success); + glyphStorage.setCharIndex(x - 2, ix, success); + x += 1; + } + + glyphStorage[firstGlyph] = d; + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvCDxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvCDxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, ic, success); + glyphStorage.setCharIndex(firstGlyph + 1, id, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + case irvDCxAB: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; + + glyphStorage[lastGlyph - 1] = a; + glyphStorage[lastGlyph] = b; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ia, success); + glyphStorage.setCharIndex(lastGlyph, ib, success); + break; + + case irvDCxBA: + a = glyphStorage[firstGlyph]; + b = glyphStorage[firstGlyph + 1]; + + glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; + glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; + + glyphStorage[lastGlyph - 1] = b; + glyphStorage[lastGlyph] = a; + + ia = glyphStorage.getCharIndex(firstGlyph, success); + ib = glyphStorage.getCharIndex(firstGlyph + 1, success); + ic = glyphStorage.getCharIndex(lastGlyph - 1, success); + id = glyphStorage.getCharIndex(lastGlyph, success); + + glyphStorage.setCharIndex(firstGlyph, id, success); + glyphStorage.setCharIndex(firstGlyph + 1, ic, success); + + glyphStorage.setCharIndex(lastGlyph - 1, ib, success); + glyphStorage.setCharIndex(lastGlyph, ia, success); + break; + + default: + break; + } + +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/IndicRearrangementProcessor2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,88 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __INDICREARRANGEMENTPROCESSOR2_H +#define __INDICREARRANGEMENTPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor.h" +#include "StateTableProcessor2.h" +#include "IndicRearrangement.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class IndicRearrangementProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success); + + virtual void endStateTable(); + + void doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const; + + IndicRearrangementProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + virtual ~IndicRearrangementProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +protected: + le_int32 firstGlyph; + le_int32 lastGlyph; + + LEReferenceToArrayOf<IndicRearrangementStateEntry2> entryTable; + LEReferenceTo<IndicRearrangementSubtableHeader2> indicRearrangementSubtableHeader; + +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/IndicReordering.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/IndicReordering.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -266,7 +266,7 @@ le_uint32 saveAuxData = fGlyphStorage.getAuxData(i+inv_count,success); const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass); int j; - for (j = 0 ; *(splitMatra)[j] != 0 ; j++) { + for (j = 0 ; j < SM_MAX_PIECES && *(splitMatra)[j] != 0 ; j++) { LEUnicode piece = (*splitMatra)[j]; if ( j == 0 ) { fOutChars[i+inv_count] = piece; @@ -357,7 +357,7 @@ const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass); int i; - for (i = 0; i < 3 && (*splitMatra)[i] != 0; i += 1) { + for (i = 0; i < SM_MAX_PIECES && (*splitMatra)[i] != 0; i += 1) { LEUnicode piece = (*splitMatra)[i]; IndicClassTable::CharClass pieceClass = classTable->getCharClass(piece); @@ -658,6 +658,11 @@ MPreFixups *mpreFixups = NULL; const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode); + if(classTable==NULL) { + success = LE_MEMORY_ALLOCATION_ERROR; + return 0; + } + if (classTable->scriptFlags & SF_MPRE_FIXUP) { mpreFixups = new MPreFixups(charCount); if (mpreFixups == NULL) { @@ -1224,7 +1229,6 @@ LEUnicode currentChar; - LEUnicode virama; LEUnicode workChars[2]; LEGlyphStorage workGlyphs; @@ -1232,14 +1236,17 @@ //le_int32 offset = 0; +#if 0 +// TODO: Should this section of code have actually been doing something? // First find the relevant virama for the script we are dealing with - + LEUnicode virama; for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) { if ( classTable->isVirama(currentChar)) { virama = currentChar; break; } } +#endif for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) { if ( classTable->isConsonant(currentChar)) {
--- a/src/share/native/sun/font/layout/IndicReordering.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/IndicReordering.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -96,7 +96,9 @@ #define SF_POST_BASE_LIMIT_MASK 0x0000FFFFU #define SF_NO_POST_BASE_LIMIT 0x00007FFFU -typedef LEUnicode SplitMatra[3]; +#define SM_MAX_PIECES 3 + +typedef LEUnicode SplitMatra[SM_MAX_PIECES]; class MPreFixups; class LEGlyphStorage;
--- a/src/share/native/sun/font/layout/KernTable.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/KernTable.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -48,7 +48,7 @@ le_int16 value; // fword, kern value in funits }; #define KERN_PAIRINFO_SIZE 6 - +LE_CORRECT_SIZE(PairInfo, KERN_PAIRINFO_SIZE) struct Subtable_0 { le_uint16 nPairs; le_uint16 searchRange; @@ -56,6 +56,7 @@ le_uint16 rangeShift; }; #define KERN_SUBTABLE_0_HEADER_SIZE 8 +LE_CORRECT_SIZE(Subtable_0, KERN_SUBTABLE_0_HEADER_SIZE) // Kern table version 0 only struct SubtableHeader { @@ -64,6 +65,7 @@ le_uint16 coverage; }; #define KERN_SUBTABLE_HEADER_SIZE 6 +LE_CORRECT_SIZE(SubtableHeader, KERN_SUBTABLE_HEADER_SIZE) // Version 0 only, version 1 has different layout struct KernTableHeader { @@ -71,6 +73,7 @@ le_uint16 nTables; }; #define KERN_TABLE_HEADER_SIZE 4 +LE_CORRECT_SIZE(KernTableHeader, KERN_TABLE_HEADER_SIZE) #define COVERAGE_HORIZONTAL 0x1 #define COVERAGE_MINIMUM 0x2 @@ -92,21 +95,21 @@ * TODO: support multiple subtables * TODO: respect header flags */ -KernTable::KernTable(const LEFontInstance* font_, const void* tableData) - : pairs(0), font(font_) +KernTable::KernTable(const LETableReference& base, LEErrorCode &success) + : pairs(), pairsSwapped(NULL), fTable(base) { - const KernTableHeader* header = (const KernTableHeader*)tableData; - if (header == 0) { + if(LE_FAILURE(success) || (fTable.isEmpty())) { #if DEBUG fprintf(stderr, "no kern data\n"); #endif return; } + LEReferenceTo<KernTableHeader> header(fTable, success); #if DEBUG // dump first 32 bytes of header for (int i = 0; i < 64; ++i) { - fprintf(stderr, "%0.2x ", ((const char*)tableData)[i]&0xff); + fprintf(stderr, "%0.2x ", ((const char*)header.getAlias())[i]&0xff); if (((i+1)&0xf) == 0) { fprintf(stderr, "\n"); } else if (((i+1)&0x7) == 0) { @@ -115,12 +118,17 @@ } #endif - if (header->version == 0 && SWAPW(header->nTables) > 0) { - const SubtableHeader* subhead = (const SubtableHeader*)((char*)tableData + KERN_TABLE_HEADER_SIZE); - if (subhead->version == 0) { + if(LE_FAILURE(success)) return; + + if (!header.isEmpty() && header->version == 0 && SWAPW(header->nTables) > 0) { + LEReferenceTo<SubtableHeader> subhead(header, success, KERN_TABLE_HEADER_SIZE); + + if (LE_SUCCESS(success) && !subhead.isEmpty() && subhead->version == 0) { coverage = SWAPW(subhead->coverage); if (coverage & COVERAGE_HORIZONTAL) { // only handle horizontal kerning - const Subtable_0* table = (const Subtable_0*)((char*)subhead + KERN_SUBTABLE_HEADER_SIZE); + LEReferenceTo<Subtable_0> table(subhead, success, KERN_SUBTABLE_HEADER_SIZE); + + if(table.isEmpty() || LE_FAILURE(success)) return; nPairs = SWAPW(table->nPairs); @@ -134,19 +142,31 @@ rangeShift = (nPairs * KERN_PAIRINFO_SIZE) - searchRange; #endif - pairs = (PairInfo*)font->getKernPairs(); - if (pairs == NULL) { - char *pairData = (char*)table + KERN_SUBTABLE_0_HEADER_SIZE; - char *pptr = pairData; - pairs = (PairInfo*)(malloc(nPairs*sizeof(PairInfo))); - PairInfo *p = (PairInfo*)pairs; - for (int i = 0; i < nPairs; i++, pptr += KERN_PAIRINFO_SIZE, p++) { - memcpy(p, pptr, KERN_PAIRINFO_SIZE); + if(LE_SUCCESS(success) && nPairs>0) { + // pairs is an instance member, and table is on the stack. + // set 'pairs' based on table.getAlias(). This will range check it. + + pairs = LEReferenceToArrayOf<PairInfo>(fTable, // based on overall table + success, + (const PairInfo*)table.getAlias(), // subtable 0 + .. + KERN_SUBTABLE_0_HEADER_SIZE, // .. offset of header size + nPairs); // count + } + if (LE_SUCCESS(success) && pairs.isValid()) { + pairsSwapped = (PairInfo*)(malloc(nPairs*sizeof(PairInfo))); + PairInfo *p = (PairInfo*)pairsSwapped; + for (int i = 0; LE_SUCCESS(success) && i < nPairs; i++, p++) { + memcpy(p, pairs.getAlias(i,success), KERN_PAIRINFO_SIZE); p->key = SWAPL(p->key); } - font->setKernPairs((void*)pairs); + fTable.getFont()->setKernPairs((void*)pairsSwapped); // store it } +#if 0 + fprintf(stderr, "coverage: %0.4x nPairs: %d pairs %p\n", coverage, nPairs, pairs.getAlias()); + fprintf(stderr, " searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift); + fprintf(stderr, "[[ ignored font table entries: range %d selector %d shift %d ]]\n", SWAPW(table->searchRange), SWAPW(table->entrySelector), SWAPW(table->rangeShift)); +#endif #if DEBUG fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairs); fprintf(stderr, @@ -194,14 +214,17 @@ * Process the glyph positions. The positions array has two floats for each * glyph, plus a trailing pair to mark the end of the last glyph. */ -void KernTable::process(LEGlyphStorage& storage) +void KernTable::process(LEGlyphStorage& storage, LEErrorCode &success) { - if (pairs) { - LEErrorCode success = LE_NO_ERROR; + if(LE_FAILURE(success)) return; + + if (pairsSwapped) { + success = LE_NO_ERROR; le_uint32 key = storage[0]; // no need to mask off high bits float adjust = 0; - for (int i = 1, e = storage.getGlyphCount(); i < e; ++i) { + + for (int i = 1, e = storage.getGlyphCount(); LE_SUCCESS(success)&& i < e; ++i) { key = key << 16 | (storage[i] & 0xffff); // argh, to do a binary search, we need to have the pair list in sorted order @@ -209,7 +232,7 @@ // so either I have to swap the element each time I examine it, or I have to swap // all the elements ahead of time and store them in the font - const PairInfo* p = pairs; + const PairInfo* p = pairsSwapped; const PairInfo* tp = (const PairInfo*)(p + (rangeShift/KERN_PAIRINFO_SIZE)); /* rangeshift is in original table bytes */ if (key > tp->key) { p = tp; @@ -225,7 +248,7 @@ tp = (const PairInfo*)(p + (probe/KERN_PAIRINFO_SIZE)); le_uint32 tkey = tp->key; #if DEBUG - fprintf(stdout, " %.3d (%0.8x)\n", (tp - pairs), tkey); + fprintf(stdout, " %.3d (%0.8x)\n", (tp - pairsSwapped), tkey); #endif if (tkey <= key) { if (tkey == key) { @@ -240,10 +263,10 @@ // device transform, or a faster way, such as moving the // entire kern table up to Java. LEPoint pt; - pt.fX = font->xUnitsToPoints(value); + pt.fX = fTable.getFont()->xUnitsToPoints(value); pt.fY = 0; - font->getKerningAdjustment(pt); + fTable.getFont()->getKerningAdjustment(pt); adjust += pt.fX; break; }
--- a/src/share/native/sun/font/layout/KernTable.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/KernTable.h Wed Apr 17 02:53:02 2013 -0700 @@ -26,7 +26,7 @@ /* * * - * (C) Copyright IBM Corp. 2004-2005 - All Rights Reserved + * (C) Copyright IBM Corp. 2004-2013 - All Rights Reserved * */ @@ -38,6 +38,7 @@ #endif #include "LETypes.h" +#include "LETableReference.h" //#include "LEFontInstance.h" //#include "LEGlyphStorage.h" @@ -56,19 +57,20 @@ private: le_uint16 coverage; le_uint16 nPairs; - const PairInfo* pairs; - const LEFontInstance* font; + LEReferenceToArrayOf<PairInfo> pairs; + PairInfo *pairsSwapped; + const LETableReference &fTable; le_uint16 searchRange; le_uint16 entrySelector; le_uint16 rangeShift; public: - KernTable(const LEFontInstance* font, const void* tableData); + KernTable(const LETableReference &table, LEErrorCode &success); /* * Process the glyph positions. */ - void process(LEGlyphStorage& storage); + void process(LEGlyphStorage& storage, LEErrorCode &success); }; U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/KhmerLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/KhmerLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -43,7 +43,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(KhmerOpenTypeLayoutEngine) KhmerOpenTypeLayoutEngine::KhmerOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) { fFeatureMap = KhmerReordering::getFeatureMap(fFeatureMapCount);
--- a/src/share/native/sun/font/layout/KhmerLayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/KhmerLayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -83,7 +83,7 @@ * @internal */ KhmerOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known
--- a/src/share/native/sun/font/layout/LEFontInstance.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LEFontInstance.h Wed Apr 17 02:53:02 2013 -0700 @@ -190,6 +190,25 @@ */ virtual const void *getFontTable(LETag tableTag) const = 0; + /** + * This method reads a table from the font. Note that in general, + * it only makes sense to call this method on an <code>LEFontInstance</code> + * which represents a physical font - i.e. one which has been returned by + * <code>getSubFont()</code>. This is because each subfont in a composite font + * will have different tables, and there's no way to know which subfont to access. + * + * Subclasses which represent composite fonts should always return <code>NULL</code>. + * + * This version sets a length, for range checking. + * + * @param tableTag - the four byte table tag. (e.g. 'cmap') + * @param length - ignored on entry, on exit will be the length of the table if known, or -1 if unknown. + * @return the address of the table in memory, or <code>NULL</code> + * if the table doesn't exist. + * @internal + */ + virtual const void* getFontTable(LETag tableTag, size_t &length) const { length=-1; return getFontTable(tableTag); } /* -1 = unknown length */ + virtual void *getKernPairs() const = 0; virtual void setKernPairs(void *pairs) const = 0;
--- a/src/share/native/sun/font/layout/LEGlyphFilter.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LEGlyphFilter.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -36,6 +36,7 @@ U_NAMESPACE_BEGIN +#ifndef U_HIDE_INTERNAL_API /** * This is a helper class that is used to * recognize a set of glyph indices. @@ -63,6 +64,7 @@ */ virtual le_bool accept(LEGlyphID glyph) const = 0; }; +#endif /* U_HIDE_INTERNAL_API */ U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/LEInsertionList.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LEInsertionList.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* ********************************************************************** - * Copyright (C) 1998-2008, International Business Machines + * Copyright (C) 1998-2013, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** */ @@ -39,6 +39,7 @@ struct InsertionRecord; +#ifndef U_HIDE_INTERNAL_API /** * This class encapsulates the callback used by <code>LEInsertionList</code> * to apply an insertion from the insertion list. @@ -194,6 +195,7 @@ */ le_bool append; }; +#endif /* U_HIDE_INTERNAL_API */ U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/LEScripts.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LEScripts.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved. + * (C) Copyright IBM Corp. 1998-2013. All Rights Reserved. * * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS * YOU REALLY KNOW WHAT YOU'RE DOING. @@ -241,8 +241,28 @@ palmScriptCode = 144, sindScriptCode = 145, waraScriptCode = 146, +/** + * @stable ICU 4.8 + */ - scriptCodeCount = 147 + afakScriptCode = 147, + jurcScriptCode = 148, + mrooScriptCode = 149, + nshuScriptCode = 150, + shrdScriptCode = 151, + soraScriptCode = 152, + takrScriptCode = 153, + tangScriptCode = 154, + woleScriptCode = 155, +/** + * @stable ICU 49 + */ + + hluwScriptCode = 156, /* bump to match current ICU */ + khojScriptCode = 157, + tirhScriptCode = 158, + + scriptCodeCount = 159 }; U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/LETableReference.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,442 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * -*- c++ -*- + * + * (C) Copyright IBM Corp. and others 2013 - All Rights Reserved + * + * Range checking + * + */ + +#ifndef __LETABLEREFERENCE_H +#define __LETABLEREFERENCE_H + +#include "LETypes.h" +#include "LEFontInstance.h" + + +#define kQuestionmarkTableTag 0x3F3F3F3FUL +#define kTildeTableTag 0x7e7e7e7eUL +#ifdef __cplusplus + +// internal - interface for range checking +U_NAMESPACE_BEGIN + +#if LE_ASSERT_BAD_FONT +class LETableReference; // fwd +/** + * defined in OpenTypeUtilities.cpp + * @internal + */ +extern void _debug_LETableReference(const char *f, int l, const char *msg, const LETableReference *what, const void *ptr, size_t len); + +#define LE_DEBUG_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0); +#define LE_DEBUG_TR3(x,y,z) _debug_LETableReference(__FILE__, __LINE__, x, this, (const void*)y, (size_t)z); +#if 0 +#define LE_TRACE_TR(x) _debug_LETableReference(__FILE__, __LINE__, x, this, NULL, 0); +#else +#define LE_TRACE_TR(x) +#endif + +#else +#define LE_DEBUG_TR(x) +#define LE_DEBUG_TR3(x,y,z) +#define LE_TRACE_TR(x) +#endif + +/** + * @internal + */ +class LETableReference { +public: +/** + * @internal + * Construct from a specific tag + */ + LETableReference(const LEFontInstance* font, LETag tableTag, LEErrorCode &success) : + fFont(font), fTag(tableTag), fParent(NULL), fStart(NULL),fLength(LE_UINTPTR_MAX) { + loadTable(success); + LE_TRACE_TR("INFO: new table load") + } + + LETableReference(const LETableReference &parent, LEErrorCode &success) : fFont(parent.fFont), fTag(parent.fTag), fParent(&parent), fStart(parent.fStart), fLength(parent.fLength) { + if(LE_FAILURE(success)) { + clear(); + } + LE_TRACE_TR("INFO: new clone") + } + + LETableReference(const le_uint8* data, size_t length = LE_UINTPTR_MAX) : + fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(data), fLength(length) { + LE_TRACE_TR("INFO: new raw") + } + LETableReference() : + fFont(NULL), fTag(kQuestionmarkTableTag), fParent(NULL), fStart(NULL), fLength(0) { + LE_TRACE_TR("INFO: new empty") + } + + ~LETableReference() { + fTag=kTildeTableTag; + LE_TRACE_TR("INFO: new dtor") + } + + /** + * @internal + * @param length if LE_UINTPTR_MAX means "whole table" + * subset + */ + LETableReference(const LETableReference &parent, size_t offset, size_t length, + LEErrorCode &err) : + fFont(parent.fFont), fTag(parent.fTag), fParent(&parent), + fStart((parent.fStart)+offset), fLength(length) { + if(LE_SUCCESS(err)) { + if(isEmpty()) { + //err = LE_MISSING_FONT_TABLE_ERROR; + clear(); // it's just empty. Not an error. + } else if(offset >= fParent->fLength) { + LE_DEBUG_TR3("offset out of range: (%p) +%d", NULL, offset); + err = LE_INDEX_OUT_OF_BOUNDS_ERROR; + clear(); + } else { + if(fLength == LE_UINTPTR_MAX && + fParent->fLength != LE_UINTPTR_MAX) { + fLength = (fParent->fLength) - offset; // decrement length as base address is incremented + } + if(fLength != LE_UINTPTR_MAX) { // if we have bounds: + if(offset+fLength > fParent->fLength) { + LE_DEBUG_TR3("offset+fLength out of range: (%p) +%d", NULL, offset+fLength); + err = LE_INDEX_OUT_OF_BOUNDS_ERROR; // exceeded + clear(); + } + } + } + } else { + clear(); + } + LE_TRACE_TR("INFO: new subset") + } + + const void* getAlias() const { return (const void*)fStart; } + const void* getAliasTODO() const { LE_DEBUG_TR("getAliasTODO()"); return (const void*)fStart; } + le_bool isEmpty() const { return fStart==NULL || fLength==0; } + le_bool isValid() const { return !isEmpty(); } + le_bool hasBounds() const { return fLength!=LE_UINTPTR_MAX; } + void clear() { fLength=0; fStart=NULL; } + size_t getLength() const { return fLength; } + const LEFontInstance* getFont() const { return fFont; } + LETag getTag() const { return fTag; } + const LETableReference* getParent() const { return fParent; } + + void addOffset(size_t offset, LEErrorCode &success) { + if(hasBounds()) { + if(offset > fLength) { + LE_DEBUG_TR("addOffset off end"); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + return; + } else { + fLength -= offset; + } + } + fStart += offset; + } + + size_t ptrToOffset(const void *atPtr, LEErrorCode &success) const { + if(atPtr==NULL) return 0; + if(LE_FAILURE(success)) return LE_UINTPTR_MAX; + if((atPtr < fStart) || + (hasBounds() && (atPtr > fStart+fLength))) { + LE_DEBUG_TR3("ptrToOffset args out of range: %p", atPtr, 0); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + return LE_UINTPTR_MAX; + } + return ((const le_uint8*)atPtr)-fStart; + } + + /** + * Clamp down the length, for range checking. + */ + size_t contractLength(size_t newLength) { + if(fLength!=LE_UINTPTR_MAX&&newLength>0&&newLength<=fLength) { + fLength = newLength; + } + return fLength; + } + + /** + * Throw an error if offset+length off end + */ +public: + size_t verifyLength(size_t offset, size_t length, LEErrorCode &success) { + if(isValid()&& + LE_SUCCESS(success) && + fLength!=LE_UINTPTR_MAX && length!=LE_UINTPTR_MAX && offset!=LE_UINTPTR_MAX && + (offset+length)>fLength) { + LE_DEBUG_TR3("verifyLength failed (%p) %d",NULL, offset+length); + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; +#if LE_ASSERT_BAD_FONT + fprintf(stderr, "offset=%lu, len=%lu, would be at %p, (%lu) off end. End at %p\n", offset,length, fStart+offset+length, (offset+length-fLength), (offset+length-fLength)+fStart); +#endif + } + return fLength; + } + + /** + * Change parent link to another + */ + LETableReference &reparent(const LETableReference &base) { + fParent = &base; + return *this; + } + + /** + * remove parent link. Factory functions should do this. + */ + void orphan(void) { + fParent=NULL; + } + +protected: + const LEFontInstance* fFont; + LETag fTag; + const LETableReference *fParent; + const le_uint8 *fStart; // keep as 8 bit internally, for pointer math + size_t fLength; + + void loadTable(LEErrorCode &success) { + if(LE_SUCCESS(success)) { + fStart = (const le_uint8*)(fFont->getFontTable(fTag, fLength)); // note - a null table is not an error. + } + } + + void setRaw(const void *data, size_t length = LE_UINTPTR_MAX) { + fFont = NULL; + fTag = kQuestionmarkTableTag; + fParent = NULL; + fStart = (const le_uint8*)data; + fLength = length; + } +}; + + +template<class T> +class LETableVarSizer { + public: + inline static size_t getSize(); +}; + +// base definition- could override for adjustments +template<class T> inline +size_t LETableVarSizer<T>::getSize() { + return sizeof(T); +} + +/** + * \def LE_VAR_ARRAY + * @param x Type (T) + * @param y some member that is of length ANY_NUMBER + * Call this after defining a class, for example: + * LE_VAR_ARRAY(FeatureListTable,featureRecordArray) + * this is roughly equivalent to: + * template<> inline size_t LETableVarSizer<FeatureListTable>::getSize() { return sizeof(FeatureListTable) - (sizeof(le_uint16)*ANY_NUMBER); } + * it's a specialization that informs the LETableReference subclasses to NOT include the variable array in the size. + * dereferencing NULL is valid here because we never actually dereference it, just inside sizeof. + */ +#define LE_VAR_ARRAY(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return sizeof(x) - (sizeof(((const x*)0)->y)); } +/** + * \def LE_CORRECT_SIZE + * @param x type (T) + * @param y fixed size for T + */ +#define LE_CORRECT_SIZE(x,y) template<> inline size_t LETableVarSizer<x>::getSize() { return y; } + +/** + * Open a new entry based on an existing table + */ + +/** + * \def LE_UNBOUNDED_ARRAY + * define an array with no *known* bound. Will trim to available size. + * @internal + */ +#define LE_UNBOUNDED_ARRAY LE_UINT32_MAX + +template<class T> +class LEReferenceToArrayOf : public LETableReference { +public: + LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, size_t offset, le_uint32 count) + : LETableReference(parent, offset, LE_UINTPTR_MAX, success), fCount(count) { + LE_TRACE_TR("INFO: new RTAO by offset") + if(LE_SUCCESS(success)) { + if(count == LE_UNBOUNDED_ARRAY) { // not a known length + count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success); + } + if(LE_FAILURE(success)) { + fCount=0; + clear(); + } + } + + LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, le_uint32 count) + : LETableReference(parent, parent.ptrToOffset(array, success), LE_UINTPTR_MAX, success), fCount(count) { +LE_TRACE_TR("INFO: new RTAO") + if(LE_SUCCESS(success)) { + if(count == LE_UNBOUNDED_ARRAY) { // not a known length + count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success); + } + if(LE_FAILURE(success)) clear(); + } + LEReferenceToArrayOf(const LETableReference &parent, LEErrorCode &success, const T* array, size_t offset, le_uint32 count) + : LETableReference(parent, parent.ptrToOffset(array, success)+offset, LE_UINTPTR_MAX, success), fCount(count) { +LE_TRACE_TR("INFO: new RTAO") + if(LE_SUCCESS(success)) { + if(count == LE_UNBOUNDED_ARRAY) { // not a known length + count = getLength()/LETableVarSizer<T>::getSize(); // fit to max size + } + LETableReference::verifyLength(0, LETableVarSizer<T>::getSize()*count, success); + } + if(LE_FAILURE(success)) clear(); + } + + LEReferenceToArrayOf() :LETableReference(), fCount(0) {} + + le_uint32 getCount() const { return fCount; } + + using LETableReference::getAlias; + + const T *getAlias(le_uint32 i, LEErrorCode &success) const { + return ((const T*)(((const char*)getAlias())+getOffsetFor(i, success))); + } + + const T *getAliasTODO() const { LE_DEBUG_TR("getAliasTODO<>"); return (const T*)fStart; } + + const T& getObject(le_uint32 i, LEErrorCode &success) const { + return *getAlias(i,success); + } + + const T& operator()(le_uint32 i, LEErrorCode &success) const { + return *getAlias(i,success); + } + + size_t getOffsetFor(le_uint32 i, LEErrorCode &success) const { + if(LE_SUCCESS(success)&&i<getCount()) { + return LETableVarSizer<T>::getSize()*i; + } else { + success = LE_INDEX_OUT_OF_BOUNDS_ERROR; + } + return 0; + } + + LEReferenceToArrayOf<T> &reparent(const LETableReference &base) { + fParent = &base; + return *this; + } + + LEReferenceToArrayOf(const LETableReference& parent, LEErrorCode & success) : LETableReference(parent,0, LE_UINTPTR_MAX, success), fCount(0) { + LE_TRACE_TR("INFO: null RTAO") + } + +private: + le_uint32 fCount; +}; + + +template<class T> +class LEReferenceTo : public LETableReference { +public: + /** + * open a sub reference. + * @param parent parent reference + * @param success error status + * @param atPtr location of reference - if NULL, will be at offset zero (i.e. downcast of parent). Otherwise must be a pointer within parent's bounds. + */ + LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr) + : LETableReference(parent, parent.ptrToOffset(atPtr, success), LE_UINTPTR_MAX, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + /** + * ptr plus offset + */ + LEReferenceTo(const LETableReference &parent, LEErrorCode &success, const void* atPtr, size_t offset) + : LETableReference(parent, parent.ptrToOffset(atPtr, success)+offset, LE_UINTPTR_MAX, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const LETableReference &parent, LEErrorCode &success, size_t offset) + : LETableReference(parent, offset, LE_UINTPTR_MAX, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const LETableReference &parent, LEErrorCode &success) + : LETableReference(parent, 0, LE_UINTPTR_MAX, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const LEFontInstance *font, LETag tableTag, LEErrorCode &success) + : LETableReference(font, tableTag, success) { + verifyLength(0, LETableVarSizer<T>::getSize(), success); + if(LE_FAILURE(success)) clear(); + } + LEReferenceTo(const le_uint8 *data, size_t length = LE_UINTPTR_MAX) : LETableReference(data, length) {} + LEReferenceTo(const T *data, size_t length = LE_UINTPTR_MAX) : LETableReference((const le_uint8*)data, length) {} + LEReferenceTo() : LETableReference(NULL) {} + + LEReferenceTo<T>& operator=(const T* other) { + setRaw(other); + return *this; + } + + LEReferenceTo<T> &reparent(const LETableReference &base) { + fParent = &base; + return *this; + } + + /** + * roll forward by one <T> size. + * same as addOffset(LETableVarSizer<T>::getSize(),success) + */ + void addObject(LEErrorCode &success) { + addOffset(LETableVarSizer<T>::getSize(), success); + } + void addObject(size_t count, LEErrorCode &success) { + addOffset(LETableVarSizer<T>::getSize()*count, success); + } + + const T *operator->() const { return getAlias(); } + const T *getAlias() const { return (const T*)fStart; } + const T *getAliasTODO() const { LE_DEBUG_TR("getAliasTODO<>"); return (const T*)fStart; } +}; + + +U_NAMESPACE_END + +#endif + +#endif
--- a/src/share/native/sun/font/layout/LETypes.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LETypes.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -50,14 +50,15 @@ #endif #include "unicode/utypes.h" + +#ifdef __cplusplus #include "unicode/uobject.h" +#endif + #ifdef LE_USE_CMEMORY #include "cmemory.h" #endif -#endif /* not standalone */ - - -U_NAMESPACE_BEGIN +#endif /*! * \file @@ -296,12 +297,14 @@ */ typedef UChar32 LEUnicode32; +#ifndef U_HIDE_DEPRECATED_API /** * Used to represent 16-bit Unicode code points. * * @deprecated since ICU 2.4. Use LEUnicode16 instead */ typedef UChar LEUnicode; +#endif /* U_HIDE_DEPRECATED_API */ /** * Used to hold a pair of (x, y) values which represent a point. @@ -325,7 +328,7 @@ float fY; }; -#ifndef XP_CPLUSPLUS +#ifndef __cplusplus /** * Used to hold a pair of (x, y) values which represent a point. * @@ -335,6 +338,39 @@ #endif +#ifndef U_HIDE_INTERNAL_API + +#ifndef LE_ASSERT_BAD_FONT +#define LE_ASSERT_BAD_FONT 0 +#endif + +#if LE_ASSERT_BAD_FONT +#include <stdio.h> +#define LE_DEBUG_BAD_FONT(x) fprintf(stderr,"%s:%d: BAD FONT: %s\n", __FILE__, __LINE__, (x)); +#else +#define LE_DEBUG_BAD_FONT(x) +#endif + +/** + * Max value representable by a uintptr + */ + +#ifndef UINT32_MAX +#define LE_UINT32_MAX 0xFFFFFFFFU +#else +#define LE_UINT32_MAX UINT32_MAX +#endif + +#ifndef UINTPTR_MAX +#define LE_UINTPTR_MAX LE_UINT32_MAX +#else +#define LE_UINTPTR_MAX UINTPTR_MAX +#endif + +/** + * Range check for overflow + */ +#define LE_RANGE_CHECK(type, count, ptrfn) (( (LE_UINTPTR_MAX / sizeof(type)) < count ) ? NULL : (ptrfn)) /** * A convenience macro to get the length of an array. * @@ -356,7 +392,7 @@ * * @internal */ -#define LE_NEW_ARRAY(type, count) (type *) uprv_malloc((count) * sizeof(type)) +#define LE_NEW_ARRAY(type, count) (type *) LE_RANGE_CHECK(type,count,uprv_malloc((count) * sizeof(type))) /** * Re-allocate an array of basic types. This is used to isolate the rest of @@ -373,7 +409,52 @@ * @internal */ #define LE_DELETE_ARRAY(array) uprv_free((void *) (array)) -#endif +#else +/* !LE_USE_CMEMORY - Not using ICU memory - use C std lib versions */ + +#include <stdlib.h> +#include <string.h> + +/** + * A convenience macro to get the length of an array. + * + * @internal + */ +#define LE_ARRAY_SIZE(array) (sizeof array / sizeof array[0]) + +/** + * A convenience macro for copying an array. + * + * @internal + */ +#define LE_ARRAY_COPY(dst, src, count) memcpy((void *) (dst), (void *) (src), (count) * sizeof (src)[0]) + +/** + * Allocate an array of basic types. This is used to isolate the rest of + * the LayoutEngine code from cmemory.h. + * + * @internal + */ +#define LE_NEW_ARRAY(type, count) LE_RANGE_CHECK(type,count,(type *) malloc((count) * sizeof(type))) + +/** + * Re-allocate an array of basic types. This is used to isolate the rest of + * the LayoutEngine code from cmemory.h. + * + * @internal + */ +#define LE_GROW_ARRAY(array, newSize) realloc((void *) (array), (newSize) * sizeof (array)[0]) + + /** + * Free an array of basic types. This is used to isolate the rest of + * the LayoutEngine code from cmemory.h. + * + * @internal + */ +#define LE_DELETE_ARRAY(array) free((void *) (array)) + +#endif /* LE_USE_CMEMORY */ +#endif /* U_HIDE_INTERNAL_API */ /** * A macro to construct the four-letter tags used to @@ -536,7 +617,7 @@ LE_RAND_FEATURE_TAG = 0x72616E64UL, /**< 'rand' */ LE_RLIG_FEATURE_TAG = 0x726C6967UL, /**< 'rlig' */ LE_RPHF_FEATURE_TAG = 0x72706866UL, /**< 'rphf' */ - LE_RKRF_FEATURE_TAG = 0x726B7266UL, /**< 'rkrf' */ + LE_RKRF_FEATURE_TAG = 0x726B7266UL, /**< 'rkrf' */ LE_RTBD_FEATURE_TAG = 0x72746264UL, /**< 'rtbd' */ LE_RTLA_FEATURE_TAG = 0x72746C61UL, /**< 'rtla' */ LE_RUBY_FEATURE_TAG = 0x72756279UL, /**< 'ruby' */ @@ -588,6 +669,68 @@ }; /** + * @internal + */ +enum LEFeatureENUMs { + LE_Kerning_FEATURE_ENUM = 0, /**< Requests Kerning. Formerly LayoutEngine::kTypoFlagKern */ + LE_Ligatures_FEATURE_ENUM = 1, /**< Requests Ligatures. Formerly LayoutEngine::kTypoFlagLiga */ + LE_NoCanon_FEATURE_ENUM = 2, /**< Requests No Canonical Processing */ + LE_CLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_DLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_HLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_LIGA_FEATURE_ENUM, /**< Feature specific enum */ + LE_RLIG_FEATURE_ENUM, /**< Feature specific enum */ + LE_SMCP_FEATURE_ENUM, /**< Feature specific enum */ + LE_FRAC_FEATURE_ENUM, /**< Feature specific enum */ + LE_AFRC_FEATURE_ENUM, /**< Feature specific enum */ + LE_ZERO_FEATURE_ENUM, /**< Feature specific enum */ + LE_SWSH_FEATURE_ENUM, /**< Feature specific enum */ + LE_CSWH_FEATURE_ENUM, /**< Feature specific enum */ + LE_SALT_FEATURE_ENUM, /**< Feature specific enum */ + LE_NALT_FEATURE_ENUM, /**< Feature specific enum */ + LE_RUBY_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS01_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS02_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS03_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS04_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS05_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS06_FEATURE_ENUM, /**< Feature specific enum */ + LE_SS07_FEATURE_ENUM, /**< Feature specific enum */ + + LE_CHAR_FILTER_FEATURE_ENUM = 31, /**< Apply CharSubstitutionFilter */ + LE_FEATURE_ENUM_MAX = LE_CHAR_FILTER_FEATURE_ENUM +}; + +#define LE_Kerning_FEATURE_FLAG (1 << LE_Kerning_FEATURE_ENUM) +#define LE_Ligatures_FEATURE_FLAG (1 << LE_Ligatures_FEATURE_ENUM) +#define LE_NoCanon_FEATURE_FLAG (1 << LE_NoCanon_FEATURE_ENUM) +#define LE_CLIG_FEATURE_FLAG (1 << LE_CLIG_FEATURE_ENUM) +#define LE_DLIG_FEATURE_FLAG (1 << LE_DLIG_FEATURE_ENUM) +#define LE_HLIG_FEATURE_FLAG (1 << LE_HLIG_FEATURE_ENUM) +#define LE_LIGA_FEATURE_FLAG (1 << LE_LIGA_FEATURE_ENUM) +#define LE_RLIG_FEATURE_FLAG (1 << LE_RLIG_FEATURE_ENUM) +#define LE_SMCP_FEATURE_FLAG (1 << LE_SMCP_FEATURE_ENUM) +#define LE_FRAC_FEATURE_FLAG (1 << LE_FRAC_FEATURE_ENUM) +#define LE_AFRC_FEATURE_FLAG (1 << LE_AFRC_FEATURE_ENUM) +#define LE_ZERO_FEATURE_FLAG (1 << LE_ZERO_FEATURE_ENUM) +#define LE_SWSH_FEATURE_FLAG (1 << LE_SWSH_FEATURE_ENUM) +#define LE_CSWH_FEATURE_FLAG (1 << LE_CSWH_FEATURE_ENUM) +#define LE_SALT_FEATURE_FLAG (1 << LE_SALT_FEATURE_ENUM) +#define LE_NALT_FEATURE_FLAG (1 << LE_NALT_FEATURE_ENUM) +#define LE_RUBY_FEATURE_FLAG (1 << LE_RUBY_FEATURE_ENUM) +#define LE_SS01_FEATURE_FLAG (1 << LE_SS01_FEATURE_ENUM) +#define LE_SS02_FEATURE_FLAG (1 << LE_SS02_FEATURE_ENUM) +#define LE_SS03_FEATURE_FLAG (1 << LE_SS03_FEATURE_ENUM) +#define LE_SS04_FEATURE_FLAG (1 << LE_SS04_FEATURE_ENUM) +#define LE_SS05_FEATURE_FLAG (1 << LE_SS05_FEATURE_ENUM) +#define LE_SS06_FEATURE_FLAG (1 << LE_SS06_FEATURE_ENUM) +#define LE_SS07_FEATURE_FLAG (1 << LE_SS07_FEATURE_ENUM) + +#define LE_CHAR_FILTER_FEATURE_FLAG (1 << LE_CHAR_FILTER_FEATURE_ENUM) + +#define LE_DEFAULT_FEATURE_FLAG (LE_Kerning_FEATURE_FLAG | LE_Ligatures_FEATURE_FLAG) /**< default features */ + +/** * Error codes returned by the LayoutEngine. * * @stable ICU 2.4 @@ -611,7 +754,7 @@ }; #endif -#ifndef XP_CPLUSPLUS +#ifndef __cplusplus /** * Error codes returned by the LayoutEngine. * @@ -638,7 +781,4 @@ #define LE_FAILURE(code) (U_FAILURE((UErrorCode)code)) #endif -U_NAMESPACE_END -#endif - - +#endif /* __LETYPES_H */
--- a/src/share/native/sun/font/layout/LayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -33,6 +33,7 @@ #include "LETypes.h" #include "LEScripts.h" #include "LELanguages.h" +#include "LESwaps.h" #include "LayoutEngine.h" #include "ArabicLayoutEngine.h" @@ -44,6 +45,8 @@ #include "ThaiLayoutEngine.h" #include "TibetanLayoutEngine.h" #include "GXLayoutEngine.h" +#include "GXLayoutEngine2.h" + #include "ScriptAndLanguageTags.h" #include "CharSubstitutionFilter.h" @@ -63,6 +66,10 @@ /* Leave this copyright notice here! It needs to go somewhere in this library. */ static const char copyright[] = U_COPYRIGHT_STRING; +/* TODO: remove these? */ +const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG; +const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG; + const LEUnicode32 DefaultCharMapper::controlChars[] = { 0x0009, 0x000A, 0x000D, /*0x200C, 0x200D,*/ 0x200E, 0x200F, @@ -140,21 +147,21 @@ class CanonMarkFilter : public UMemory, public LEGlyphFilter { private: - const GlyphClassDefinitionTable *classDefTable; + const LEReferenceTo<GlyphClassDefinitionTable> classDefTable; CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class public: - CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable); + CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success); virtual ~CanonMarkFilter(); virtual le_bool accept(LEGlyphID glyph) const; }; -CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable) +CanonMarkFilter::CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success) + : classDefTable(gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success)) { - classDefTable = gdefTable->getMarkAttachClassDefinitionTable(); } CanonMarkFilter::~CanonMarkFilter() @@ -164,9 +171,10 @@ le_bool CanonMarkFilter::accept(LEGlyphID glyph) const { - le_int32 glyphClass = classDefTable->getGlyphClass(glyph); - - return glyphClass != 0; + LEErrorCode success = LE_NO_ERROR; + le_int32 glyphClass = classDefTable->getGlyphClass(classDefTable, glyph, success); + if(LE_FAILURE(success)) return false; + return glyphClass != 0; } UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) @@ -251,24 +259,24 @@ return 0; } - if ((fTypoFlags & 0x4) == 0) { // no canonical processing + if ((fTypoFlags & LE_NoCanon_FEATURE_FLAG) == 0) { // no canonical processing return count; } - const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; + LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable((GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable); LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); le_int32 i, dir = 1, out = 0, outCharCount = count; - if (canonGSUBTable->coversScript(scriptTag)) { + if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) { CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); if (substitutionFilter == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } - const LEUnicode *inChars = &chars[offset]; - LEUnicode *reordered = NULL; + const LEUnicode *inChars = &chars[offset]; + LEUnicode *reordered = NULL; LEGlyphStorage fakeGlyphStorage; fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); @@ -278,20 +286,20 @@ return 0; } - // This is the cheapest way to get mark reordering only for Hebrew. - // We could just do the mark reordering for all scripts, but most - // of them probably don't need it... - if (fScriptCode == hebrScriptCode) { - reordered = LE_NEW_ARRAY(LEUnicode, count); + // This is the cheapest way to get mark reordering only for Hebrew. + // We could just do the mark reordering for all scripts, but most + // of them probably don't need it... + if (fScriptCode == hebrScriptCode) { + reordered = LE_NEW_ARRAY(LEUnicode, count); - if (reordered == NULL) { - delete substitutionFilter; - success = LE_MEMORY_ALLOCATION_ERROR; - return 0; - } + if (reordered == NULL) { + delete substitutionFilter; + success = LE_MEMORY_ALLOCATION_ERROR; + return 0; + } - CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); - inChars = reordered; + CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); + inChars = reordered; } fakeGlyphStorage.allocateAuxData(success); @@ -311,11 +319,11 @@ fakeGlyphStorage.setAuxData(out, canonFeatures, success); } - if (reordered != NULL) { - LE_DELETE_ARRAY(reordered); - } + if (reordered != NULL) { + LE_DELETE_ARRAY(reordered); + } - outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); + outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, (const GlyphDefinitionTableHeader*)NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); if (LE_FAILURE(success)) { delete substitutionFilter; @@ -416,16 +424,16 @@ return; } - GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; - CanonMarkFilter filter(gdefTable); + LEReferenceTo<GlyphDefinitionTableHeader> gdefTable((GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable, + CanonShaping::glyphDefinitionTableLen); + CanonMarkFilter filter(gdefTable, success); adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); - if (fTypoFlags & 0x1) { /* kerning enabled */ - static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; - - KernTable kt(fFontInstance, getFontTable(kernTableTag)); - kt.process(glyphStorage); + if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ + LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); + KernTable kt(kernTable, success); + kt.process(glyphStorage, success); } // default is no adjustments @@ -510,9 +518,9 @@ glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); } -const void *LayoutEngine::getFontTable(LETag tableTag) const +const void *LayoutEngine::getFontTable(LETag tableTag, size_t &length) const { - return fFontInstance->getFontTable(tableTag); + return fFontInstance->getFontTable(tableTag, length); } void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, @@ -559,37 +567,41 @@ void LayoutEngine::reset() { + if(fGlyphStorage!=NULL) { fGlyphStorage->reset(); + fGlyphStorage = NULL; + } } LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) { - // 3 -> kerning and ligatures - return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success); + //kerning and ligatures - by default + return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, LE_DEFAULT_FEATURE_FLAG, success); } LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) { static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; + static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG; if (LE_FAILURE(success)) { return NULL; } - const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag); + LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success); LayoutEngine *result = NULL; LETag scriptTag = 0x00000000; LETag languageTag = 0x00000000; - LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); + LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are // properly tested. - if ( v2ScriptTag == dev2ScriptTag && gsubTable != NULL && gsubTable->coversScript( v2ScriptTag )) { - result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); - } - else if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) { + if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) { + result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); + } + else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) { switch (scriptCode) { case bengScriptCode: case devaScriptCode: @@ -608,6 +620,11 @@ result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; + case hebrScriptCode: + // Disable hebrew ligatures since they have only archaic uses, see ticket #8318 + result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success); + break; + case hangScriptCode: result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; @@ -620,10 +637,10 @@ case janLanguageCode: case zhtLanguageCode: case zhsLanguageCode: - if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) { + if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) { result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; - } + } // note: falling through to default case. default: @@ -646,26 +663,29 @@ break; } } else { - const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); - - if (morphTable != NULL) { - result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success); + MorphTableHeader2 *morxTable = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); + if (morxTable != NULL && SWAPL(morxTable->version)==0x00020000) { + result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); } else { - switch (scriptCode) { - case bengScriptCode: - case devaScriptCode: - case gujrScriptCode: - case kndaScriptCode: - case mlymScriptCode: - case oryaScriptCode: - case guruScriptCode: - case tamlScriptCode: - case teluScriptCode: - case sinhScriptCode: - { - result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; - } + LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success); + if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort + result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); + } else { + switch (scriptCode) { + case bengScriptCode: + case devaScriptCode: + case gujrScriptCode: + case kndaScriptCode: + case mlymScriptCode: + case oryaScriptCode: + case guruScriptCode: + case tamlScriptCode: + case teluScriptCode: + case sinhScriptCode: + { + result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + } case arabScriptCode: //case hebrScriptCode: @@ -683,9 +703,10 @@ result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); break; - default: - result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); - break; + default: + result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + } } } }
--- a/src/share/native/sun/font/layout/LayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -26,7 +26,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -90,6 +90,14 @@ * @stable ICU 2.8 */ class U_LAYOUT_API LayoutEngine : public UObject { +public: +#ifndef U_HIDE_INTERNAL_API + /** @internal Flag to request kerning. Use LE_Kerning_FEATURE_FLAG instead. */ + static const le_int32 kTypoFlagKern; + /** @internal Flag to request ligatures. Use LE_Ligatures_FEATURE_FLAG instead. */ + static const le_int32 kTypoFlagLiga; +#endif /* U_HIDE_INTERNAL_API */ + protected: /** * The object which holds the glyph storage @@ -140,6 +148,7 @@ */ le_bool fFilterZeroWidth; +#ifndef U_HIDE_INTERNAL_API /** * This constructs an instance for a given font, script and language. Subclass constructors * must call this constructor. @@ -161,7 +170,10 @@ le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success); +#endif /* U_HIDE_INTERNAL_API */ + // Do not enclose the protected default constructor with #ifndef U_HIDE_INTERNAL_API + // or else the compiler will create a public default constructor. /** * This overrides the default no argument constructor to make it * difficult for clients to call it. Clients are expected to call @@ -268,12 +280,18 @@ * some other way must override this method. * * @param tableTag - the four byte table tag. + * @param length - length to use * * @return the address of the table. * * @internal */ - virtual const void *getFontTable(LETag tableTag) const; + virtual const void *getFontTable(LETag tableTag, size_t &length) const; + + /** + * @deprecated + */ + virtual const void *getFontTable(LETag tableTag) const { size_t ignored; return getFontTable(tableTag, ignored); } /** * This method does character to glyph mapping. The default implementation @@ -302,6 +320,7 @@ */ virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, LEGlyphStorage &glyphStorage, LEErrorCode &success); +#ifndef U_HIDE_INTERNAL_API /** * This is a convenience method that forces the advance width of mark * glyphs to be zero, which is required for proper selection and highlighting. @@ -336,7 +355,7 @@ * @internal */ static void adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success); - +#endif /* U_HIDE_INTERNAL_API */ public: /**
--- a/src/share/native/sun/font/layout/LigatureSubstProc.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LigatureSubstProc.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -47,15 +47,15 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor) -LigatureSubstitutionProcessor::LigatureSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader) - : StateTableProcessor(morphSubtableHeader) + LigatureSubstitutionProcessor::LigatureSubstitutionProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) +: StateTableProcessor(morphSubtableHeader, success), ligatureSubstitutionHeader(morphSubtableHeader, success) { - ligatureSubstitutionHeader = (const LigatureSubstitutionHeader *) morphSubtableHeader; + if(LE_FAILURE(success)) return; ligatureActionTableOffset = SWAPW(ligatureSubstitutionHeader->ligatureActionTableOffset); componentTableOffset = SWAPW(ligatureSubstitutionHeader->componentTableOffset); ligatureTableOffset = SWAPW(ligatureSubstitutionHeader->ligatureTableOffset); - entryTable = (const LigatureSubstitutionStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset); + entryTable = LEReferenceToArrayOf<LigatureSubstitutionStateEntry>(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); } LigatureSubstitutionProcessor::~LigatureSubstitutionProcessor() @@ -69,7 +69,9 @@ ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index) { - const LigatureSubstitutionStateEntry *entry = &entryTable[index]; + LEErrorCode success = LE_NO_ERROR; + const LigatureSubstitutionStateEntry *entry = entryTable.getAlias(index, success); + ByteOffset newState = SWAPW(entry->newStateOffset); le_int16 flags = SWAPW(entry->flags); @@ -79,12 +81,16 @@ } componentStack[m] = currGlyph; + } else if ( m == -1) { + // bad font- skip this glyph. + currGlyph++; + return newState; } ByteOffset actionOffset = flags & lsfActionOffsetMask; if (actionOffset != 0) { - const LigatureActionEntry *ap = (const LigatureActionEntry *) ((char *) &ligatureSubstitutionHeader->stHeader + actionOffset); + LEReferenceTo<LigatureActionEntry> ap(stHeader, success, actionOffset); LigatureActionEntry action; le_int32 offset, i = 0; le_int32 stack[nComponents]; @@ -93,7 +99,8 @@ do { le_uint32 componentGlyph = componentStack[m--]; - action = SWAPL(*ap++); + action = SWAPL(*ap.getAlias()); + ap.addObject(success); // ap++ if (m < 0) { m = nComponents - 1; @@ -101,29 +108,48 @@ offset = action & lafComponentOffsetMask; if (offset != 0) { - const le_int16 *offsetTable = (const le_int16 *)((char *) &ligatureSubstitutionHeader->stHeader + 2 * SignExtend(offset, lafComponentOffsetMask)); + LEReferenceToArrayOf<le_int16> offsetTable(stHeader, success, 2 * SignExtend(offset, lafComponentOffsetMask), LE_UNBOUNDED_ARRAY); - i += SWAPW(offsetTable[LE_GET_GLYPH(glyphStorage[componentGlyph])]); + if(LE_FAILURE(success)) { + currGlyph++; + LE_DEBUG_BAD_FONT("off end of ligature substitution header"); + return newState; // get out! bad font + } + if(componentGlyph > glyphStorage.getGlyphCount()) { + LE_DEBUG_BAD_FONT("preposterous componentGlyph"); + currGlyph++; + return newState; // get out! bad font + } + i += SWAPW(offsetTable.getObject(LE_GET_GLYPH(glyphStorage[componentGlyph]), success)); if (action & (lafLast | lafStore)) { - const TTGlyphID *ligatureOffset = (const TTGlyphID *) ((char *) &ligatureSubstitutionHeader->stHeader + i); - TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset); + LEReferenceTo<TTGlyphID> ligatureOffset(stHeader, success, i); + TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset.getAlias()); - glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); - stack[++mm] = componentGlyph; - i = 0; + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); + if(mm==nComponents) { + LE_DEBUG_BAD_FONT("exceeded nComponents"); + mm--; // don't overrun the stack. + } + stack[++mm] = componentGlyph; + i = 0; } else { - glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF); + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF); } } - } while (!(action & lafLast)); +#if LE_ASSERT_BAD_FONT + if(m<0) { + LE_DEBUG_BAD_FONT("m<0") + } +#endif + } while (!(action & lafLast) && (m>=0) ); // stop if last bit is set, or if run out of items while (mm >= 0) { - if (++m >= nComponents) { - m = 0; - } + if (++m >= nComponents) { + m = 0; + } - componentStack[m] = stack[mm--]; + componentStack[m] = stack[mm--]; } }
--- a/src/share/native/sun/font/layout/LigatureSubstProc.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LigatureSubstProc.h Wed Apr 17 02:53:02 2013 -0700 @@ -58,7 +58,7 @@ virtual void endStateTable(); - LigatureSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader); + LigatureSubstitutionProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~LigatureSubstitutionProcessor(); /** @@ -83,12 +83,12 @@ ByteOffset componentTableOffset; ByteOffset ligatureTableOffset; - const LigatureSubstitutionStateEntry *entryTable; + LEReferenceToArrayOf<LigatureSubstitutionStateEntry> entryTable; le_int32 componentStack[nComponents]; le_int16 m; - const LigatureSubstitutionHeader *ligatureSubstitutionHeader; + LEReferenceTo<LigatureSubstitutionHeader> ligatureSubstitutionHeader; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/LigatureSubstProc2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,170 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp and Others. 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LigatureSubstProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +#define ExtendedComplement(m) ((le_int32) (~((le_uint32) (m)))) +#define SignBit(m) ((ExtendedComplement(m) >> 1) & (le_int32)(m)) +#define SignExtend(v,m) (((v) & SignBit(m))? ((v) | ExtendedComplement(m)): (v)) + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor2) + +LigatureSubstitutionProcessor2::LigatureSubstitutionProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : StateTableProcessor2(morphSubtableHeader, success), + ligActionOffset(0), + ligatureSubstitutionHeader(morphSubtableHeader, success), componentOffset(0), ligatureOffset(0), entryTable() +{ + if (LE_FAILURE(success)) return; + + ligActionOffset = SWAPL(ligatureSubstitutionHeader->ligActionOffset); + componentOffset = SWAPL(ligatureSubstitutionHeader->componentOffset); + ligatureOffset = SWAPL(ligatureSubstitutionHeader->ligatureOffset); + + entryTable = LEReferenceToArrayOf<LigatureSubstitutionStateEntry2>(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); +} + +LigatureSubstitutionProcessor2::~LigatureSubstitutionProcessor2() +{ +} + +void LigatureSubstitutionProcessor2::beginStateTable() +{ + m = -1; +} + +le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success) +{ + const LigatureSubstitutionStateEntry2 *entry = entryTable.getAlias(index, success); + if(LE_FAILURE(success)) return 0; + + le_uint16 nextStateIndex = SWAPW(entry->nextStateIndex); + le_uint16 flags = SWAPW(entry->entryFlags); + le_uint16 ligActionIndex = SWAPW(entry->ligActionIndex); + + if (flags & lsfSetComponent) { + if (++m >= nComponents) { + m = 0; + } + componentStack[m] = currGlyph; + } else if ( m == -1) { + // bad font- skip this glyph. + //LE_DEBUG_BAD_FONT("m==-1 (componentCount went negative)") + currGlyph+= dir; + return nextStateIndex; + } + + ByteOffset actionOffset = flags & lsfPerformAction; + + if (actionOffset != 0) { + LEReferenceTo<LigatureActionEntry> ap(stHeader, success, ligActionOffset); // byte offset + ap.addObject(ligActionIndex - 1, success); // index offset ( one before the actual start, because we will pre-increment) + LEReferenceToArrayOf<TTGlyphID> ligatureTable(stHeader, success, ligatureOffset, LE_UNBOUNDED_ARRAY); + LigatureActionEntry action; + le_int32 offset, i = 0; + le_int32 stack[nComponents]; + le_int16 mm = -1; + + LEReferenceToArrayOf<le_uint16> componentTable(stHeader, success, componentOffset, LE_UNBOUNDED_ARRAY); + if(LE_FAILURE(success)) { + currGlyph+= dir; + return nextStateIndex; // get out! bad font + } + + do { + le_uint32 componentGlyph = componentStack[m--]; // pop off + + ap.addObject(success); + action = SWAPL(*ap.getAlias()); + + if (m < 0) { + m = nComponents - 1; + } + + offset = action & lafComponentOffsetMask; + if (offset != 0) { + if(componentGlyph > glyphStorage.getGlyphCount()) { + LE_DEBUG_BAD_FONT("preposterous componentGlyph"); + currGlyph+= dir; + return nextStateIndex; // get out! bad font + } + i += SWAPW(componentTable(LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask)),success)); + + if (action & (lafLast | lafStore)) { + TTGlyphID ligatureGlyph = SWAPW(ligatureTable(i,success)); + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph); + if(mm==nComponents) { + LE_DEBUG_BAD_FONT("exceeded nComponents"); + mm--; // don't overrun the stack. + } + stack[++mm] = componentGlyph; + i = 0; + } else { + glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF); + } + } +#if LE_ASSERT_BAD_FONT + if(m<0) { + LE_DEBUG_BAD_FONT("m<0") + } +#endif + } while (!(action & lafLast) && (m>=0) ); // stop if last bit is set, or if run out of items + + while (mm >= 0) { + if (++m >= nComponents) { + m = 0; + } + + componentStack[m] = stack[mm--]; + } + } + + if (!(flags & lsfDontAdvance)) { + currGlyph += dir; + } + + return nextStateIndex; +} + +void LigatureSubstitutionProcessor2::endStateTable() +{ +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/LigatureSubstProc2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,97 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __LIGATURESUBSTITUTIONPROCESSOR2_H +#define __LIGATURESUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LigatureSubstitution.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +#define nComponents 16 + +class LigatureSubstitutionProcessor2 : public StateTableProcessor2 +{ +public: + virtual void beginStateTable(); + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, + EntryTableIndex2 index, LEErrorCode &success); + + virtual void endStateTable(); + + LigatureSubstitutionProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + virtual ~LigatureSubstitutionProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + LigatureSubstitutionProcessor2(); + +protected: + le_uint32 ligActionOffset; + le_uint32 componentOffset; + le_uint32 ligatureOffset; + + LEReferenceToArrayOf<LigatureSubstitutionStateEntry2> entryTable; + + le_int32 componentStack[nComponents]; + le_int16 m; + + const LEReferenceTo<LigatureSubstitutionHeader2> ligatureSubstitutionHeader; + +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LigatureSubstSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -40,10 +40,10 @@ U_NAMESPACE_BEGIN -le_uint32 LigatureSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 LigatureSubstitutionSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { Offset ligSetTableOffset = SWAPW(ligSetTableOffsetArray[coverageIndex]);
--- a/src/share/native/sun/font/layout/LigatureSubstSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LigatureSubstSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -50,6 +50,7 @@ le_uint16 ligatureCount; Offset ligatureTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureSetTable, ligatureTableOffsetArray) struct LigatureTable { @@ -57,14 +58,16 @@ le_uint16 compCount; TTGlyphID componentArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureTable, componentArray) struct LigatureSubstitutionSubtable : GlyphSubstitutionSubtable { le_uint16 ligSetCount; Offset ligSetTableOffsetArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; +LE_VAR_ARRAY(LigatureSubstitutionSubtable, ligSetTableOffsetArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/LigatureSubstitution.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LigatureSubstitution.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -52,17 +52,32 @@ ByteOffset ligatureTableOffset; }; +struct LigatureSubstitutionHeader2 : MorphStateTableHeader2 +{ + le_uint32 ligActionOffset; + le_uint32 componentOffset; + le_uint32 ligatureOffset; +}; + enum LigatureSubstitutionFlags { lsfSetComponent = 0x8000, lsfDontAdvance = 0x4000, - lsfActionOffsetMask = 0x3FFF + lsfActionOffsetMask = 0x3FFF, // N/A in morx + lsfPerformAction = 0x2000 }; struct LigatureSubstitutionStateEntry : StateEntry { }; +struct LigatureSubstitutionStateEntry2 +{ + le_uint16 nextStateIndex; + le_uint16 entryFlags; + le_uint16 ligActionIndex; +}; + typedef le_uint32 LigatureActionEntry; enum LigatureActionFlags
--- a/src/share/native/sun/font/layout/LookupProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LookupProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -44,7 +44,7 @@ U_NAMESPACE_BEGIN -le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, GlyphIterator *glyphIterator, +le_uint32 LookupProcessor::applyLookupTable(const LEReferenceTo<LookupTable> &lookupTable, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const { if (LE_FAILURE(success)) { @@ -57,7 +57,7 @@ le_uint32 delta; for (le_uint16 subtable = 0; subtable < subtableCount; subtable += 1) { - const LookupSubtable *lookupSubtable = lookupTable->getLookupSubtable(subtable); + LEReferenceTo<LookupSubtable> lookupSubtable = lookupTable->getLookupSubtable(lookupTable, subtable, success); delta = applySubtable(lookupSubtable, lookupType, glyphIterator, fontInstance, success); @@ -72,7 +72,7 @@ } le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, - le_bool rightToLeft, const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, + le_bool rightToLeft, const LEReferenceTo<GlyphDefinitionTableHeader> &glyphDefinitionTableHeader, const LEFontInstance *fontInstance, LEErrorCode& success) const { if (LE_FAILURE(success)) { @@ -89,22 +89,21 @@ rightToLeft, 0, 0, glyphDefinitionTableHeader); le_int32 newGlyphCount = glyphCount; - for (le_uint16 order = 0; order < lookupOrderCount; order += 1) { + for (le_uint16 order = 0; order < lookupOrderCount && LE_SUCCESS(success); order += 1) { le_uint16 lookup = lookupOrderArray[order]; FeatureMask selectMask = lookupSelectArray[lookup]; if (selectMask != 0) { - const LookupTable *lookupTable = lookupListTable->getLookupTable(lookup); - - if (!lookupTable) + const LEReferenceTo<LookupTable> lookupTable = lookupListTable->getLookupTable(lookupListTable, lookup, success); + if (!lookupTable.isValid() ||LE_FAILURE(success) ) { continue; - + } le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags); glyphIterator.reset(lookupFlags, selectMask); while (glyphIterator.findFeatureTag()) { - applyLookupTable(lookupTable, &glyphIterator, fontInstance, success); + applyLookupTable(lookupTable, &glyphIterator, fontInstance, success); // TODO if (LE_FAILURE(success)) { return 0; } @@ -124,8 +123,8 @@ return 0; } - const LookupTable *lookupTable = lookupListTable->getLookupTable(lookupTableIndex); - if (lookupTable == NULL) { + const LEReferenceTo<LookupTable> lookupTable = lookupListTable->getLookupTable(lookupListTable, lookupTableIndex, success); + if (!lookupTable.isValid()) { success = LE_INTERNAL_ERROR; return 0; } @@ -136,33 +135,35 @@ return delta; } -le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order) +le_int32 LookupProcessor::selectLookups(const LEReferenceTo<FeatureTable> &featureTable, FeatureMask featureMask, le_int32 order, LEErrorCode &success) { - le_uint16 lookupCount = featureTable? SWAPW(featureTable->lookupCount) : 0; + le_uint16 lookupCount = featureTable.isValid()? SWAPW(featureTable->lookupCount) : 0; le_int32 store = order; - for (le_uint16 lookup = 0; lookup < lookupCount; lookup += 1) { - le_uint16 lookupListIndex = SWAPW(featureTable->lookupListIndexArray[lookup]); + LEReferenceToArrayOf<le_uint16> lookupListIndexArray(featureTable, success, featureTable->lookupListIndexArray, lookupCount); - if (lookupListIndex >= lookupSelectCount) - continue; + for (le_uint16 lookup = 0; LE_SUCCESS(success) && lookup < lookupCount; lookup += 1) { + le_uint16 lookupListIndex = SWAPW(lookupListIndexArray.getObject(lookup,success)); + if (lookupListIndex >= lookupSelectCount) { + continue; + } - lookupSelectArray[lookupListIndex] |= featureMask; - lookupOrderArray[store++] = lookupListIndex; + lookupSelectArray[lookupListIndex] |= featureMask; + lookupOrderArray[store++] = lookupListIndex; } return store - order; } -LookupProcessor::LookupProcessor(const char *baseAddress, +LookupProcessor::LookupProcessor(const LETableReference &baseAddress, Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset, LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures, LEErrorCode& success) - : lookupListTable(NULL), featureListTable(NULL), lookupSelectArray(NULL), lookupSelectCount(0), - lookupOrderArray(NULL), lookupOrderCount(0) + : lookupListTable(), featureListTable(), lookupSelectArray(NULL), lookupSelectCount(0), + lookupOrderArray(NULL), lookupOrderCount(0), fReference(baseAddress) { - const ScriptListTable *scriptListTable = NULL; - const LangSysTable *langSysTable = NULL; + LEReferenceTo<ScriptListTable> scriptListTable; + LEReferenceTo<LangSysTable> langSysTable; le_uint16 featureCount = 0; le_uint16 lookupListCount = 0; le_uint16 requiredFeatureIndex; @@ -172,29 +173,33 @@ } if (scriptListOffset != 0) { - scriptListTable = (const ScriptListTable *) (baseAddress + scriptListOffset); - langSysTable = scriptListTable->findLanguage(scriptTag, languageTag); + scriptListTable = LEReferenceTo<ScriptListTable>(baseAddress, success, scriptListOffset); + langSysTable = scriptListTable->findLanguage(scriptListTable, scriptTag, languageTag, success); - if (langSysTable != 0) { - featureCount = SWAPW(langSysTable->featureCount); - } + if (langSysTable.isValid() && LE_SUCCESS(success)) { + featureCount = SWAPW(langSysTable->featureCount); + } } if (featureListOffset != 0) { - featureListTable = (const FeatureListTable *) (baseAddress + featureListOffset); + featureListTable = LEReferenceTo<FeatureListTable>(baseAddress, success, featureListOffset); } if (lookupListOffset != 0) { - lookupListTable = (const LookupListTable *) (baseAddress + lookupListOffset); + lookupListTable = LEReferenceTo<LookupListTable>(baseAddress,success, lookupListOffset); + if(LE_SUCCESS(success) && lookupListTable.isValid()) { lookupListCount = SWAPW(lookupListTable->lookupCount); + } } - if (langSysTable == NULL || featureListTable == NULL || lookupListTable == NULL || + if (langSysTable.isEmpty() || featureListTable.isEmpty() || lookupListTable.isEmpty() || featureCount == 0 || lookupListCount == 0) { return; } - requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex); + if(langSysTable.isValid()) { + requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex); + } lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount); if (lookupSelectArray == NULL) { @@ -209,31 +214,39 @@ lookupSelectCount = lookupListCount; le_int32 count, order = 0; - le_int32 featureReferences = 0; - const FeatureTable *featureTable = NULL; + le_uint32 featureReferences = 0; + LEReferenceTo<FeatureTable> featureTable; LETag featureTag; - const FeatureTable *requiredFeatureTable = NULL; + LEReferenceTo<FeatureTable> requiredFeatureTable; LETag requiredFeatureTag = 0x00000000U; // Count the total number of lookups referenced by all features. This will // be the maximum number of entries in the lookupOrderArray. We can't use // lookupListCount because some lookups might be referenced by more than // one feature. - for (le_int32 feature = 0; feature < featureCount; feature += 1) { - le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); + if(featureListTable.isValid() && LE_SUCCESS(success)) { + LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount); - featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); + for (le_uint32 feature = 0; LE_SUCCESS(success)&&(feature < featureCount); feature += 1) { + le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature, success)); - if (!featureTable) - continue; + featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success); + if (!featureTable.isValid() || LE_FAILURE(success)) { + continue; + } + featureReferences += SWAPW(featureTable->lookupCount); + } + } - featureReferences += SWAPW(featureTable->lookupCount); + if (!featureTable.isValid() || LE_FAILURE(success)) { + success = LE_INTERNAL_ERROR; + return; } if (requiredFeatureIndex != 0xFFFF) { - requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag); - featureReferences += SWAPW(featureTable->lookupCount); + requiredFeatureTable = featureListTable->getFeatureTable(featureListTable, requiredFeatureIndex, &requiredFeatureTag, success); + featureReferences += SWAPW(featureTable->lookupCount); } lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences); @@ -248,7 +261,7 @@ // If this is the required feature, add its lookups if (requiredFeatureTag == fm.tag) { - count += selectLookups(requiredFeatureTable, fm.mask, order); + count += selectLookups(requiredFeatureTable, fm.mask, order, success); } if (orderFeatures) { @@ -258,7 +271,8 @@ } for (le_uint16 feature = 0; feature < featureCount; feature += 1) { - le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); + LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount); + le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success)); // don't add the required feature to the list more than once... // TODO: Do we need this check? (Spec. says required feature won't be in feature list...) @@ -266,10 +280,10 @@ continue; } - featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); + featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success); if (featureTag == fm.tag) { - count += selectLookups(featureTable, fm.mask, order + count); + count += selectLookups(featureTable, fm.mask, order + count, success); } } @@ -278,9 +292,10 @@ } order += count; - } else { - for (le_uint16 feature = 0; feature < featureCount; feature += 1) { - le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); + } else if(langSysTable.isValid()) { + LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount); + for (le_uint16 feature = 0; LE_SUCCESS(success)&& (feature < featureCount); feature += 1) { + le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success)); // don't add the required feature to the list more than once... // NOTE: This check is commented out because the spec. says that @@ -292,10 +307,10 @@ } #endif - featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); + featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success); if (featureTag == fm.tag) { - order += selectLookups(featureTable, fm.mask, order); + order += selectLookups(featureTable, fm.mask, order, success); } } }
--- a/src/share/native/sun/font/layout/LookupProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LookupProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -41,6 +41,7 @@ #include "LETypes.h" #include "LEFontInstance.h" #include "OpenTypeTables.h" +#include "LETableReference.h" //#include "Lookups.h" //#include "Features.h" @@ -59,19 +60,21 @@ class LookupProcessor : public UMemory { public: le_int32 process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, - le_bool rightToLeft, const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, const LEFontInstance *fontInstance, LEErrorCode& success) const; + le_bool rightToLeft, const LEReferenceTo<GlyphDefinitionTableHeader> &glyphDefinitionTableHeader, const LEFontInstance *fontInstance, LEErrorCode& success) const; - le_uint32 applyLookupTable(const LookupTable *lookupTable, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; + le_uint32 applyLookupTable(const LEReferenceTo<LookupTable> &lookupTable, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; le_uint32 applySingleLookup(le_uint16 lookupTableIndex, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const; - virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 subtableType, + virtual le_uint32 applySubtable(const LEReferenceTo<LookupSubtable> &lookupSubtable, le_uint16 subtableType, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const = 0; virtual ~LookupProcessor(); + const LETableReference &getReference() const { return fReference; } + protected: - LookupProcessor(const char *baseAddress, + LookupProcessor(const LETableReference &baseAddress, Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset, @@ -84,10 +87,10 @@ LookupProcessor(); - le_int32 selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order); + le_int32 selectLookups(const LEReferenceTo<FeatureTable> &featureTable, FeatureMask featureMask, le_int32 order, LEErrorCode &success); - const LookupListTable *lookupListTable; - const FeatureListTable *featureListTable; + LEReferenceTo<LookupListTable> lookupListTable; + LEReferenceTo<FeatureListTable> featureListTable; FeatureMask *lookupSelectArray; le_uint32 lookupSelectCount; @@ -95,6 +98,8 @@ le_uint16 *lookupOrderArray; le_uint32 lookupOrderCount; + LETableReference fReference; + private: LookupProcessor(const LookupProcessor &other); // forbid copying of this class
--- a/src/share/native/sun/font/layout/LookupTables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LookupTables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -49,22 +49,26 @@ of the derived classes, and implement it in the others by casting the "this" pointer to the type that has the implementation. */ -const LookupSegment *BinarySearchLookupTable::lookupSegment(const LookupSegment *segments, LEGlyphID glyph) const +const LookupSegment *BinarySearchLookupTable::lookupSegment(const LETableReference &base, const LookupSegment *segments, LEGlyphID glyph, LEErrorCode &success) const { + le_int16 unity = SWAPW(unitSize); le_int16 probe = SWAPW(searchRange); le_int16 extra = SWAPW(rangeShift); TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph); - const LookupSegment *entry = segments; - const LookupSegment *trial = (const LookupSegment *) ((char *) entry + extra); + LEReferenceTo<LookupSegment> entry(base, success, segments); + LEReferenceTo<LookupSegment> trial(entry, success, extra); + + if(LE_FAILURE(success)) return NULL; if (SWAPW(trial->lastGlyph) <= ttGlyph) { entry = trial; } - while (probe > unity) { + while (probe > unity && LE_SUCCESS(success)) { probe >>= 1; - trial = (const LookupSegment *) ((char *) entry + probe); + trial = entry; // copy + trial.addOffset(probe, success); if (SWAPW(trial->lastGlyph) <= ttGlyph) { entry = trial; @@ -72,28 +76,29 @@ } if (SWAPW(entry->firstGlyph) <= ttGlyph) { - return entry; + return entry.getAlias(); } return NULL; } -const LookupSingle *BinarySearchLookupTable::lookupSingle(const LookupSingle *entries, LEGlyphID glyph) const +const LookupSingle *BinarySearchLookupTable::lookupSingle(const LETableReference &base, const LookupSingle *entries, LEGlyphID glyph, LEErrorCode &success) const { le_int16 unity = SWAPW(unitSize); le_int16 probe = SWAPW(searchRange); le_int16 extra = SWAPW(rangeShift); TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph); - const LookupSingle *entry = entries; - const LookupSingle *trial = (const LookupSingle *) ((char *) entry + extra); + LEReferenceTo<LookupSingle> entry(base, success, entries); + LEReferenceTo<LookupSingle> trial(entry, success, extra); if (SWAPW(trial->glyph) <= ttGlyph) { entry = trial; } - while (probe > unity) { + while (probe > unity && LE_SUCCESS(success)) { probe >>= 1; - trial = (const LookupSingle *) ((char *) entry + probe); + trial = entry; + trial.addOffset(probe, success); if (SWAPW(trial->glyph) <= ttGlyph) { entry = trial; @@ -101,7 +106,7 @@ } if (SWAPW(entry->glyph) == ttGlyph) { - return entry; + return entry.getAlias(); } return NULL;
--- a/src/share/native/sun/font/layout/LookupTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/LookupTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -39,6 +39,7 @@ #include "LETypes.h" #include "LayoutTables.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -79,30 +80,34 @@ le_int16 entrySelector; le_int16 rangeShift; - const LookupSegment *lookupSegment(const LookupSegment *segments, LEGlyphID glyph) const; + const LookupSegment *lookupSegment(const LETableReference &base, const LookupSegment *segments, LEGlyphID glyph, LEErrorCode &success) const; - const LookupSingle *lookupSingle(const LookupSingle *entries, LEGlyphID glyph) const; + const LookupSingle *lookupSingle(const LETableReference &base, const LookupSingle *entries, LEGlyphID glyph, LEErrorCode &success) const; }; struct SimpleArrayLookupTable : LookupTable { LookupValue valueArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SimpleArrayLookupTable, valueArray) struct SegmentSingleLookupTable : BinarySearchLookupTable { LookupSegment segments[ANY_NUMBER]; }; +LE_VAR_ARRAY(SegmentSingleLookupTable, segments) struct SegmentArrayLookupTable : BinarySearchLookupTable { LookupSegment segments[ANY_NUMBER]; }; +LE_VAR_ARRAY(SegmentArrayLookupTable, segments) struct SingleTableLookupTable : BinarySearchLookupTable { LookupSingle entries[ANY_NUMBER]; }; +LE_VAR_ARRAY(SingleTableLookupTable, entries) struct TrimmedArrayLookupTable : LookupTable { @@ -110,6 +115,7 @@ TTGlyphID glyphCount; LookupValue valueArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(TrimmedArrayLookupTable, valueArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/Lookups.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/Lookups.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -37,33 +37,35 @@ U_NAMESPACE_BEGIN -const LookupTable *LookupListTable::getLookupTable(le_uint16 lookupTableIndex) const +const LEReferenceTo<LookupTable> LookupListTable::getLookupTable(const LEReferenceTo<LookupListTable> &base, le_uint16 lookupTableIndex, LEErrorCode &success) const { - if (lookupTableIndex >= SWAPW(lookupCount)) { - return 0; - } + LEReferenceToArrayOf<Offset> lookupTableOffsetArrayRef(base, success, (const Offset*)&lookupTableOffsetArray, SWAPW(lookupCount)); - Offset lookupTableOffset = lookupTableOffsetArray[lookupTableIndex]; - - return (const LookupTable *) ((char *) this + SWAPW(lookupTableOffset)); + if(LE_FAILURE(success) || lookupTableIndex>lookupTableOffsetArrayRef.getCount()) { + return LEReferenceTo<LookupTable>(); + } else { + return LEReferenceTo<LookupTable>(base, success, SWAPW(lookupTableOffsetArrayRef.getObject(lookupTableIndex, success))); + } } -const LookupSubtable *LookupTable::getLookupSubtable(le_uint16 subtableIndex) const +const LEReferenceTo<LookupSubtable> LookupTable::getLookupSubtable(const LEReferenceTo<LookupTable> &base, le_uint16 subtableIndex, LEErrorCode &success) const { - if (subtableIndex >= SWAPW(subTableCount)) { - return 0; - } + LEReferenceToArrayOf<Offset> subTableOffsetArrayRef(base, success, (const Offset*)&subTableOffsetArray, SWAPW(subTableCount)); - Offset subtableOffset = subTableOffsetArray[subtableIndex]; - - return (const LookupSubtable *) ((char *) this + SWAPW(subtableOffset)); + if(LE_FAILURE(success) || subtableIndex>subTableOffsetArrayRef.getCount()) { + return LEReferenceTo<LookupSubtable>(); + } else { + return LEReferenceTo<LookupSubtable>(base, success, SWAPW(subTableOffsetArrayRef.getObject(subtableIndex, success))); + } } -le_int32 LookupSubtable::getGlyphCoverage(Offset tableOffset, LEGlyphID glyphID) const +le_int32 LookupSubtable::getGlyphCoverage(const LEReferenceTo<LookupSubtable> &base, Offset tableOffset, LEGlyphID glyphID, LEErrorCode &success) const { - const CoverageTable *coverageTable = (const CoverageTable *) ((char *) this + SWAPW(tableOffset)); + const LEReferenceTo<CoverageTable> coverageTable(base, success, SWAPW(tableOffset)); - return coverageTable->getGlyphCoverage(glyphID); + if(LE_FAILURE(success)) return 0; + + return coverageTable->getGlyphCoverage(glyphID); } U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/Lookups.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/Lookups.h Wed Apr 17 02:53:02 2013 -0700 @@ -58,9 +58,14 @@ le_uint16 subtableFormat; Offset coverageTableOffset; - inline le_int32 getGlyphCoverage(LEGlyphID glyphID) const; + inline le_int32 getGlyphCoverage(const LEReferenceTo<LookupSubtable> &base, LEGlyphID glyphID, LEErrorCode &success) const; + + le_int32 getGlyphCoverage(const LEReferenceTo<LookupSubtable> &base, Offset tableOffset, LEGlyphID glyphID, LEErrorCode &success) const; - le_int32 getGlyphCoverage(Offset tableOffset, LEGlyphID glyphID) const; + // convenience + inline le_int32 getGlyphCoverage(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const; + + inline le_int32 getGlyphCoverage(const LETableReference &base, Offset tableOffset, LEGlyphID glyphID, LEErrorCode &success) const; }; struct LookupTable @@ -70,20 +75,32 @@ le_uint16 subTableCount; Offset subTableOffsetArray[ANY_NUMBER]; - const LookupSubtable *getLookupSubtable(le_uint16 subtableIndex) const; + const LEReferenceTo<LookupSubtable> getLookupSubtable(const LEReferenceTo<LookupTable> &base, le_uint16 subtableIndex, LEErrorCode &success) const; }; +LE_VAR_ARRAY(LookupTable, subTableOffsetArray) struct LookupListTable { le_uint16 lookupCount; Offset lookupTableOffsetArray[ANY_NUMBER]; - const LookupTable *getLookupTable(le_uint16 lookupTableIndex) const; + const LEReferenceTo<LookupTable> getLookupTable(const LEReferenceTo<LookupListTable> &base, le_uint16 lookupTableIndex, LEErrorCode &success) const; }; +LE_VAR_ARRAY(LookupListTable, lookupTableOffsetArray) + +inline le_int32 LookupSubtable::getGlyphCoverage(const LEReferenceTo<LookupSubtable> &base, LEGlyphID glyphID, LEErrorCode &success) const +{ + return getGlyphCoverage(base, coverageTableOffset, glyphID, success); +} -inline le_int32 LookupSubtable::getGlyphCoverage(LEGlyphID glyphID) const -{ - return getGlyphCoverage(coverageTableOffset, glyphID); +inline le_int32 LookupSubtable::getGlyphCoverage(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const { + LEReferenceTo<LookupSubtable> thisRef(base, success, this); + return getGlyphCoverage(thisRef, glyphID, success); +} + +inline le_int32 LookupSubtable::getGlyphCoverage(const LETableReference &base, Offset tableOffset, LEGlyphID glyphID, LEErrorCode &success) const { + LEReferenceTo<LookupSubtable> thisRef(base, success, this); + return getGlyphCoverage(thisRef, tableOffset, glyphID, success); } U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/MPreFixups.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MPreFixups.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 2002-2008 - All Rights Reserved + * (C) Copyright IBM Corp. 2002-2013 - All Rights Reserved * */ @@ -65,9 +65,9 @@ } } -void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& leSuccess) +void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& success) { - if (LE_FAILURE(leSuccess)) { + if (LE_FAILURE(success)) { return; }
--- a/src/share/native/sun/font/layout/MarkArrays.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MarkArrays.h Wed Apr 17 02:53:02 2013 -0700 @@ -57,6 +57,7 @@ le_int32 getMarkClass(LEGlyphID glyphID, le_int32 coverageIndex, const LEFontInstance *fontInstance, LEPoint &anchor) const; }; +LE_VAR_ARRAY(MarkArray, markRecordArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -51,10 +51,10 @@ return 0xFFFF; } -le_int32 MarkToBasePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_int32 MarkToBasePositioningSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); - le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph); + le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); if (markCoverage < 0) { // markGlyph isn't a covered mark glyph @@ -75,7 +75,7 @@ // FIXME: We probably don't want to find a base glyph before a previous ligature... GlyphIterator baseIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreLigatures*/)); LEGlyphID baseGlyph = findBaseGlyph(&baseIterator); - le_int32 baseCoverage = getBaseCoverage((LEGlyphID) baseGlyph); + le_int32 baseCoverage = getBaseCoverage(base, (LEGlyphID) baseGlyph, success); const BaseArray *baseArray = (const BaseArray *) ((char *) this + SWAPW(baseArrayOffset)); le_uint16 baseCount = SWAPW(baseArray->baseRecordCount);
--- a/src/share/native/sun/font/layout/MarkToBasePosnSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MarkToBasePosnSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -48,7 +48,7 @@ struct MarkToBasePositioningSubtable : AttachmentPositioningSubtable { - le_int32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_int32 process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; LEGlyphID findBaseGlyph(GlyphIterator *glyphIterator) const; }; @@ -56,12 +56,14 @@ { Offset baseAnchorTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(BaseRecord, baseAnchorTableOffsetArray) struct BaseArray { le_int16 baseRecordCount; BaseRecord baseRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(BaseArray, baseRecordArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -50,10 +50,10 @@ return 0xFFFF; } -le_int32 MarkToLigaturePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_int32 MarkToLigaturePositioningSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); - le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph); + le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); if (markCoverage < 0) { // markGlyph isn't a covered mark glyph @@ -74,7 +74,7 @@ // FIXME: we probably don't want to find a ligature before a previous base glyph... GlyphIterator ligatureIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreBaseGlyphs*/)); LEGlyphID ligatureGlyph = findLigatureGlyph(&ligatureIterator); - le_int32 ligatureCoverage = getBaseCoverage((LEGlyphID) ligatureGlyph); + le_int32 ligatureCoverage = getBaseCoverage(base, (LEGlyphID) ligatureGlyph, success); const LigatureArray *ligatureArray = (const LigatureArray *) ((char *) this + SWAPW(baseArrayOffset)); le_uint16 ligatureCount = SWAPW(ligatureArray->ligatureCount);
--- a/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -48,7 +48,7 @@ struct MarkToLigaturePositioningSubtable : AttachmentPositioningSubtable { - le_int32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_int32 process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; LEGlyphID findLigatureGlyph(GlyphIterator *glyphIterator) const; }; @@ -56,18 +56,21 @@ { Offset ligatureAnchorTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ComponentRecord, ligatureAnchorTableOffsetArray) struct LigatureAttachTable { le_uint16 componentCount; ComponentRecord componentRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureAttachTable, componentRecordArray) struct LigatureArray { le_uint16 ligatureCount; Offset ligatureAttachTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LigatureArray, ligatureAttachTableOffsetArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -51,10 +51,10 @@ return 0xFFFF; } -le_int32 MarkToMarkPositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_int32 MarkToMarkPositioningSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); - le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph); + le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); if (markCoverage < 0) { // markGlyph isn't a covered mark glyph @@ -74,7 +74,7 @@ GlyphIterator mark2Iterator(*glyphIterator); LEGlyphID mark2Glyph = findMark2Glyph(&mark2Iterator); - le_int32 mark2Coverage = getBaseCoverage((LEGlyphID) mark2Glyph); + le_int32 mark2Coverage = getBaseCoverage(base, (LEGlyphID) mark2Glyph, success); const Mark2Array *mark2Array = (const Mark2Array *) ((char *) this + SWAPW(baseArrayOffset)); le_uint16 mark2Count = SWAPW(mark2Array->mark2RecordCount);
--- a/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -48,7 +48,7 @@ struct MarkToMarkPositioningSubtable : AttachmentPositioningSubtable { - le_int32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_int32 process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; LEGlyphID findMark2Glyph(GlyphIterator *glyphIterator) const; }; @@ -56,12 +56,14 @@ { Offset mark2AnchorTableOffsetArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(Mark2Record, mark2AnchorTableOffsetArray) struct Mark2Array { le_uint16 mark2RecordCount; Mark2Record mark2RecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(Mark2Array, mark2RecordArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/MorphStateTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MorphStateTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -49,5 +49,10 @@ StateTableHeader stHeader; }; +struct MorphStateTableHeader2 : MorphSubtableHeader2 +{ + StateTableHeader2 stHeader; +}; + U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/MorphTables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MorphTables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -44,61 +44,61 @@ U_NAMESPACE_BEGIN -void MorphTableHeader::process(LEGlyphStorage &glyphStorage) const +void MorphTableHeader::process(const LETableReference &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const { - const ChainHeader *chainHeader = chains; - le_uint32 chainCount = SWAPL(this->nChains); + le_uint32 chainCount = SWAPL(this->nChains); + LEReferenceTo<ChainHeader> chainHeader(base, success, chains); // moving header + LEReferenceToArrayOf<ChainHeader> chainHeaderArray(base, success, chains, chainCount); le_uint32 chain; - for (chain = 0; chain < chainCount; chain += 1) { + for (chain = 0; LE_SUCCESS(success) && (chain < chainCount); chain += 1) { FeatureFlags defaultFlags = SWAPL(chainHeader->defaultFlags); le_uint32 chainLength = SWAPL(chainHeader->chainLength); le_int16 nFeatureEntries = SWAPW(chainHeader->nFeatureEntries); le_int16 nSubtables = SWAPW(chainHeader->nSubtables); - const MorphSubtableHeader *subtableHeader = - (const MorphSubtableHeader *)&chainHeader->featureTable[nFeatureEntries]; + LEReferenceTo<MorphSubtableHeader> subtableHeader = + LEReferenceTo<MorphSubtableHeader>(chainHeader,success, &(chainHeader->featureTable[nFeatureEntries])); le_int16 subtable; - for (subtable = 0; subtable < nSubtables; subtable += 1) { + for (subtable = 0; LE_SUCCESS(success) && (subtable < nSubtables); subtable += 1) { le_int16 length = SWAPW(subtableHeader->length); SubtableCoverage coverage = SWAPW(subtableHeader->coverage); FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures); // should check coverage more carefully... - if ((coverage & scfVertical) == 0 && (subtableFeatures & defaultFlags) != 0) { - subtableHeader->process(glyphStorage); + if ((coverage & scfVertical) == 0 && (subtableFeatures & defaultFlags) != 0 && LE_SUCCESS(success)) { + subtableHeader->process(subtableHeader, glyphStorage, success); } - subtableHeader = (const MorphSubtableHeader *) ((char *)subtableHeader + length); + subtableHeader.addOffset(length, success); } - - chainHeader = (const ChainHeader *)((char *)chainHeader + chainLength); + chainHeader.addOffset(chainLength, success); } } -void MorphSubtableHeader::process(LEGlyphStorage &glyphStorage) const +void MorphSubtableHeader::process(const LEReferenceTo<MorphSubtableHeader> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const { SubtableProcessor *processor = NULL; switch (SWAPW(coverage) & scfTypeMask) { case mstIndicRearrangement: - processor = new IndicRearrangementProcessor(this); + processor = new IndicRearrangementProcessor(base, success); break; case mstContextualGlyphSubstitution: - processor = new ContextualGlyphSubstitutionProcessor(this); + processor = new ContextualGlyphSubstitutionProcessor(base, success); break; case mstLigatureSubstitution: - processor = new LigatureSubstitutionProcessor(this); + processor = new LigatureSubstitutionProcessor(base, success); break; case mstReservedUnused: break; case mstNonContextualGlyphSubstitution: - processor = NonContextualGlyphSubstitutionProcessor::createInstance(this); + processor = NonContextualGlyphSubstitutionProcessor::createInstance(base, success); break; /* @@ -112,8 +112,10 @@ } if (processor != NULL) { - processor->process(glyphStorage); - delete processor; + if(LE_SUCCESS(success)) { + processor->process(glyphStorage, success); + } + delete processor; } }
--- a/src/share/native/sun/font/layout/MorphTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MorphTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -39,6 +39,7 @@ #include "LETypes.h" #include "LayoutTables.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -65,6 +66,7 @@ le_int16 nSubtables; FeatureTableEntry featureTable[ANY_NUMBER]; }; +LE_VAR_ARRAY(ChainHeader, featureTable) struct MorphTableHeader { @@ -72,10 +74,12 @@ le_uint32 nChains; ChainHeader chains[ANY_NUMBER]; - void process(LEGlyphStorage &glyphStorage) const; + void process(const LETableReference& base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const; }; +LE_VAR_ARRAY(MorphTableHeader, chains) typedef le_int16 SubtableCoverage; +typedef le_uint32 SubtableCoverage2; enum SubtableCoverageFlags { @@ -102,7 +106,305 @@ SubtableCoverage coverage; FeatureFlags subtableFeatures; - void process(LEGlyphStorage &glyphStorage) const; + void process(const LEReferenceTo<MorphSubtableHeader> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const; +}; + +enum SubtableCoverageFlags2 +{ + scfVertical2 = 0x80000000, + scfReverse2 = 0x40000000, + scfIgnoreVt2 = 0x20000000, + scfReserved2 = 0x1FFFFF00, + scfTypeMask2 = 0x000000FF +}; + +struct MorphSubtableHeader2 +{ + le_uint32 length; + SubtableCoverage2 coverage; + FeatureFlags subtableFeatures; + + void process(const LEReferenceTo<MorphSubtableHeader2> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const; +}; + +struct ChainHeader2 +{ + FeatureFlags defaultFlags; + le_uint32 chainLength; + le_uint32 nFeatureEntries; + le_uint32 nSubtables; + FeatureTableEntry featureTable[ANY_NUMBER]; +}; +LE_VAR_ARRAY(ChainHeader2, featureTable) + +struct MorphTableHeader2 +{ + le_int32 version; + le_uint32 nChains; + ChainHeader2 chains[ANY_NUMBER]; + + void process(const LEReferenceTo<MorphTableHeader2> &base, LEGlyphStorage &glyphStorage, le_int32 typoFlags, LEErrorCode &success) const; +}; +LE_VAR_ARRAY(MorphTableHeader2, chains) + +/* + * AAT Font Features + * source: https://developer.apple.com/fonts/registry/ + * (plus addition from ATS/SFNTLayoutTypes.h) + */ + +enum { + + allTypographicFeaturesType = 0, + + allTypeFeaturesOnSelector = 0, + allTypeFeaturesOffSelector = 1, + + ligaturesType = 1, + + requiredLigaturesOnSelector = 0, + requiredLigaturesOffSelector = 1, + commonLigaturesOnSelector = 2, + commonLigaturesOffSelector = 3, + rareLigaturesOnSelector = 4, + rareLigaturesOffSelector = 5, + logosOnSelector = 6, + logosOffSelector = 7, + rebusPicturesOnSelector = 8, + rebusPicturesOffSelector = 9, + diphthongLigaturesOnSelector = 10, + diphthongLigaturesOffSelector = 11, + squaredLigaturesOnSelector = 12, + squaredLigaturesOffSelector = 13, + abbrevSquaredLigaturesOnSelector = 14, + abbrevSquaredLigaturesOffSelector = 15, + symbolLigaturesOnSelector = 16, + symbolLigaturesOffSelector = 17, + contextualLigaturesOnSelector = 18, + contextualLigaturesOffSelector = 19, + historicalLigaturesOnSelector = 20, + historicalLigaturesOffSelector = 21, + + cursiveConnectionType = 2, + + unconnectedSelector = 0, + partiallyConnectedSelector = 1, + cursiveSelector = 2, + + letterCaseType = 3, + + upperAndLowerCaseSelector = 0, + allCapsSelector = 1, + allLowerCaseSelector = 2, + smallCapsSelector = 3, + initialCapsSelector = 4, + initialCapsAndSmallCapsSelector = 5, + + verticalSubstitutionType = 4, + + substituteVerticalFormsOnSelector = 0, + substituteVerticalFormsOffSelector = 1, + + linguisticRearrangementType = 5, + + linguisticRearrangementOnSelector = 0, + linguisticRearrangementOffSelector = 1, + + numberSpacingType = 6, + + monospacedNumbersSelector = 0, + proportionalNumbersSelector = 1, + + /* + appleReserved1Type = 7, + */ + + smartSwashType = 8, + + wordInitialSwashesOnSelector = 0, + wordInitialSwashesOffSelector = 1, + wordFinalSwashesOnSelector = 2, + wordFinalSwashesOffSelector = 3, + lineInitialSwashesOnSelector = 4, + lineInitialSwashesOffSelector = 5, + lineFinalSwashesOnSelector = 6, + lineFinalSwashesOffSelector = 7, + nonFinalSwashesOnSelector = 8, + nonFinalSwashesOffSelector = 9, + + diacriticsType = 9, + + showDiacriticsSelector = 0, + hideDiacriticsSelector = 1, + decomposeDiacriticsSelector = 2, + + verticalPositionType = 10, + + normalPositionSelector = 0, + superiorsSelector = 1, + inferiorsSelector = 2, + ordinalsSelector = 3, + + fractionsType = 11, + + noFractionsSelector = 0, + verticalFractionsSelector = 1, + diagonalFractionsSelector = 2, + + /* + appleReserved2Type = 12, + */ + + overlappingCharactersType = 13, + + preventOverlapOnSelector = 0, + preventOverlapOffSelector = 1, + + typographicExtrasType = 14, + + hyphensToEmDashOnSelector = 0, + hyphensToEmDashOffSelector = 1, + hyphenToEnDashOnSelector = 2, + hyphenToEnDashOffSelector = 3, + unslashedZeroOnSelector = 4, + slashedZeroOffSelector = 4, + unslashedZeroOffSelector = 5, + slashedZeroOnSelector = 5, + formInterrobangOnSelector = 6, + formInterrobangOffSelector = 7, + smartQuotesOnSelector = 8, + smartQuotesOffSelector = 9, + periodsToEllipsisOnSelector = 10, + periodsToEllipsisOffSelector = 11, + + mathematicalExtrasType = 15, + + hyphenToMinusOnSelector = 0, + hyphenToMinusOffSelector = 1, + asteriskToMultiplyOnSelector = 2, + asteriskToMultiplyOffSelector = 3, + slashToDivideOnSelector = 4, + slashToDivideOffSelector = 5, + inequalityLigaturesOnSelector = 6, + inequalityLigaturesOffSelector = 7, + exponentsOnSelector = 8, + exponentsOffSelector = 9, + + ornamentSetsType = 16, + + noOrnamentsSelector = 0, + dingbatsSelector = 1, + piCharactersSelector = 2, + fleuronsSelector = 3, + decorativeBordersSelector = 4, + internationalSymbolsSelector = 5, + mathSymbolsSelector = 6, + + characterAlternativesType = 17, + + noAlternatesSelector = 0, + + designComplexityType = 18, + + designLevel1Selector = 0, + designLevel2Selector = 1, + designLevel3Selector = 2, + designLevel4Selector = 3, + designLevel5Selector = 4, + designLevel6Selector = 5, + designLevel7Selector = 6, + + styleOptionsType = 19, + + noStyleOptionsSelector = 0, + displayTextSelector = 1, + engravedTextSelector = 2, + illuminatedCapsSelector = 3, + titlingCapsSelector = 4, + tallCapsSelector = 5, + + characterShapeType = 20, + + traditionalCharactersSelector = 0, + simplifiedCharactersSelector = 1, + jis1978CharactersSelector = 2, + jis1983CharactersSelector = 3, + jis1990CharactersSelector = 4, + traditionalAltOneSelector = 5, + traditionalAltTwoSelector = 6, + traditionalAltThreeSelector = 7, + traditionalAltFourSelector = 8, + traditionalAltFiveSelector = 9, + expertCharactersSelector = 10, + + numberCaseType = 21, + + lowerCaseNumbersSelector = 0, + upperCaseNumbersSelector = 1, + + textSpacingType = 22, + + proportionalTextSelector = 0, + monospacedTextSelector = 1, + halfWidthTextSelector = 2, + normallySpacedTextSelector = 3, + + transliterationType = 23, + + noTransliterationSelector = 0, + hanjaToHangulSelector = 1, + hiraganaToKatakanaSelector = 2, + katakanaToHiraganaSelector = 3, + kanaToRomanizationSelector = 4, + romanizationToHiraganaSelector = 5, + romanizationToKatakanaSelector = 6, + hanjaToHangulAltOneSelector = 7, + hanjaToHangulAltTwoSelector = 8, + hanjaToHangulAltThreeSelector = 9, + + annotationType = 24, + + noAnnotationSelector = 0, + boxAnnotationSelector = 1, + roundedBoxAnnotationSelector = 2, + circleAnnotationSelector = 3, + invertedCircleAnnotationSelector = 4, + parenthesisAnnotationSelector = 5, + periodAnnotationSelector = 6, + romanNumeralAnnotationSelector = 7, + diamondAnnotationSelector = 8, + + kanaSpacingType = 25, + + fullWidthKanaSelector = 0, + proportionalKanaSelector = 1, + + ideographicSpacingType = 26, + + fullWidthIdeographsSelector = 0, + proportionalIdeographsSelector = 1, + + cjkRomanSpacingType = 103, + + halfWidthCJKRomanSelector = 0, + proportionalCJKRomanSelector = 1, + defaultCJKRomanSelector = 2, + fullWidthCJKRomanSelector = 3, + + rubyKanaType = 28, + + rubyKanaOnSelector = 2, + rubyKanaOffSelector = 3, + +/* The following types are provided for compatibility; note that + their use is deprecated. */ + + adobeCharacterSpacingType = 100, /* prefer 22 */ + adobeKanaSpacingType = 101, /* prefer 25 */ + adobeKanjiSpacingType = 102, /* prefer 26 */ + adobeSquareLigatures = 104, /* prefer 1 */ + + lastFeatureType = -1 }; U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/MorphTables2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,248 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * (C) Copyright IBM Corp. and others 1998 - 2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "LayoutTables.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "IndicRearrangementProcessor2.h" +#include "ContextualGlyphSubstProc2.h" +#include "LigatureSubstProc2.h" +#include "NonContextualGlyphSubstProc2.h" +#include "ContextualGlyphInsertionProc2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +void MorphTableHeader2::process(const LEReferenceTo<MorphTableHeader2> &base, LEGlyphStorage &glyphStorage, + le_int32 typoFlags, LEErrorCode &success) const +{ + if(LE_FAILURE(success)) return; + + le_uint32 chainCount = SWAPL(this->nChains); + LEReferenceTo<ChainHeader2> chainHeader(base, success, &chains[0]); + /* chainHeader and subtableHeader are implemented as a moving pointer rather than an array dereference + * to (slightly) reduce code churn. However, must be careful to preincrement them the 2nd time through. + * We don't want to increment them at the end of the loop, as that would attempt to dereference + * out of range memory. + */ + le_uint32 chain; + + for (chain = 0; LE_SUCCESS(success) && (chain < chainCount); chain++) { + if (chain>0) { + le_uint32 chainLength = SWAPL(chainHeader->chainLength); + chainHeader.addOffset(chainLength, success); // Don't increment the first time + } + FeatureFlags flag = SWAPL(chainHeader->defaultFlags); + le_uint32 nFeatureEntries = SWAPL(chainHeader->nFeatureEntries); + le_uint32 nSubtables = SWAPL(chainHeader->nSubtables); + LEReferenceTo<MorphSubtableHeader2> subtableHeader(chainHeader, + success, (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]); + le_uint32 subtable; + if(LE_FAILURE(success)) break; // malformed table + + if (typoFlags != 0) { + le_uint32 featureEntry; + LEReferenceToArrayOf<FeatureTableEntry> featureTableRef(chainHeader, success, &chainHeader->featureTable[0], nFeatureEntries); + if(LE_FAILURE(success)) break; + // Feature subtables + for (featureEntry = 0; featureEntry < nFeatureEntries; featureEntry++) { + const FeatureTableEntry &featureTableEntry = featureTableRef(featureEntry, success); + le_int16 featureType = SWAPW(featureTableEntry.featureType); + le_int16 featureSetting = SWAPW(featureTableEntry.featureSetting); + le_uint32 enableFlags = SWAPL(featureTableEntry.enableFlags); + le_uint32 disableFlags = SWAPL(featureTableEntry.disableFlags); + switch (featureType) { + case ligaturesType: + if ((typoFlags & LE_Ligatures_FEATURE_ENUM ) && (featureSetting ^ 0x1)){ + flag &= disableFlags; + flag |= enableFlags; + } else { + if (((typoFlags & LE_RLIG_FEATURE_FLAG) && featureSetting == requiredLigaturesOnSelector) || + ((typoFlags & LE_CLIG_FEATURE_FLAG) && featureSetting == contextualLigaturesOnSelector) || + ((typoFlags & LE_HLIG_FEATURE_FLAG) && featureSetting == historicalLigaturesOnSelector) || + ((typoFlags & LE_LIGA_FEATURE_FLAG) && featureSetting == commonLigaturesOnSelector)) { + flag &= disableFlags; + flag |= enableFlags; + } + } + break; + case letterCaseType: + if ((typoFlags & LE_SMCP_FEATURE_FLAG) && featureSetting == smallCapsSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case verticalSubstitutionType: + break; + case linguisticRearrangementType: + break; + case numberSpacingType: + break; + case smartSwashType: + if ((typoFlags & LE_SWSH_FEATURE_FLAG) && (featureSetting ^ 0x1)){ + flag &= disableFlags; + flag |= enableFlags; + } + break; + case diacriticsType: + break; + case verticalPositionType: + break; + case fractionsType: + if (((typoFlags & LE_FRAC_FEATURE_FLAG) && featureSetting == diagonalFractionsSelector) || + ((typoFlags & LE_AFRC_FEATURE_FLAG) && featureSetting == verticalFractionsSelector)) { + flag &= disableFlags; + flag |= enableFlags; + } else { + flag &= disableFlags; + } + break; + case typographicExtrasType: + if ((typoFlags & LE_ZERO_FEATURE_FLAG) && featureSetting == slashedZeroOnSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case mathematicalExtrasType: + break; + case ornamentSetsType: + break; + case characterAlternativesType: + break; + case designComplexityType: + if (((typoFlags & LE_SS01_FEATURE_FLAG) && featureSetting == designLevel1Selector) || + ((typoFlags & LE_SS02_FEATURE_FLAG) && featureSetting == designLevel2Selector) || + ((typoFlags & LE_SS03_FEATURE_FLAG) && featureSetting == designLevel3Selector) || + ((typoFlags & LE_SS04_FEATURE_FLAG) && featureSetting == designLevel4Selector) || + ((typoFlags & LE_SS05_FEATURE_FLAG) && featureSetting == designLevel5Selector) || + ((typoFlags & LE_SS06_FEATURE_FLAG) && featureSetting == designLevel6Selector) || + ((typoFlags & LE_SS07_FEATURE_FLAG) && featureSetting == designLevel7Selector)) { + + flag &= disableFlags; + flag |= enableFlags; + } + break; + case styleOptionsType: + break; + case characterShapeType: + break; + case numberCaseType: + break; + case textSpacingType: + break; + case transliterationType: + break; + case annotationType: + if ((typoFlags & LE_NALT_FEATURE_FLAG) && featureSetting == circleAnnotationSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case kanaSpacingType: + break; + case ideographicSpacingType: + break; + case rubyKanaType: + if ((typoFlags & LE_RUBY_FEATURE_FLAG) && featureSetting == rubyKanaOnSelector) { + flag &= disableFlags; + flag |= enableFlags; + } + break; + case cjkRomanSpacingType: + break; + default: + break; + } + } + } + + for (subtable = 0; LE_SUCCESS(success) && subtable < nSubtables; subtable++) { + if(subtable>0) { + le_uint32 length = SWAPL(subtableHeader->length); + subtableHeader.addOffset(length, success); // Don't addOffset for the last entry. + } + le_uint32 coverage = SWAPL(subtableHeader->coverage); + FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures); + // should check coverage more carefully... + if (((coverage & scfIgnoreVt2) || !(coverage & scfVertical2)) && (subtableFeatures & flag) != 0) { + subtableHeader->process(subtableHeader, glyphStorage, success); + } + } + } +} + +void MorphSubtableHeader2::process(const LEReferenceTo<MorphSubtableHeader2> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const +{ + SubtableProcessor2 *processor = NULL; + + switch (SWAPL(coverage) & scfTypeMask2) + { + case mstIndicRearrangement: + processor = new IndicRearrangementProcessor2(base, success); + break; + + case mstContextualGlyphSubstitution: + processor = new ContextualGlyphSubstitutionProcessor2(base, success); + break; + + case mstLigatureSubstitution: + processor = new LigatureSubstitutionProcessor2(base, success); + break; + + case mstReservedUnused: + break; + + case mstNonContextualGlyphSubstitution: + processor = NonContextualGlyphSubstitutionProcessor2::createInstance(base, success); + break; + + + case mstContextualGlyphInsertion: + processor = new ContextualGlyphInsertionProcessor2(base, success); + break; + + default: + return; + break; /*NOTREACHED*/ + } + + if (processor != NULL) { + processor->process(glyphStorage, success); + delete processor; + } else { + if(LE_SUCCESS(success)) { + success = LE_MEMORY_ALLOCATION_ERROR; // because ptr is null and we didn't break out. + } + } +} + +U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MultipleSubstSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -39,7 +39,7 @@ U_NAMESPACE_BEGIN -le_uint32 MultipleSubstitutionSubtable::process(GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter) const +le_uint32 MultipleSubstitutionSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter) const { if (LE_FAILURE(success)) { return 0; @@ -58,7 +58,7 @@ return 0; } - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); le_uint16 seqCount = SWAPW(sequenceCount); if (coverageIndex >= 0 && coverageIndex < seqCount) {
--- a/src/share/native/sun/font/layout/MultipleSubstSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/MultipleSubstSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -50,14 +50,16 @@ le_uint16 glyphCount; TTGlyphID substituteArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(SequenceTable, substituteArray) struct MultipleSubstitutionSubtable : GlyphSubstitutionSubtable { le_uint16 sequenceCount; Offset sequenceTableOffsetArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter = NULL) const; }; +LE_VAR_ARRAY(MultipleSubstitutionSubtable, sequenceTableOffsetArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/NonContextualGlyphSubst.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/NonContextualGlyphSubst.h Wed Apr 17 02:53:02 2013 -0700 @@ -26,7 +26,7 @@ /* * * - * (C) Copyright IBM Corp. 1998-2003 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -50,6 +50,11 @@ LookupTable table; }; +struct NonContextualGlyphSubstitutionHeader2 : MorphSubtableHeader2 +{ + LookupTable table; +}; + U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -47,8 +47,8 @@ { } -NonContextualGlyphSubstitutionProcessor::NonContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader) - : SubtableProcessor(morphSubtableHeader) +NonContextualGlyphSubstitutionProcessor::NonContextualGlyphSubstitutionProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : SubtableProcessor(morphSubtableHeader, success) { } @@ -56,26 +56,27 @@ { } -SubtableProcessor *NonContextualGlyphSubstitutionProcessor::createInstance(const MorphSubtableHeader *morphSubtableHeader) +SubtableProcessor *NonContextualGlyphSubstitutionProcessor::createInstance(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; + LEReferenceTo<NonContextualGlyphSubstitutionHeader> header(morphSubtableHeader, success); - switch (SWAPW(header->table.format)) - { + if(LE_FAILURE(success)) return NULL; + + switch (SWAPW(header->table.format)) { case ltfSimpleArray: - return new SimpleArrayProcessor(morphSubtableHeader); + return new SimpleArrayProcessor(morphSubtableHeader, success); case ltfSegmentSingle: - return new SegmentSingleProcessor(morphSubtableHeader); + return new SegmentSingleProcessor(morphSubtableHeader, success); case ltfSegmentArray: - return new SegmentArrayProcessor(morphSubtableHeader); + return new SegmentArrayProcessor(morphSubtableHeader, success); case ltfSingleTable: - return new SingleTableProcessor(morphSubtableHeader); + return new SingleTableProcessor(morphSubtableHeader, success); case ltfTrimmedArray: - return new TrimmedArrayProcessor(morphSubtableHeader); + return new TrimmedArrayProcessor(morphSubtableHeader, success); default: return NULL;
--- a/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/NonContextualGlyphSubstProc.h Wed Apr 17 02:53:02 2013 -0700 @@ -49,13 +49,13 @@ class NonContextualGlyphSubstitutionProcessor : public SubtableProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage) = 0; + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success) = 0; - static SubtableProcessor *createInstance(const MorphSubtableHeader *morphSubtableHeader); + static SubtableProcessor *createInstance(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); protected: NonContextualGlyphSubstitutionProcessor(); - NonContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader); + NonContextualGlyphSubstitutionProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &status); virtual ~NonContextualGlyphSubstitutionProcessor();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,88 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SimpleArrayProcessor2.h" +#include "SegmentSingleProcessor2.h" +#include "SegmentArrayProcessor2.h" +#include "SingleTableProcessor2.h" +#include "TrimmedArrayProcessor2.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcessor2() +{ +} + +NonContextualGlyphSubstitutionProcessor2::NonContextualGlyphSubstitutionProcessor2( + const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : SubtableProcessor2(morphSubtableHeader, success) +{ +} + +NonContextualGlyphSubstitutionProcessor2::~NonContextualGlyphSubstitutionProcessor2() +{ +} + +SubtableProcessor2 *NonContextualGlyphSubstitutionProcessor2::createInstance( + const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) +{ + const LEReferenceTo<NonContextualGlyphSubstitutionHeader2> header(morphSubtableHeader, success); + if(LE_FAILURE(success)) return NULL; + + switch (SWAPW(header->table.format)) + { + case ltfSimpleArray: + return new SimpleArrayProcessor2(morphSubtableHeader, success); + + case ltfSegmentSingle: + return new SegmentSingleProcessor2(morphSubtableHeader, success); + + case ltfSegmentArray: + return new SegmentArrayProcessor2(morphSubtableHeader, success); + + case ltfSingleTable: + return new SingleTableProcessor2(morphSubtableHeader, success); + + case ltfTrimmedArray: + return new TrimmedArrayProcessor2(morphSubtableHeader, success); + + default: + return NULL; + } +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,68 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __NONCONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H +#define __NONCONTEXTUALGLYPHSUBSTITUTIONPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class NonContextualGlyphSubstitutionProcessor2 : public SubtableProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success) = 0; + + static SubtableProcessor2 *createInstance(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + +protected: + NonContextualGlyphSubstitutionProcessor2(); + NonContextualGlyphSubstitutionProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + + virtual ~NonContextualGlyphSubstitutionProcessor2(); + +private: + NonContextualGlyphSubstitutionProcessor2(const NonContextualGlyphSubstitutionProcessor2 &other); // forbid copying of this class + NonContextualGlyphSubstitutionProcessor2 &operator=(const NonContextualGlyphSubstitutionProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -26,7 +26,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -64,11 +64,27 @@ #define loclFeatureTag LE_LOCL_FEATURE_TAG #define caltFeatureTag LE_CALT_FEATURE_TAG -// 'dlig' not used at the moment -#define dligFeatureTag 0x646C6967 +#define dligFeatureTag LE_DLIG_FEATURE_TAG +#define rligFeatureTag LE_RLIG_FEATURE_TAG +#define paltFeatureTag LE_PALT_FEATURE_TAG -// 'palt' -#define paltFeatureTag 0x70616C74 +#define hligFeatureTag LE_HLIG_FEATURE_TAG +#define smcpFeatureTag LE_SMCP_FEATURE_TAG +#define fracFeatureTag LE_FRAC_FEATURE_TAG +#define afrcFeatureTag LE_AFRC_FEATURE_TAG +#define zeroFeatureTag LE_ZERO_FEATURE_TAG +#define swshFeatureTag LE_SWSH_FEATURE_TAG +#define cswhFeatureTag LE_CSWH_FEATURE_TAG +#define saltFeatureTag LE_SALT_FEATURE_TAG +#define naltFeatureTag LE_NALT_FEATURE_TAG +#define rubyFeatureTag LE_RUBY_FEATURE_TAG +#define ss01FeatureTag LE_SS01_FEATURE_TAG +#define ss02FeatureTag LE_SS02_FEATURE_TAG +#define ss03FeatureTag LE_SS03_FEATURE_TAG +#define ss04FeatureTag LE_SS04_FEATURE_TAG +#define ss05FeatureTag LE_SS05_FEATURE_TAG +#define ss06FeatureTag LE_SS06_FEATURE_TAG +#define ss07FeatureTag LE_SS07_FEATURE_TAG #define ccmpFeatureMask 0x80000000UL #define ligaFeatureMask 0x40000000UL @@ -80,60 +96,146 @@ #define loclFeatureMask 0x01000000UL #define caltFeatureMask 0x00800000UL +#define dligFeatureMask 0x00400000UL +#define rligFeatureMask 0x00200000UL +#define hligFeatureMask 0x00100000UL +#define smcpFeatureMask 0x00080000UL +#define fracFeatureMask 0x00040000UL +#define afrcFeatureMask 0x00020000UL +#define zeroFeatureMask 0x00010000UL +#define swshFeatureMask 0x00008000UL +#define cswhFeatureMask 0x00004000UL +#define saltFeatureMask 0x00002000UL +#define naltFeatureMask 0x00001000UL +#define rubyFeatureMask 0x00000800UL +#define ss01FeatureMask 0x00000400UL +#define ss02FeatureMask 0x00000200UL +#define ss03FeatureMask 0x00000100UL +#define ss04FeatureMask 0x00000080UL +#define ss05FeatureMask 0x00000040UL +#define ss06FeatureMask 0x00000020UL +#define ss07FeatureMask 0x00000010UL + #define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask | caltFeatureMask) -#define ligaFeatures (ligaFeatureMask | cligFeatureMask | minimalFeatures) -#define kernFeatures (kernFeatureMask | paltFeatureMask | minimalFeatures) -#define kernAndLigaFeatures (ligaFeatures | kernFeatures) static const FeatureMap featureMap[] = { {ccmpFeatureTag, ccmpFeatureMask}, {ligaFeatureTag, ligaFeatureMask}, {cligFeatureTag, cligFeatureMask}, - {kernFeatureTag, kernFeatureMask}, + {kernFeatureTag, kernFeatureMask}, {paltFeatureTag, paltFeatureMask}, {markFeatureTag, markFeatureMask}, {mkmkFeatureTag, mkmkFeatureMask}, {loclFeatureTag, loclFeatureMask}, - {caltFeatureTag, caltFeatureMask} + {caltFeatureTag, caltFeatureMask}, + {hligFeatureTag, hligFeatureMask}, + {smcpFeatureTag, smcpFeatureMask}, + {fracFeatureTag, fracFeatureMask}, + {afrcFeatureTag, afrcFeatureMask}, + {zeroFeatureTag, zeroFeatureMask}, + {swshFeatureTag, swshFeatureMask}, + {cswhFeatureTag, cswhFeatureMask}, + {saltFeatureTag, saltFeatureMask}, + {naltFeatureTag, naltFeatureMask}, + {rubyFeatureTag, rubyFeatureMask}, + {ss01FeatureTag, ss01FeatureMask}, + {ss02FeatureTag, ss02FeatureMask}, + {ss03FeatureTag, ss03FeatureMask}, + {ss04FeatureTag, ss04FeatureMask}, + {ss05FeatureTag, ss05FeatureMask}, + {ss06FeatureTag, ss06FeatureMask}, + {ss07FeatureTag, ss07FeatureMask} }; static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap); OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success) : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureMask(minimalFeatures), fFeatureMap(featureMap), fFeatureMapCount(featureMapCount), fFeatureOrder(FALSE), - fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) + fGSUBTable(gsubTable), + fGDEFTable(fontInstance, LE_GDEF_TABLE_TAG, success), + fGPOSTable(fontInstance, LE_GPOS_TABLE_TAG, success), fSubstitutionFilter(NULL) { - static const le_uint32 gdefTableTag = LE_GDEF_TABLE_TAG; - static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG; - const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag); - - // todo: switch to more flags and bitfield rather than list of feature tags? - switch (typoFlags & ~0x80000000L) { - case 0: break; // default - case 1: fFeatureMask = kernFeatures; break; - case 2: fFeatureMask = ligaFeatures; break; - case 3: fFeatureMask = kernAndLigaFeatures; break; - default: break; - } - - if (typoFlags & 0x80000000L) { - fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); - } + applyTypoFlags(); setScriptAndLanguageTags(); - fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag); - // JK patch, 2008-05-30 - see Sinhala bug report and LKLUG font // if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { - if (gposTable != NULL && gposTable->coversScript(fScriptTag)) { - fGPOSTable = gposTable; + if (!fGPOSTable.isEmpty()&& !fGPOSTable->coversScript(fGPOSTable, fScriptTag, success)) { + fGPOSTable.clear(); // already loaded } } +void OpenTypeLayoutEngine::applyTypoFlags() { + const le_int32& typoFlags = fTypoFlags; + const LEFontInstance *fontInstance = fFontInstance; + + switch (typoFlags & (LE_SS01_FEATURE_FLAG + | LE_SS02_FEATURE_FLAG + | LE_SS03_FEATURE_FLAG + | LE_SS04_FEATURE_FLAG + | LE_SS05_FEATURE_FLAG + | LE_SS06_FEATURE_FLAG + | LE_SS07_FEATURE_FLAG)) { + case LE_SS01_FEATURE_FLAG: + fFeatureMask |= ss01FeatureMask; + break; + case LE_SS02_FEATURE_FLAG: + fFeatureMask |= ss02FeatureMask; + break; + case LE_SS03_FEATURE_FLAG: + fFeatureMask |= ss03FeatureMask; + break; + case LE_SS04_FEATURE_FLAG: + fFeatureMask |= ss04FeatureMask; + break; + case LE_SS05_FEATURE_FLAG: + fFeatureMask |= ss05FeatureMask; + break; + case LE_SS06_FEATURE_FLAG: + fFeatureMask |= ss06FeatureMask; + break; + case LE_SS07_FEATURE_FLAG: + fFeatureMask |= ss07FeatureMask; + break; + } + + if (typoFlags & LE_Kerning_FEATURE_FLAG) { + fFeatureMask |= (kernFeatureMask | paltFeatureMask); + // Convenience. + } + if (typoFlags & LE_Ligatures_FEATURE_FLAG) { + fFeatureMask |= (ligaFeatureMask | cligFeatureMask); + // Convenience TODO: should add: .. dligFeatureMask | rligFeatureMask ? + } + if (typoFlags & LE_CLIG_FEATURE_FLAG) fFeatureMask |= cligFeatureMask; + if (typoFlags & LE_DLIG_FEATURE_FLAG) fFeatureMask |= dligFeatureMask; + if (typoFlags & LE_HLIG_FEATURE_FLAG) fFeatureMask |= hligFeatureMask; + if (typoFlags & LE_LIGA_FEATURE_FLAG) fFeatureMask |= ligaFeatureMask; + if (typoFlags & LE_RLIG_FEATURE_FLAG) fFeatureMask |= rligFeatureMask; + if (typoFlags & LE_SMCP_FEATURE_FLAG) fFeatureMask |= smcpFeatureMask; + if (typoFlags & LE_FRAC_FEATURE_FLAG) fFeatureMask |= fracFeatureMask; + if (typoFlags & LE_AFRC_FEATURE_FLAG) fFeatureMask |= afrcFeatureMask; + if (typoFlags & LE_ZERO_FEATURE_FLAG) fFeatureMask |= zeroFeatureMask; + if (typoFlags & LE_SWSH_FEATURE_FLAG) fFeatureMask |= swshFeatureMask; + if (typoFlags & LE_CSWH_FEATURE_FLAG) fFeatureMask |= cswhFeatureMask; + if (typoFlags & LE_SALT_FEATURE_FLAG) fFeatureMask |= saltFeatureMask; + if (typoFlags & LE_RUBY_FEATURE_FLAG) fFeatureMask |= rubyFeatureMask; + if (typoFlags & LE_NALT_FEATURE_FLAG) { + // Mutually exclusive with ALL other features. http://www.microsoft.com/typography/otspec/features_ko.htm + fFeatureMask = naltFeatureMask; + } + + if (typoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { + // This isn't a font feature, but requests a Char Substitution Filter + fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); + } + +} + void OpenTypeLayoutEngine::reset() { // NOTE: if we're called from @@ -146,15 +248,17 @@ OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureOrder(FALSE), - fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) + fGSUBTable(), fGDEFTable(), fGPOSTable(), fSubstitutionFilter(NULL) { - setScriptAndLanguageTags(); + applyTypoFlags(); + setScriptAndLanguageTags(); } OpenTypeLayoutEngine::~OpenTypeLayoutEngine() { - if (fTypoFlags & 0x80000000L) { + if (fTypoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { delete fSubstitutionFilter; + fSubstitutionFilter = NULL; } reset(); @@ -267,13 +371,13 @@ return 0; } - if (fGSUBTable != NULL) { - if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { - count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, + if (fGSUBTable.isValid()) { + if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fGSUBTable, fScriptTagV2, fLangSysTag, success)) { + count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureMap, fFeatureMapCount, fFeatureOrder, success); } else { - count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, + count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureMap, fFeatureMapCount, fFeatureOrder, success); } } @@ -294,13 +398,13 @@ return 0; } - if (fGSUBTable != NULL) { - if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { - count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, + if (fGSUBTable.isValid()) { + if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fGSUBTable,fScriptTagV2,fLangSysTag,success)) { + count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureMap, fFeatureMapCount, fFeatureOrder, success); } else { - count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, + count = fGSUBTable->process(fGSUBTable, glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureMap, fFeatureMapCount, fFeatureOrder, success); } } @@ -325,7 +429,7 @@ { LEUnicode *outChars = NULL; LEGlyphStorage fakeGlyphStorage; - le_int32 outCharCount, outGlyphCount, fakeGlyphCount; + le_int32 outCharCount, outGlyphCount; if (LE_FAILURE(success)) { return 0; @@ -343,11 +447,13 @@ } if (outChars != NULL) { - fakeGlyphCount = glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success); + // le_int32 fakeGlyphCount = + glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success); LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount); } else { - fakeGlyphCount = glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success); + // le_int32 fakeGlyphCount = + glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success); //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount); } @@ -378,7 +484,7 @@ return; } - if (fGPOSTable != NULL) { + if (!fGPOSTable.isEmpty()) { GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount); le_int32 i; @@ -401,19 +507,20 @@ } #endif - if (fGPOSTable != NULL) { - if (fScriptTagV2 != nullScriptTag && fGPOSTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { - fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, fGDEFTable, success, fFontInstance, - fFeatureMap, fFeatureMapCount, fFeatureOrder); + if (!fGPOSTable.isEmpty()) { + if (fScriptTagV2 != nullScriptTag && + fGPOSTable->coversScriptAndLanguage(fGPOSTable, fScriptTagV2,fLangSysTag,success)) { + fGPOSTable->process(fGPOSTable, glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, + fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); } else { - fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance, - fFeatureMap, fFeatureMapCount, fFeatureOrder); + fGPOSTable->process(fGPOSTable, glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, + fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); } - } else if ( fTypoFlags & 0x1 ) { - static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; - KernTable kt(fFontInstance, getFontTable(kernTableTag)); - kt.process(glyphStorage); + } else if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ + LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); + KernTable kt(kernTable, success); + kt.process(glyphStorage, success); } float xAdjust = 0, yAdjust = 0;
--- a/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/OpenTypeLayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -24,7 +24,7 @@ */ /* - * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -35,6 +35,7 @@ #include "LEGlyphFilter.h" #include "LEFontInstance.h" #include "LayoutEngine.h" +#include "LETableReference.h" #include "GlyphSubstitutionTables.h" #include "GlyphDefinitionTables.h" @@ -88,7 +89,7 @@ * @internal */ OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known @@ -184,6 +185,11 @@ */ static const LETag scriptTags[]; + /** + * apply the typoflags. Only called by the c'tors. + */ + void applyTypoFlags(); + protected: /** * A set of "default" features. The default characterProcessing method @@ -223,21 +229,21 @@ * * @internal */ - const GlyphSubstitutionTableHeader *fGSUBTable; + LEReferenceTo<GlyphSubstitutionTableHeader> fGSUBTable; /** * The address of the GDEF table. * * @internal */ - const GlyphDefinitionTableHeader *fGDEFTable; + LEReferenceTo<GlyphDefinitionTableHeader> fGDEFTable; /** * The address of the GPOS table. * * @internal */ - const GlyphPositioningTableHeader *fGPOSTable; + LEReferenceTo<GlyphPositioningTableHeader> fGPOSTable; /** * An optional filter used to inhibit substitutions
--- a/src/share/native/sun/font/layout/OpenTypeTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/OpenTypeTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -38,6 +38,7 @@ */ #include "LETypes.h" +#include "LETableReference.h" U_NAMESPACE_BEGIN @@ -50,7 +51,7 @@ #define LE_GLYPH_GROUP_MASK 0x00000001UL typedef le_uint32 FeatureMask; -#define SWAPT(atag) ((LETag) ((atag[0] << 24) + (atag[1] << 16) + (atag[2] << 8) + atag[3])) +#define SWAPT(atag) ((LETag) (((atag[0]) << 24) + ((atag[1]) << 16) + ((atag[2]) << 8) + (atag[3]))) struct TagAndOffsetRecord {
--- a/src/share/native/sun/font/layout/OpenTypeUtilities.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/OpenTypeUtilities.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -76,58 +76,74 @@ return bit; } -Offset OpenTypeUtilities::getTagOffset(LETag tag, const TagAndOffsetRecord *records, le_int32 recordCount) + +Offset OpenTypeUtilities::getTagOffset(LETag tag, const LEReferenceToArrayOf<TagAndOffsetRecord> &records, LEErrorCode &success) { - le_uint8 bit = highBit(recordCount); - le_int32 power = 1 << bit; - le_int32 extra = recordCount - power; - le_int32 probe = power; - le_int32 index = 0; + if(LE_FAILURE(success)) return 0; - if (SWAPT(records[extra].tag) <= tag) { - index = extra; + le_uint32 recordCount = records.getCount(); + le_uint8 bit = highBit(recordCount); + le_int32 power = 1 << bit; + le_int32 extra = recordCount - power; + le_int32 probe = power; + le_int32 index = 0; + + { + const ATag &aTag = records.getAlias(extra,success)->tag; + if (SWAPT(aTag) <= tag) { + index = extra; } + } - while (probe > (1 << 0)) { - probe >>= 1; + while (probe > (1 << 0) && LE_SUCCESS(success)) { + probe >>= 1; - if (SWAPT(records[index + probe].tag) <= tag) { - index += probe; - } + { + const ATag &aTag = records.getAlias(index+probe,success)->tag; + if (SWAPT(aTag) <= tag) { + index += probe; + } } + } - if (SWAPT(records[index].tag) == tag) { - return SWAPW(records[index].offset); + { + const ATag &aTag = records.getAlias(index,success)->tag; + if (SWAPT(aTag) == tag) { + return SWAPW(records.getAlias(index,success)->offset); } + } - return 0; + return 0; } -le_int32 OpenTypeUtilities::getGlyphRangeIndex(TTGlyphID glyphID, const GlyphRangeRecord *records, le_int32 recordCount) +le_int32 OpenTypeUtilities::getGlyphRangeIndex(TTGlyphID glyphID, const LEReferenceToArrayOf<GlyphRangeRecord> &records, LEErrorCode &success) { + if(LE_FAILURE(success)) return -1; + + le_uint32 recordCount = records.getCount(); le_uint8 bit = highBit(recordCount); le_int32 power = 1 << bit; le_int32 extra = recordCount - power; le_int32 probe = power; le_int32 range = 0; - if (recordCount == 0) { - return -1; - } + if (recordCount == 0) { + return -1; + } - if (SWAPW(records[extra].firstGlyph) <= glyphID) { + if (SWAPW(records(extra,success).firstGlyph) <= glyphID) { range = extra; } - while (probe > (1 << 0)) { + while (probe > (1 << 0) && LE_SUCCESS(success)) { probe >>= 1; - if (SWAPW(records[range + probe].firstGlyph) <= glyphID) { + if (SWAPW(records(range + probe,success).firstGlyph) <= glyphID) { range += probe; } } - if (SWAPW(records[range].firstGlyph) <= glyphID && SWAPW(records[range].lastGlyph) >= glyphID) { + if (SWAPW(records(range,success).firstGlyph) <= glyphID && SWAPW(records(range,success).lastGlyph) >= glyphID) { return range; } @@ -199,6 +215,38 @@ } } +U_NAMESPACE_END +#if LE_ASSERT_BAD_FONT +#include <stdio.h> + +static const char *letagToStr(LETag tag, char *str) { + str[0]= 0xFF & (tag>>24); + str[1]= 0xFF & (tag>>16); + str[2]= 0xFF & (tag>>8); + str[3]= 0xFF & (tag>>0); + str[4]= 0; + return str; +} + +U_CAPI void U_EXPORT2 _debug_LETableReference(const char *f, int l, const char *msg, const LETableReference *what, const void *ptr, size_t len) { + char tagbuf[5]; -U_NAMESPACE_END + fprintf(stderr, "%s:%d: LETableReference@0x%p: ", f, l, what); + fprintf(stderr, msg, ptr, len); + fprintf(stderr, "\n"); + + for(int depth=0;depth<10&&(what!=NULL);depth++) { + for(int i=0;i<depth;i++) { + fprintf(stderr, " "); // indent + } + if(!what->isValid()) { + fprintf(stderr, "(invalid)"); + } + fprintf(stderr, "@%p: tag (%s) font (0x%p), [0x%p+0x%lx]\n", what, letagToStr(what->getTag(), tagbuf), what->getFont(), + what->getAlias(), what->getLength()); + + what = what->getParent(); + } +} +#endif
--- a/src/share/native/sun/font/layout/OpenTypeUtilities.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/OpenTypeUtilities.h Wed Apr 17 02:53:02 2013 -0700 @@ -45,8 +45,17 @@ class OpenTypeUtilities /* not : public UObject because all methods are static */ { public: static le_int8 highBit(le_int32 value); - static Offset getTagOffset(LETag tag, const TagAndOffsetRecord *records, le_int32 recordCount); - static le_int32 getGlyphRangeIndex(TTGlyphID glyphID, const GlyphRangeRecord *records, le_int32 recordCount); + static Offset getTagOffset(LETag tag, const LEReferenceToArrayOf<TagAndOffsetRecord> &records, LEErrorCode &success); + /** + * @deprecated TODO remove + */ + static le_int32 getGlyphRangeIndex(TTGlyphID glyphID, const GlyphRangeRecord *records, le_int32 recordCount) { + LEErrorCode success = LE_NO_ERROR; + LETableReference recordRef0((const le_uint8*)records); + LEReferenceToArrayOf<GlyphRangeRecord> recordRef(recordRef0, success, (size_t)0, recordCount); + return getGlyphRangeIndex(glyphID, recordRef, success); + } + static le_int32 getGlyphRangeIndex(TTGlyphID glyphID, const LEReferenceToArrayOf<GlyphRangeRecord> &records, LEErrorCode &success); static le_int32 search(le_uint16 value, const le_uint16 array[], le_int32 count); static le_int32 search(le_uint32 value, const le_uint32 array[], le_int32 count); static void sort(le_uint16 *array, le_int32 count);
--- a/src/share/native/sun/font/layout/PairPositioningSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/PairPositioningSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -41,7 +41,7 @@ U_NAMESPACE_BEGIN -le_uint32 PairPositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 PairPositioningSubtable::process(const LEReferenceTo<PairPositioningSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { switch(SWAPW(subtableFormat)) { @@ -50,27 +50,32 @@ case 1: { - const PairPositioningFormat1Subtable *subtable = (const PairPositioningFormat1Subtable *) this; + const LEReferenceTo<PairPositioningFormat1Subtable> subtable(base, success, (const PairPositioningFormat1Subtable *) this); - return subtable->process(glyphIterator, fontInstance); + if(LE_SUCCESS(success)) + return subtable->process(subtable, glyphIterator, fontInstance, success); + else + return 0; } case 2: { - const PairPositioningFormat2Subtable *subtable = (const PairPositioningFormat2Subtable *) this; + const LEReferenceTo<PairPositioningFormat2Subtable> subtable(base, success, (const PairPositioningFormat2Subtable *) this); - return subtable->process(glyphIterator, fontInstance); + if(LE_SUCCESS(success)) + return subtable->process(subtable, glyphIterator, fontInstance, success); + else + return 0; } - default: - return 0; + return 0; } } -le_uint32 PairPositioningFormat1Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 PairPositioningFormat1Subtable::process(const LEReferenceTo<PairPositioningFormat1Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(firstGlyph); + le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success); GlyphIterator tempIterator(*glyphIterator); if (coverageIndex >= 0 && glyphIterator->next()) { @@ -110,10 +115,10 @@ return 0; } -le_uint32 PairPositioningFormat2Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 PairPositioningFormat2Subtable::process(const LEReferenceTo<PairPositioningFormat2Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(firstGlyph); + le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success); GlyphIterator tempIterator(*glyphIterator); if (coverageIndex >= 0 && glyphIterator->next()) {
--- a/src/share/native/sun/font/layout/PairPositioningSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/PairPositioningSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -59,13 +59,14 @@ le_uint16 pairValueCount; PairValueRecord pairValueRecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(PairSetTable, pairValueRecordArray) struct PairPositioningSubtable : GlyphPositioningSubtable { ValueFormat valueFormat1; ValueFormat valueFormat2; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo<PairPositioningSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; struct PairPositioningFormat1Subtable : PairPositioningSubtable @@ -73,12 +74,13 @@ le_uint16 pairSetCount; Offset pairSetTableOffsetArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo<PairPositioningFormat1Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; private: const PairValueRecord *findPairValueRecord(TTGlyphID glyphID, const PairValueRecord *records, le_uint16 recordCount, le_uint16 recordSize) const; }; +LE_VAR_ARRAY(PairPositioningFormat1Subtable, pairSetTableOffsetArray) // NOTE: ValueRecord has a variable size struct Class2Record @@ -91,6 +93,7 @@ { Class2Record class2RecordArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(Class1Record, class2RecordArray) struct PairPositioningFormat2Subtable : PairPositioningSubtable { @@ -100,8 +103,9 @@ le_uint16 class2Count; Class1Record class1RecordArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo<PairPositioningFormat2Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; +LE_VAR_ARRAY(PairPositioningFormat2Subtable, class1RecordArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/ScriptAndLanguage.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ScriptAndLanguage.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -38,29 +38,33 @@ U_NAMESPACE_BEGIN -const LangSysTable *ScriptTable::findLanguage(LETag languageTag, le_bool exactMatch) const +LEReferenceTo<LangSysTable> ScriptTable::findLanguage(const LETableReference& base, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const { le_uint16 count = SWAPW(langSysCount); Offset langSysTableOffset = exactMatch? 0 : SWAPW(defaultLangSysTableOffset); if (count > 0) { - Offset foundOffset = - OpenTypeUtilities::getTagOffset(languageTag, langSysRecordArray, count); + LEReferenceToArrayOf<TagAndOffsetRecord> langSysRecords(base, success, langSysRecordArray, count); + Offset foundOffset = + OpenTypeUtilities::getTagOffset(languageTag, langSysRecords, success); - if (foundOffset != 0) { - langSysTableOffset = foundOffset; - } + if (foundOffset != 0 && LE_SUCCESS(success)) { + langSysTableOffset = foundOffset; + } } if (langSysTableOffset != 0) { - return (const LangSysTable *) ((char *)this + langSysTableOffset); + return LEReferenceTo<LangSysTable>(base, success, langSysTableOffset); } - return NULL; + return LEReferenceTo<LangSysTable>(); } -const ScriptTable *ScriptListTable::findScript(LETag scriptTag) const +LEReferenceTo<ScriptTable> ScriptListTable::findScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const { + if (LE_FAILURE(success) ) { + return LEReferenceTo<ScriptTable>(); // get out + } /* * There are some fonts that have a large, bogus value for scriptCount. To try * and protect against this, we use the offset in the first scriptRecord, @@ -74,38 +78,53 @@ * to be unsorted. */ le_uint16 count = SWAPW(scriptCount); + + if (count == 0) { + return LEReferenceTo<ScriptTable>(); // no items, no search + } + + // attempt to construct a ref with at least one element + LEReferenceToArrayOf<ScriptRecord> oneElementTable(base, success, &scriptRecordArray[0], 1); + + if( LE_FAILURE(success) ) { + return LEReferenceTo<ScriptTable>(); // couldn't even read the first record - bad font. + } + le_uint16 limit = ((SWAPW(scriptRecordArray[0].offset) - sizeof(ScriptListTable)) / sizeof(scriptRecordArray)) + ANY_NUMBER; Offset scriptTableOffset = 0; + if (count > limit) { // the scriptCount value is bogus; do a linear search // because limit may still be too large. - for(le_int32 s = 0; s < limit; s += 1) { - if (SWAPT(scriptRecordArray[s].tag) == scriptTag) { - scriptTableOffset = SWAPW(scriptRecordArray[s].offset); - break; - } + LEReferenceToArrayOf<ScriptRecord> scriptRecordArrayRef(base, success, &scriptRecordArray[0], limit); + for(le_int32 s = 0; (s < limit)&&LE_SUCCESS(success); s += 1) { + if (SWAPT(scriptRecordArrayRef(s,success).tag) == scriptTag) { + scriptTableOffset = SWAPW(scriptRecordArrayRef(s,success).offset); + break; + } } } else { - scriptTableOffset = OpenTypeUtilities::getTagOffset(scriptTag, scriptRecordArray, count); + LEReferenceToArrayOf<ScriptRecord> scriptRecordArrayRef(base, success, &scriptRecordArray[0], count); + scriptTableOffset = OpenTypeUtilities::getTagOffset(scriptTag, scriptRecordArrayRef, success); // TODO } if (scriptTableOffset != 0) { - return (const ScriptTable *) ((char *)this + scriptTableOffset); + return LEReferenceTo<ScriptTable>(base, success, scriptTableOffset); } - return NULL; + return LEReferenceTo<ScriptTable>(); } -const LangSysTable *ScriptListTable::findLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch) const +LEReferenceTo<LangSysTable> ScriptListTable::findLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const { - const ScriptTable *scriptTable = findScript(scriptTag); + const LEReferenceTo<ScriptTable> scriptTable = findScript(base, scriptTag, success); - if (scriptTable == 0) { - return NULL; - } + if (scriptTable.isEmpty()) { + return LEReferenceTo<LangSysTable>(); + } - return scriptTable->findLanguage(languageTag, exactMatch); + return scriptTable->findLanguage(scriptTable, languageTag, success, exactMatch).reparent(base); } U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/ScriptAndLanguage.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ScriptAndLanguage.h Wed Apr 17 02:53:02 2013 -0700 @@ -51,6 +51,7 @@ le_uint16 featureCount; le_uint16 featureIndexArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(LangSysTable, featureIndexArray) struct ScriptTable { @@ -58,8 +59,9 @@ le_uint16 langSysCount; LangSysRecord langSysRecordArray[ANY_NUMBER]; - const LangSysTable *findLanguage(LETag languageTag, le_bool exactMatch = FALSE) const; + LEReferenceTo<LangSysTable> findLanguage(const LETableReference &base, LETag languageTag, LEErrorCode &success, le_bool exactMatch = FALSE) const; }; +LE_VAR_ARRAY(ScriptTable, langSysRecordArray) typedef TagAndOffsetRecord ScriptRecord; @@ -68,9 +70,10 @@ le_uint16 scriptCount; ScriptRecord scriptRecordArray[ANY_NUMBER]; - const ScriptTable *findScript(LETag scriptTag) const; - const LangSysTable *findLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch = FALSE) const; + LEReferenceTo<ScriptTable> findScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const; + LEReferenceTo<LangSysTable> findLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch = FALSE) const; }; +LE_VAR_ARRAY(ScriptListTable, scriptRecordArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/ScriptAndLanguageTags.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ScriptAndLanguageTags.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved. + * (C) Copyright IBM Corp. 1998-2013. All Rights Reserved. * * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS * YOU REALLY KNOW WHAT YOU'RE DOING. @@ -186,7 +186,18 @@ nbatScriptTag, /* 'nbat' (NBAT) */ palmScriptTag, /* 'palm' (PALM) */ sindScriptTag, /* 'sind' (SIND) */ - waraScriptTag /* 'wara' (WARA) */ + waraScriptTag, /* 'wara' (WARA) */ + afakScriptTag, /* 'afak' (AFAK) */ + jurcScriptTag, /* 'jurc' (JURC) */ + mrooScriptTag, /* 'mroo' (MROO) */ + nshuScriptTag, /* 'nshu' (NSHU) */ + shrdScriptTag, /* 'shrd' (SHARADA) */ + soraScriptTag, /* 'sora' (SORA_SOMPENG) */ + takrScriptTag, /* 'takr' (TAKRI) */ + tangScriptTag, /* 'tang' (TANG) */ + woleScriptTag, /* 'wole' (WOLE) */ + khojScriptTag, /* 'khoj' (KHOJ) */ + tirhScriptTag /* 'tirh' (TIRH) */ }; const LETag OpenTypeLayoutEngine::languageTags[] = {
--- a/src/share/native/sun/font/layout/ScriptAndLanguageTags.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ScriptAndLanguageTags.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved. + * (C) Copyright IBM Corp. 1998-2013. All Rights Reserved. * * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS * YOU REALLY KNOW WHAT YOU'RE DOING. @@ -201,6 +201,17 @@ const LETag palmScriptTag = 0x70616C6D; /* 'palm' (PALM) */ const LETag sindScriptTag = 0x73696E64; /* 'sind' (SIND) */ const LETag waraScriptTag = 0x77617261; /* 'wara' (WARA) */ +const LETag afakScriptTag = 0x6166616B; /* 'afak' (AFAK) */ +const LETag jurcScriptTag = 0x6A757263; /* 'jurc' (JURC) */ +const LETag mrooScriptTag = 0x6D726F6F; /* 'mroo' (MROO) */ +const LETag nshuScriptTag = 0x6E736875; /* 'nshu' (NSHU) */ +const LETag shrdScriptTag = 0x73687264; /* 'shrd' (SHARADA) */ +const LETag soraScriptTag = 0x736F7261; /* 'sora' (SORA_SOMPENG) */ +const LETag takrScriptTag = 0x74616B72; /* 'takr' (TAKRI) */ +const LETag tangScriptTag = 0x74616E67; /* 'tang' (TANG) */ +const LETag woleScriptTag = 0x776F6C65; /* 'wole' (WOLE) */ +const LETag khojScriptTag = 0x6B686F6A; /* 'khoj' (KHOJ) */ +const LETag tirhScriptTag = 0x74697268; /* 'tirh' (TIRH) */ const LETag nullScriptTag = 0x00000000; /* '' (NULL) */
--- a/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -46,19 +46,18 @@ { } -SegmentArrayProcessor::SegmentArrayProcessor(const MorphSubtableHeader *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader) +SegmentArrayProcessor::SegmentArrayProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; - - segmentArrayLookupTable = (const SegmentArrayLookupTable *) &header->table; + LEReferenceTo<NonContextualGlyphSubstitutionHeader> header(morphSubtableHeader, success); + segmentArrayLookupTable = LEReferenceTo<SegmentArrayLookupTable>(morphSubtableHeader, success, (const SegmentArrayLookupTable*)&header->table); } SegmentArrayProcessor::~SegmentArrayProcessor() { } -void SegmentArrayProcessor::process(LEGlyphStorage &glyphStorage) +void SegmentArrayProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSegment *segments = segmentArrayLookupTable->segments; le_int32 glyphCount = glyphStorage.getGlyphCount(); @@ -66,17 +65,16 @@ for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; - const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segments, thisGlyph); + const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segmentArrayLookupTable, segments, thisGlyph, success); if (lookupSegment != NULL) { TTGlyphID firstGlyph = SWAPW(lookupSegment->firstGlyph); le_int16 offset = SWAPW(lookupSegment->value); if (offset != 0) { - TTGlyphID *glyphArray = (TTGlyphID *) ((char *) subtableHeader + offset); - TTGlyphID newGlyph = SWAPW(glyphArray[LE_GET_GLYPH(thisGlyph) - firstGlyph]); - - glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + LEReferenceToArrayOf<TTGlyphID> glyphArray(subtableHeader, success, offset, LE_UNBOUNDED_ARRAY); + TTGlyphID newGlyph = SWAPW(glyphArray(LE_GET_GLYPH(thisGlyph) - firstGlyph, success)); + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } }
--- a/src/share/native/sun/font/layout/SegmentArrayProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SegmentArrayProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -50,9 +50,9 @@ class SegmentArrayProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SegmentArrayProcessor(const MorphSubtableHeader *morphSubtableHeader); + SegmentArrayProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~SegmentArrayProcessor(); @@ -74,7 +74,7 @@ SegmentArrayProcessor(); protected: - const SegmentArrayLookupTable *segmentArrayLookupTable; + LEReferenceTo<SegmentArrayLookupTable> segmentArrayLookupTable; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,84 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SegmentArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SegmentArrayProcessor2) + +SegmentArrayProcessor2::SegmentArrayProcessor2() +{ +} + +SegmentArrayProcessor2::SegmentArrayProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) +{ + const LEReferenceTo<NonContextualGlyphSubstitutionHeader2> header(morphSubtableHeader, success); + segmentArrayLookupTable = LEReferenceTo<SegmentArrayLookupTable>(morphSubtableHeader, success, &header->table); // don't parent to 'header' as it is on the stack +} + +SegmentArrayProcessor2::~SegmentArrayProcessor2() +{ +} + +void SegmentArrayProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + const LookupSegment *segments = segmentArrayLookupTable->segments; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segmentArrayLookupTable, segments, thisGlyph, success); + + if (lookupSegment != NULL) { + TTGlyphID firstGlyph = SWAPW(lookupSegment->firstGlyph); + le_int16 offset = SWAPW(lookupSegment->value); + + if (offset != 0) { + TTGlyphID *glyphArray = (TTGlyphID *) ((char *) subtableHeader.getAliasTODO() + offset); + TTGlyphID newGlyph = SWAPW(glyphArray[LE_GET_GLYPH(thisGlyph) - firstGlyph]); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } + } +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SegmentArrayProcessor2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,82 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SEGMENTARRAYPROCESSOR_H +#define __SEGMENTARRAYPROCESSOR_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SegmentArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); + + SegmentArrayProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + + virtual ~SegmentArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SegmentArrayProcessor2(); + +protected: + LEReferenceTo<SegmentArrayLookupTable> segmentArrayLookupTable; + +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/SegmentSingleProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SegmentSingleProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -46,29 +46,28 @@ { } -SegmentSingleProcessor::SegmentSingleProcessor(const MorphSubtableHeader *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader) +SegmentSingleProcessor::SegmentSingleProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; - - segmentSingleLookupTable = (const SegmentSingleLookupTable *) &header->table; + LEReferenceTo<NonContextualGlyphSubstitutionHeader> header(morphSubtableHeader, success); + segmentSingleLookupTable = LEReferenceTo<SegmentSingleLookupTable>(morphSubtableHeader, success, (const SegmentSingleLookupTable*)&header->table); } SegmentSingleProcessor::~SegmentSingleProcessor() { } -void SegmentSingleProcessor::process(LEGlyphStorage &glyphStorage) +void SegmentSingleProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSegment *segments = segmentSingleLookupTable->segments; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; - for (glyph = 0; glyph < glyphCount; glyph += 1) { + for (glyph = 0; glyph < glyphCount && LE_SUCCESS(success); glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; - const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segments, thisGlyph); + const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segmentSingleLookupTable, segments, thisGlyph, success); - if (lookupSegment != NULL) { + if (lookupSegment != NULL && LE_SUCCESS(success)) { TTGlyphID newGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
--- a/src/share/native/sun/font/layout/SegmentSingleProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SegmentSingleProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -50,9 +50,9 @@ class SegmentSingleProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SegmentSingleProcessor(const MorphSubtableHeader *morphSubtableHeader); + SegmentSingleProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~SegmentSingleProcessor(); @@ -74,7 +74,7 @@ SegmentSingleProcessor(); protected: - const SegmentSingleLookupTable *segmentSingleLookupTable; + LEReferenceTo<SegmentSingleLookupTable> segmentSingleLookupTable; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SegmentSingleProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SegmentSingleProcessor2) + +SegmentSingleProcessor2::SegmentSingleProcessor2() +{ +} + +SegmentSingleProcessor2::SegmentSingleProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) +{ + const LEReferenceTo<NonContextualGlyphSubstitutionHeader2> header(morphSubtableHeader, success); + + segmentSingleLookupTable = LEReferenceTo<SegmentSingleLookupTable>(morphSubtableHeader, success, &header->table); +} + +SegmentSingleProcessor2::~SegmentSingleProcessor2() +{ +} + +void SegmentSingleProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + const LookupSegment *segments = segmentSingleLookupTable->segments; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segmentSingleLookupTable, segments, thisGlyph, success); + + if (lookupSegment != NULL && LE_SUCCESS(success)) { + TTGlyphID newGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SegmentSingleProcessor2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,82 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SEGMENTSINGLEPROCESSOR_H +#define __SEGMENTSINGLEPROCESSOR_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SegmentSingleProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); + + SegmentSingleProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + + virtual ~SegmentSingleProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SegmentSingleProcessor2(); + +protected: + LEReferenceTo<SegmentSingleLookupTable> segmentSingleLookupTable; + +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/ShapingTypeData.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ShapingTypeData.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -122,4 +122,6 @@ 0x00, 0x05, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x05, 0xFF, 0xF9, 0xFF, 0xFB, 0x00, 0x05 }; +const size_t ArabicShaping::shapingTypeTableLen = sizeof(shapingTypeTable)/sizeof(shapingTypeTable[0]); + U_NAMESPACE_END
--- a/src/share/native/sun/font/layout/SimpleArrayProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SimpleArrayProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -46,29 +46,29 @@ { } -SimpleArrayProcessor::SimpleArrayProcessor(const MorphSubtableHeader *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader) +SimpleArrayProcessor::SimpleArrayProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; - - simpleArrayLookupTable = (const SimpleArrayLookupTable *) &header->table; + LEReferenceTo<NonContextualGlyphSubstitutionHeader> header(morphSubtableHeader, success); + simpleArrayLookupTable = LEReferenceTo<SimpleArrayLookupTable>(morphSubtableHeader, success, (const SimpleArrayLookupTable*)&header->table); } SimpleArrayProcessor::~SimpleArrayProcessor() { } -void SimpleArrayProcessor::process(LEGlyphStorage &glyphStorage) +void SimpleArrayProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; - for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEReferenceToArrayOf<LookupValue> valueArray(simpleArrayLookupTable, success, (const LookupValue*)&simpleArrayLookupTable->valueArray, LE_UNBOUNDED_ARRAY); + + for (glyph = 0; LE_SUCCESS(success) && (glyph < glyphCount); glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) { - TTGlyphID newGlyph = SWAPW(simpleArrayLookupTable->valueArray[LE_GET_GLYPH(thisGlyph)]); - - glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + TTGlyphID newGlyph = SWAPW(valueArray.getObject(LE_GET_GLYPH(thisGlyph),success)); + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } }
--- a/src/share/native/sun/font/layout/SimpleArrayProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SimpleArrayProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -50,9 +50,9 @@ class SimpleArrayProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SimpleArrayProcessor(const MorphSubtableHeader *morphSubtableHeader); + SimpleArrayProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~SimpleArrayProcessor(); @@ -74,7 +74,7 @@ SimpleArrayProcessor(); protected: - const SimpleArrayLookupTable *simpleArrayLookupTable; + LEReferenceTo<SimpleArrayLookupTable> simpleArrayLookupTable; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,78 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SimpleArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleArrayProcessor2) + +SimpleArrayProcessor2::SimpleArrayProcessor2() +{ +} + +SimpleArrayProcessor2::SimpleArrayProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) +{ + const LEReferenceTo<NonContextualGlyphSubstitutionHeader2> header(morphSubtableHeader, success); + + simpleArrayLookupTable = LEReferenceTo<SimpleArrayLookupTable>(morphSubtableHeader, success, &header->table); + valueArray = LEReferenceToArrayOf<LookupValue>(morphSubtableHeader, success, &simpleArrayLookupTable->valueArray[0], LE_UNBOUNDED_ARRAY); +} + +SimpleArrayProcessor2::~SimpleArrayProcessor2() +{ +} + +void SimpleArrayProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + if (LE_FAILURE(success)) return; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) { + TTGlyphID newGlyph = SWAPW(valueArray(LE_GET_GLYPH(thisGlyph),success)); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SimpleArrayProcessor2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,83 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SIMPLEARRAYPROCESSOR2_H +#define __SIMPLEARRAYPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SimpleArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); + + SimpleArrayProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + + virtual ~SimpleArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SimpleArrayProcessor2(); + +protected: + LEReferenceTo<SimpleArrayLookupTable> simpleArrayLookupTable; + LEReferenceToArrayOf<LookupValue> valueArray; + +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SinglePositioningSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -40,7 +40,7 @@ U_NAMESPACE_BEGIN -le_uint32 SinglePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 SinglePositioningSubtable::process(const LEReferenceTo<SinglePositioningSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { switch(SWAPW(subtableFormat)) { @@ -49,16 +49,16 @@ case 1: { - const SinglePositioningFormat1Subtable *subtable = (const SinglePositioningFormat1Subtable *) this; + const LEReferenceTo<SinglePositioningFormat1Subtable> subtable(base, success, (const SinglePositioningFormat1Subtable *) this); - return subtable->process(glyphIterator, fontInstance); + return subtable->process(subtable, glyphIterator, fontInstance, success); } case 2: { - const SinglePositioningFormat2Subtable *subtable = (const SinglePositioningFormat2Subtable *) this; + const LEReferenceTo<SinglePositioningFormat2Subtable> subtable(base, success, (const SinglePositioningFormat2Subtable *) this); - return subtable->process(glyphIterator, fontInstance); + return subtable->process(subtable, glyphIterator, fontInstance, success); } default: @@ -66,10 +66,10 @@ } } -le_uint32 SinglePositioningFormat1Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 SinglePositioningFormat1Subtable::process(const LEReferenceTo<SinglePositioningFormat1Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { valueRecord.adjustPosition(SWAPW(valueFormat), (const char *) this, *glyphIterator, fontInstance); @@ -80,10 +80,10 @@ return 0; } -le_uint32 SinglePositioningFormat2Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const +le_uint32 SinglePositioningFormat2Subtable::process(const LEReferenceTo<SinglePositioningFormat2Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int16 coverageIndex = (le_int16) getGlyphCoverage(glyph); + le_int16 coverageIndex = (le_int16) getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { valueRecordArray[0].adjustPosition(coverageIndex, SWAPW(valueFormat), (const char *) this, *glyphIterator, fontInstance);
--- a/src/share/native/sun/font/layout/SinglePositioningSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SinglePositioningSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -48,7 +48,7 @@ struct SinglePositioningSubtable : GlyphPositioningSubtable { - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo<SinglePositioningSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; struct SinglePositioningFormat1Subtable : SinglePositioningSubtable @@ -56,7 +56,7 @@ ValueFormat valueFormat; ValueRecord valueRecord; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo<SinglePositioningFormat1Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; struct SinglePositioningFormat2Subtable : SinglePositioningSubtable @@ -65,8 +65,9 @@ le_uint16 valueCount; ValueRecord valueRecordArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const; + le_uint32 process(const LEReferenceTo<SinglePositioningFormat2Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const; }; +LE_VAR_ARRAY(SinglePositioningFormat2Subtable, valueRecordArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -39,7 +39,7 @@ U_NAMESPACE_BEGIN -le_uint32 SingleSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 SingleSubstitutionSubtable::process(const LEReferenceTo<SingleSubstitutionSubtable> &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { switch(SWAPW(subtableFormat)) { @@ -48,16 +48,16 @@ case 1: { - const SingleSubstitutionFormat1Subtable *subtable = (const SingleSubstitutionFormat1Subtable *) this; + const LEReferenceTo<SingleSubstitutionFormat1Subtable> subtable(base, success, (const SingleSubstitutionFormat1Subtable *) this); - return subtable->process(glyphIterator, filter); + return subtable->process(subtable, glyphIterator, success, filter); } case 2: { - const SingleSubstitutionFormat2Subtable *subtable = (const SingleSubstitutionFormat2Subtable *) this; + const LEReferenceTo<SingleSubstitutionFormat2Subtable> subtable(base, success, (const SingleSubstitutionFormat2Subtable *) this); - return subtable->process(glyphIterator, filter); + return subtable->process(subtable, glyphIterator, success, filter); } default: @@ -65,10 +65,10 @@ } } -le_uint32 SingleSubstitutionFormat1Subtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 SingleSubstitutionFormat1Subtable::process(const LEReferenceTo<SingleSubstitutionFormat1Subtable> &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { TTGlyphID substitute = ((TTGlyphID) LE_GET_GLYPH(glyph)) + SWAPW(deltaGlyphID); @@ -83,10 +83,10 @@ return 0; } -le_uint32 SingleSubstitutionFormat2Subtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const +le_uint32 SingleSubstitutionFormat2Subtable::process(const LEReferenceTo<SingleSubstitutionFormat2Subtable> &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const { LEGlyphID glyph = glyphIterator->getCurrGlyphID(); - le_int32 coverageIndex = getGlyphCoverage(glyph); + le_int32 coverageIndex = getGlyphCoverage(base, glyph, success); if (coverageIndex >= 0) { TTGlyphID substitute = SWAPW(substituteArray[coverageIndex]);
--- a/src/share/native/sun/font/layout/SingleSubstitutionSubtables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SingleSubstitutionSubtables.h Wed Apr 17 02:53:02 2013 -0700 @@ -47,14 +47,14 @@ struct SingleSubstitutionSubtable : GlyphSubstitutionSubtable { - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LEReferenceTo<SingleSubstitutionSubtable> &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; struct SingleSubstitutionFormat1Subtable : SingleSubstitutionSubtable { le_int16 deltaGlyphID; - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LEReferenceTo<SingleSubstitutionFormat1Subtable> &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; struct SingleSubstitutionFormat2Subtable : SingleSubstitutionSubtable @@ -62,8 +62,9 @@ le_uint16 glyphCount; TTGlyphID substituteArray[ANY_NUMBER]; - le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const; + le_uint32 process(const LEReferenceTo<SingleSubstitutionFormat2Subtable> &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const; }; +LE_VAR_ARRAY(SingleSubstitutionFormat2Subtable, substituteArray) U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/SingleTableProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SingleTableProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -46,26 +46,25 @@ { } -SingleTableProcessor::SingleTableProcessor(const MorphSubtableHeader *moprhSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(moprhSubtableHeader) +SingleTableProcessor::SingleTableProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) moprhSubtableHeader; - - singleTableLookupTable = (const SingleTableLookupTable *) &header->table; + LEReferenceTo<NonContextualGlyphSubstitutionHeader> header(morphSubtableHeader, success); + singleTableLookupTable = LEReferenceTo<SingleTableLookupTable>(morphSubtableHeader, success, (const SingleTableLookupTable*)&header->table); } SingleTableProcessor::~SingleTableProcessor() { } -void SingleTableProcessor::process(LEGlyphStorage &glyphStorage) +void SingleTableProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSingle *entries = singleTableLookupTable->entries; le_int32 glyph; le_int32 glyphCount = glyphStorage.getGlyphCount(); for (glyph = 0; glyph < glyphCount; glyph += 1) { - const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(entries, glyphStorage[glyph]); + const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(singleTableLookupTable, entries, glyphStorage[glyph], success); if (lookupSingle != NULL) { glyphStorage[glyph] = SWAPW(lookupSingle->value);
--- a/src/share/native/sun/font/layout/SingleTableProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SingleTableProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -50,9 +50,9 @@ class SingleTableProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - SingleTableProcessor(const MorphSubtableHeader *morphSubtableHeader); + SingleTableProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~SingleTableProcessor(); @@ -74,7 +74,7 @@ SingleTableProcessor(); protected: - const SingleTableLookupTable *singleTableLookupTable; + LEReferenceTo<SingleTableLookupTable> singleTableLookupTable; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SingleTableProcessor2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,77 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "SingleTableProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SingleTableProcessor2) + +SingleTableProcessor2::SingleTableProcessor2() +{ +} + +SingleTableProcessor2::SingleTableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) +{ + const LEReferenceTo<NonContextualGlyphSubstitutionHeader2> header(morphSubtableHeader, success); + + singleTableLookupTable = LEReferenceTo<SingleTableLookupTable>(morphSubtableHeader, success, &header->table); +} + +SingleTableProcessor2::~SingleTableProcessor2() +{ +} + +void SingleTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + if(LE_FAILURE(success)) return; + const LookupSingle *entries = singleTableLookupTable->entries; + le_int32 glyph; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(singleTableLookupTable, entries, glyphStorage[glyph], success); + + if (lookupSingle != NULL) { + glyphStorage[glyph] = SWAPW(lookupSingle->value); + } + } +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SingleTableProcessor2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,82 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SINGLETABLEPROCESSOR2_H +#define __SINGLETABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SingleTableProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); + + SingleTableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + + virtual ~SingleTableProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + SingleTableProcessor2(); + +protected: + LEReferenceTo<SingleTableLookupTable> singleTableLookupTable; + +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/StateTableProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/StateTableProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -44,17 +44,18 @@ { } -StateTableProcessor::StateTableProcessor(const MorphSubtableHeader *morphSubtableHeader) - : SubtableProcessor(morphSubtableHeader) +StateTableProcessor::StateTableProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : SubtableProcessor(morphSubtableHeader, success), stateTableHeader(morphSubtableHeader, success), + stHeader(stateTableHeader, success, (const StateTableHeader*)&stateTableHeader->stHeader) { - stateTableHeader = (const MorphStateTableHeader *) morphSubtableHeader; - + if(LE_FAILURE(success)) return; stateSize = SWAPW(stateTableHeader->stHeader.stateSize); classTableOffset = SWAPW(stateTableHeader->stHeader.classTableOffset); stateArrayOffset = SWAPW(stateTableHeader->stHeader.stateArrayOffset); entryTableOffset = SWAPW(stateTableHeader->stHeader.entryTableOffset); - classTable = (const ClassTable *) ((char *) &stateTableHeader->stHeader + classTableOffset); + classTable = LEReferenceTo<ClassTable>(stateTableHeader, success, ((char *) &stateTableHeader->stHeader + classTableOffset)); + if(LE_FAILURE(success)) return; firstGlyph = SWAPW(classTable->firstGlyph); lastGlyph = firstGlyph + SWAPW(classTable->nGlyphs); } @@ -63,8 +64,11 @@ { } -void StateTableProcessor::process(LEGlyphStorage &glyphStorage) +void StateTableProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { + if (LE_FAILURE(success)) return; + LE_STATE_PATIENCE_INIT(); + // Start at state 0 // XXX: How do we know when to start at state 1? ByteOffset currentState = stateArrayOffset; @@ -76,6 +80,7 @@ beginStateTable(); while (currGlyph <= glyphCount) { + if(LE_STATE_PATIENCE_DECR()) break; // patience exceeded. ClassCode classCode = classCodeOOB; if (currGlyph == glyphCount) { // XXX: How do we handle EOT vs. EOL? @@ -90,10 +95,11 @@ } } - const EntryTableIndex *stateArray = (const EntryTableIndex *) ((char *) &stateTableHeader->stHeader + currentState); - EntryTableIndex entryTableIndex = stateArray[(le_uint8)classCode]; - + LEReferenceToArrayOf<EntryTableIndex> stateArray(stHeader, success, currentState, LE_UNBOUNDED_ARRAY); + EntryTableIndex entryTableIndex = stateArray.getObject((le_uint8)classCode, success); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); + LE_STATE_PATIENCE_INCR(currGlyph); } endStateTable();
--- a/src/share/native/sun/font/layout/StateTableProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/StateTableProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -49,7 +49,7 @@ class StateTableProcessor : public SubtableProcessor { public: - void process(LEGlyphStorage &glyphStorage); + void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); virtual void beginStateTable() = 0; @@ -58,7 +58,7 @@ virtual void endStateTable() = 0; protected: - StateTableProcessor(const MorphSubtableHeader *morphSubtableHeader); + StateTableProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~StateTableProcessor(); StateTableProcessor(); @@ -68,11 +68,12 @@ ByteOffset stateArrayOffset; ByteOffset entryTableOffset; - const ClassTable *classTable; + LEReferenceTo<ClassTable> classTable; TTGlyphID firstGlyph; TTGlyphID lastGlyph; - const MorphStateTableHeader *stateTableHeader; + LEReferenceTo<MorphStateTableHeader> stateTableHeader; + LEReferenceTo<StateTableHeader> stHeader; // for convenience private: StateTableProcessor(const StateTableProcessor &other); // forbid copying of this class
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/StateTableProcessor2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,236 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "StateTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "StateTableProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" +#include "LookupTables.h" + +U_NAMESPACE_BEGIN + +StateTableProcessor2::StateTableProcessor2() +{ +} + +StateTableProcessor2::StateTableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : SubtableProcessor2(morphSubtableHeader, success), stateTableHeader(morphSubtableHeader, success), + stHeader(stateTableHeader, success, (const StateTableHeader2*)&stateTableHeader->stHeader), + nClasses(0), classTableOffset(0), stateArrayOffset(0), entryTableOffset(0), classTable(), format(0), + stateArray() +{ + if (LE_FAILURE(success)) { + return; + } + nClasses = SWAPL(stHeader->nClasses); + classTableOffset = SWAPL(stHeader->classTableOffset); + stateArrayOffset = SWAPL(stHeader->stateArrayOffset); + entryTableOffset = SWAPL(stHeader->entryTableOffset); + + classTable = LEReferenceTo<LookupTable>(stHeader, success, classTableOffset); + format = SWAPW(classTable->format); + + stateArray = LEReferenceToArrayOf<EntryTableIndex2>(stHeader, success, stateArrayOffset, LE_UNBOUNDED_ARRAY); +} + +StateTableProcessor2::~StateTableProcessor2() +{ +} + +void StateTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + if (LE_FAILURE(success)) return; + // Start at state 0 + // XXX: How do we know when to start at state 1? + le_uint16 currentState = 0; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + + LE_STATE_PATIENCE_INIT(); + + le_int32 currGlyph = 0; + if ((coverage & scfReverse2) != 0) { // process glyphs in descending order + currGlyph = glyphCount - 1; + dir = -1; + } else { + dir = 1; + } + + beginStateTable(); + switch (format) { + case ltfSimpleArray: { +#ifdef TEST_FORMAT + LEReferenceTo<SimpleArrayLookupTable> lookupTable0(classTable, success); + if(LE_FAILURE(success)) break; + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + if (LE_FAILURE(success)) break; + if (LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + break; // patience exceeded. + } + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + classCode = SWAPW(lookupTable0->valueArray[gid]); + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success)); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset + LE_STATE_PATIENCE_INCR(currGlyph); + } +#endif + break; + } + case ltfSegmentSingle: { + LEReferenceTo<SegmentSingleLookupTable> lookupTable2(classTable, success); + if(LE_FAILURE(success)) break; + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + if (LE_FAILURE(success)) break; + if (LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + break; // patience exceeded. + } + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + const LookupSegment *segment = + lookupTable2->lookupSegment(lookupTable2, lookupTable2->segments, gid, success); + if (segment != NULL && LE_SUCCESS(success)) { + classCode = SWAPW(segment->value); + } + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses,success)); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success); + LE_STATE_PATIENCE_INCR(currGlyph); + } + break; + } + case ltfSegmentArray: { + //printf("Lookup Table Format4: specific interpretation needed!\n"); + break; + } + case ltfSingleTable: { + LEReferenceTo<SingleTableLookupTable> lookupTable6(classTable, success); + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + if (LE_FAILURE(success)) break; + if (LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + break; // patience exceeded. + } + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else if(currGlyph > glyphCount) { + // note if > glyphCount, we've run off the end (bad font) + currGlyph = glyphCount; + classCode = classCodeEOT; + } else { + LEGlyphID gid = glyphStorage[currGlyph]; + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); + + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else { + const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6, lookupTable6->entries, gid, success); + if (segment != NULL) { + classCode = SWAPW(segment->value); + } + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success)); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success); + LE_STATE_PATIENCE_INCR(currGlyph); + } + break; + } + case ltfTrimmedArray: { + LEReferenceTo<TrimmedArrayLookupTable> lookupTable8(classTable, success); + if (LE_FAILURE(success)) break; + TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph); + TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount); + + while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) { + if(LE_STATE_PATIENCE_DECR()) { + LE_DEBUG_BAD_FONT("patience exceeded - state table not moving") + break; // patience exceeded. + } + + LookupValue classCode = classCodeOOB; + if (currGlyph == glyphCount || currGlyph == -1) { + // XXX: How do we handle EOT vs. EOL? + classCode = classCodeEOT; + } else { + TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(glyphStorage[currGlyph]); + if (glyphCode == 0xFFFF) { + classCode = classCodeDEL; + } else if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) { + classCode = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]); + } + } + EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success)); + LE_STATE_PATIENCE_CURR(le_int32, currGlyph); + currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success); + LE_STATE_PATIENCE_INCR(currGlyph); + } + break; + } + default: + break; + } + + endStateTable(); +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/StateTableProcessor2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,85 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __STATETABLEPROCESSOR2_H +#define __STATETABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "MorphStateTables.h" +#include "SubtableProcessor2.h" +#include "LookupTables.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class StateTableProcessor2 : public SubtableProcessor2 +{ +public: + void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); + + virtual void beginStateTable() = 0; + + virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success) = 0; + + virtual void endStateTable() = 0; + +protected: + StateTableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + virtual ~StateTableProcessor2(); + + StateTableProcessor2(); + + le_int32 dir; + le_uint16 format; + le_uint32 nClasses; + le_uint32 classTableOffset; + le_uint32 stateArrayOffset; + le_uint32 entryTableOffset; + + LEReferenceTo<LookupTable> classTable; + LEReferenceToArrayOf<EntryTableIndex2> stateArray; + LEReferenceTo<MorphStateTableHeader2> stateTableHeader; + LEReferenceTo<StateTableHeader2> stHeader; // for convenience + +private: + StateTableProcessor2(const StateTableProcessor2 &other); // forbid copying of this class + StateTableProcessor2 &operator=(const StateTableProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/StateTables.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/StateTables.h Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved + * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ @@ -42,6 +42,41 @@ U_NAMESPACE_BEGIN + + + +/* + * State table loop detection. + * Detects if too many ( LE_STATE_PATIENCE_COUNT ) state changes occur without moving the glyph index 'g'. + * + * Usage (pseudocode): + * + * { + * LE_STATE_PATIENCE_INIT(); + * + * int g=0; // the glyph index - expect it to be moving + * + * for(;;) { + * if(LE_STATE_PATIENCE_DECR()) { // decrements the patience counter + * // ran out of patience, get out. + * break; + * } + * + * LE_STATE_PATIENCE_CURR(int, g); // store the 'current' + * state = newState(state,g); + * g+= <something, could be zero>; + * LE_STATE_PATIENCE_INCR(g); // if g has moved, increment the patience counter. Otherwise leave it. + * } + * + */ + +#define LE_STATE_PATIENCE_COUNT 4096 /**< give up if a state table doesn't move the glyph after this many iterations */ +#define LE_STATE_PATIENCE_INIT() le_uint32 le_patience_count = LE_STATE_PATIENCE_COUNT +#define LE_STATE_PATIENCE_DECR() --le_patience_count==0 +#define LE_STATE_PATIENCE_CURR(type,x) type le_patience_curr=(x) +#define LE_STATE_PATIENCE_INCR(x) if((x)!=le_patience_curr) ++le_patience_count; + + struct StateTableHeader { le_int16 stateSize; @@ -50,6 +85,14 @@ ByteOffset entryTableOffset; }; +struct StateTableHeader2 +{ + le_uint32 nClasses; + le_uint32 classTableOffset; + le_uint32 stateArrayOffset; + le_uint32 entryTableOffset; +}; + enum ClassCodes { classCodeEOT = 0, @@ -68,6 +111,7 @@ le_uint16 nGlyphs; ClassCode classArray[ANY_NUMBER]; }; +LE_VAR_ARRAY(ClassTable, classArray) enum StateNumber { @@ -85,6 +129,14 @@ le_int16 flags; }; +typedef le_uint16 EntryTableIndex2; + +struct StateEntry2 // same struct different interpretation +{ + le_uint16 newStateIndex; + le_uint16 flags; +}; + U_NAMESPACE_END #endif
--- a/src/share/native/sun/font/layout/SubtableProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SubtableProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -40,10 +40,10 @@ { } -SubtableProcessor::SubtableProcessor(const MorphSubtableHeader *morphSubtableHeader) +SubtableProcessor::SubtableProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : length(0), coverage(0), subtableFeatures(0L), subtableHeader(morphSubtableHeader) { - subtableHeader = morphSubtableHeader; - + if(LE_FAILURE(success)) return; length = SWAPW(subtableHeader->length); coverage = SWAPW(subtableHeader->coverage); subtableFeatures = SWAPL(subtableHeader->subtableFeatures);
--- a/src/share/native/sun/font/layout/SubtableProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/SubtableProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -46,11 +46,11 @@ class SubtableProcessor : public UMemory { public: - virtual void process(LEGlyphStorage &glyphStorage) = 0; + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success) = 0; virtual ~SubtableProcessor(); protected: - SubtableProcessor(const MorphSubtableHeader *morphSubtableHeader); + SubtableProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); SubtableProcessor(); @@ -58,7 +58,7 @@ SubtableCoverage coverage; FeatureFlags subtableFeatures; - const MorphSubtableHeader *subtableHeader; + const LEReferenceTo<MorphSubtableHeader> subtableHeader; private:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SubtableProcessor2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,57 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +SubtableProcessor2::SubtableProcessor2() +{ +} + +SubtableProcessor2::SubtableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : subtableHeader(morphSubtableHeader, success), length(0), coverage(0), subtableFeatures(0L) +{ + if(LE_FAILURE(success)) return; + + length = SWAPL(subtableHeader->length); + coverage = SWAPL(subtableHeader->coverage); + subtableFeatures = SWAPL(subtableHeader->subtableFeatures); +} + +SubtableProcessor2::~SubtableProcessor2() +{ +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/SubtableProcessor2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __SUBTABLEPROCESSOR2_H +#define __SUBTABLEPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class SubtableProcessor2 : public UMemory { +public: + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success) = 0; + virtual ~SubtableProcessor2(); + +protected: + SubtableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + + SubtableProcessor2(); + + le_uint32 length; + SubtableCoverage2 coverage; + FeatureFlags subtableFeatures; + + const LEReferenceTo<MorphSubtableHeader2> subtableHeader; + +private: + + SubtableProcessor2(const SubtableProcessor2 &other); // forbid copying of this class + SubtableProcessor2 &operator=(const SubtableProcessor2 &other); // forbid copying of this class +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/ThaiLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ThaiLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -134,11 +134,10 @@ return; } - if (fTypoFlags & 0x1) { /* kerning enabled */ - static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; - - KernTable kt(fFontInstance, getFontTable(kernTableTag)); - kt.process(glyphStorage); + if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ + LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); + KernTable kt(kernTable, success); + kt.process(glyphStorage, success); } // default is no adjustments
--- a/src/share/native/sun/font/layout/TibetanLayoutEngine.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/TibetanLayoutEngine.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -49,7 +49,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TibetanOpenTypeLayoutEngine) TibetanOpenTypeLayoutEngine::TibetanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success) : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) { fFeatureMap = TibetanReordering::getFeatureMap(fFeatureMapCount);
--- a/src/share/native/sun/font/layout/TibetanLayoutEngine.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/TibetanLayoutEngine.h Wed Apr 17 02:53:02 2013 -0700 @@ -83,7 +83,7 @@ * @internal */ TibetanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success); + le_int32 typoFlags, const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, LEErrorCode &success); /** * This constructor is used when the font requires a "canned" GSUB table which can't be known
--- a/src/share/native/sun/font/layout/TrimmedArrayProcessor.cpp Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/TrimmedArrayProcessor.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -46,22 +46,28 @@ { } -TrimmedArrayProcessor::TrimmedArrayProcessor(const MorphSubtableHeader *morphSubtableHeader) - : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader) +TrimmedArrayProcessor::TrimmedArrayProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader, success), firstGlyph(0), lastGlyph(0) { - const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader; + LEReferenceTo<NonContextualGlyphSubstitutionHeader> header(morphSubtableHeader, success); + + if(LE_FAILURE(success)) return; - trimmedArrayLookupTable = (const TrimmedArrayLookupTable *) &header->table; - firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph); - lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount); + trimmedArrayLookupTable = LEReferenceTo<TrimmedArrayLookupTable>(morphSubtableHeader, success, (const TrimmedArrayLookupTable*)&header->table); + + if(LE_FAILURE(success)) return; + + firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph); + lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount); } TrimmedArrayProcessor::~TrimmedArrayProcessor() { } -void TrimmedArrayProcessor::process(LEGlyphStorage &glyphStorage) +void TrimmedArrayProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { + if(LE_FAILURE(success)) return; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph;
--- a/src/share/native/sun/font/layout/TrimmedArrayProcessor.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/TrimmedArrayProcessor.h Wed Apr 17 02:53:02 2013 -0700 @@ -50,9 +50,9 @@ class TrimmedArrayProcessor : public NonContextualGlyphSubstitutionProcessor { public: - virtual void process(LEGlyphStorage &glyphStorage); + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); - TrimmedArrayProcessor(const MorphSubtableHeader *morphSubtableHeader); + TrimmedArrayProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success); virtual ~TrimmedArrayProcessor(); @@ -76,7 +76,7 @@ protected: TTGlyphID firstGlyph; TTGlyphID lastGlyph; - const TrimmedArrayLookupTable *trimmedArrayLookupTable; + LEReferenceTo<TrimmedArrayLookupTable> trimmedArrayLookupTable; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,82 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" +#include "TrimmedArrayProcessor2.h" +#include "LEGlyphStorage.h" +#include "LESwaps.h" + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TrimmedArrayProcessor2) + +TrimmedArrayProcessor2::TrimmedArrayProcessor2() +{ +} + +TrimmedArrayProcessor2::TrimmedArrayProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) + : NonContextualGlyphSubstitutionProcessor2(morphSubtableHeader, success) +{ + const LEReferenceTo<NonContextualGlyphSubstitutionHeader2> header(morphSubtableHeader, success); + + trimmedArrayLookupTable = LEReferenceTo<TrimmedArrayLookupTable>(morphSubtableHeader, success, &header->table); + firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph); + lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount); + valueArray = LEReferenceToArrayOf<LookupValue>(morphSubtableHeader, success, &trimmedArrayLookupTable->valueArray[0], LE_UNBOUNDED_ARRAY); +} + +TrimmedArrayProcessor2::~TrimmedArrayProcessor2() +{ +} + +void TrimmedArrayProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + if(LE_FAILURE(success)) return; + le_int32 glyphCount = glyphStorage.getGlyphCount(); + le_int32 glyph; + + for (glyph = 0; glyph < glyphCount; glyph += 1) { + LEGlyphID thisGlyph = glyphStorage[glyph]; + TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph); + + if ((ttGlyph > firstGlyph) && (ttGlyph < lastGlyph)) { + TTGlyphID newGlyph = SWAPW(valueArray(ttGlyph - firstGlyph, success)); + + glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); + } + } +} + +U_NAMESPACE_END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/native/sun/font/layout/TrimmedArrayProcessor2.h Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,84 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved + * + */ + +#ifndef __TRIMMEDARRAYPROCESSOR2_H +#define __TRIMMEDARRAYPROCESSOR2_H + +/** + * \file + * \internal + */ + +#include "LETypes.h" +#include "MorphTables.h" +#include "SubtableProcessor2.h" +#include "NonContextualGlyphSubst.h" +#include "NonContextualGlyphSubstProc2.h" + +U_NAMESPACE_BEGIN + +class LEGlyphStorage; + +class TrimmedArrayProcessor2 : public NonContextualGlyphSubstitutionProcessor2 +{ +public: + virtual void process(LEGlyphStorage &glyphStorage, LEErrorCode &success); + + TrimmedArrayProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success); + + virtual ~TrimmedArrayProcessor2(); + + /** + * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.8 + */ + virtual UClassID getDynamicClassID() const; + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.8 + */ + static UClassID getStaticClassID(); + +private: + TrimmedArrayProcessor2(); + +protected: + TTGlyphID firstGlyph; + TTGlyphID lastGlyph; + LEReferenceTo<TrimmedArrayLookupTable> trimmedArrayLookupTable; + LEReferenceToArrayOf<LookupValue> valueArray; +}; + +U_NAMESPACE_END +#endif
--- a/src/share/native/sun/font/layout/ValueRecords.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/layout/ValueRecords.h Wed Apr 17 02:53:02 2013 -0700 @@ -64,6 +64,7 @@ static le_int16 getFieldCount(ValueFormat valueFormat); static le_int16 getFieldIndex(ValueFormat valueFormat, ValueRecordField field); }; +LE_VAR_ARRAY(ValueRecord, values) enum ValueRecordFields {
--- a/src/share/native/sun/font/sunFont.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/font/sunFont.c Wed Apr 17 02:53:02 2013 -0700 @@ -320,22 +320,20 @@ JNIEXPORT TTLayoutTableCache* newLayoutTableCache() { TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache)); if (ltc) { - ltc->gsub_len = -1; - ltc->gpos_len = -1; - ltc->gdef_len = -1; - ltc->mort_len = -1; - ltc->kern_len = -1; + int i; + for(i=0;i<LAYOUTCACHE_ENTRIES;i++) { + ltc->entries[i].len = -1; + } } return ltc; } JNIEXPORT void freeLayoutTableCache(TTLayoutTableCache* ltc) { if (ltc) { - if (ltc->gsub) free(ltc->gsub); - if (ltc->gpos) free(ltc->gpos); - if (ltc->gdef) free(ltc->gdef); - if (ltc->mort) free(ltc->mort); - if (ltc->kern) free(ltc->kern); + int i; + for(i=0;i<LAYOUTCACHE_ENTRIES;i++) { + if(ltc->entries[i].ptr) free (ltc->entries[i].ptr); + } if (ltc->kernPairs) free(ltc->kernPairs); free(ltc); }
--- a/src/share/native/sun/reflect/Reflection.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/share/native/sun/reflect/Reflection.c Wed Apr 17 02:53:02 2013 -0700 @@ -27,9 +27,9 @@ #include "sun_reflect_Reflection.h" JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass -(JNIEnv *env, jclass unused, jint depth) +(JNIEnv *env, jclass unused) { - return JVM_GetCallerClass(env, depth); + return JVM_GetCallerClass(env, JVM_DEPTH); // JVM_DEPTH is only the expected value } JNIEXPORT jint JNICALL Java_sun_reflect_Reflection_getClassAccessFlags
--- a/src/solaris/classes/sun/awt/X11/XWindowPeer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/solaris/classes/sun/awt/X11/XWindowPeer.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -993,8 +993,8 @@ XLayerProtocol.LAYER_NORMAL); } - public void setAlwaysOnTop(boolean alwaysOnTop) { - this.alwaysOnTop = alwaysOnTop; + public void updateAlwaysOnTopState() { + this.alwaysOnTop = ((Window) this.target).isAlwaysOnTop(); updateAlwaysOnTop(); }
--- a/src/solaris/native/java/net/Inet4AddressImpl.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/solaris/native/java/net/Inet4AddressImpl.c Wed Apr 17 02:53:02 2013 -0700 @@ -135,9 +135,6 @@ ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); initialized = 1; } @@ -238,9 +235,8 @@ ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, name); + setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr)); + setInetAddress_hostName(env, iaObj, name); (*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj); i++; iterator = iterator->ai_next; @@ -372,9 +368,6 @@ static jclass ni_iacls; static jclass ni_ia4cls; static jmethodID ni_ia4ctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iahostID; -static jfieldID ni_iafamilyID; static int initialized = 0; /* @@ -403,9 +396,6 @@ ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); initialized = 1; } @@ -499,9 +489,8 @@ ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, i++, iaObj); iterator = iterator->ai_next; }
--- a/src/solaris/native/java/net/Inet6AddressImpl.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/solaris/native/java/net/Inet6AddressImpl.c Wed Apr 17 02:53:02 2013 -0700 @@ -120,9 +120,6 @@ static jclass ni_ia6cls; static jmethodID ni_ia4ctrID; static jmethodID ni_ia6ctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iahostID; -static jfieldID ni_iafamilyID; static jfieldID ni_ia6ipaddressID; static int initialized = 0; @@ -159,9 +156,6 @@ ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V"); ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B"); initialized = 1; } @@ -315,9 +309,8 @@ ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj); inetIndex++; } else if (iterator->ai_family == AF_INET6) { @@ -342,7 +335,7 @@ (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); } (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj); inet6Index++; }
--- a/src/solaris/native/java/net/NetworkInterface.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/solaris/native/java/net/NetworkInterface.c Wed Apr 17 02:53:02 2013 -0700 @@ -118,8 +118,6 @@ static jmethodID ni_ia4ctrID; static jmethodID ni_ia6ctrID; static jmethodID ni_ibctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iafamilyID; static jfieldID ni_ia6ipaddressID; static jfieldID ni_ibaddressID; static jfieldID ni_ib4broadcastID; @@ -195,8 +193,6 @@ ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V"); ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V"); ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B"); ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;"); ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;"); @@ -300,7 +296,7 @@ netif *ifs, *curr; #ifdef AF_INET6 - int family = ( (*env)->GetIntField(env, iaObj, ni_iafamilyID) == IPv4 ) ? AF_INET : AF_INET6; + int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6; #else int family = AF_INET; #endif @@ -325,7 +321,7 @@ if (family == addrP->family) { if (family == AF_INET) { int address1 = htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr); - int address2 = (*env)->GetIntField(env, iaObj, ni_iaaddressID); + int address2 = getInetAddress_addr(env, iaObj); if (address1 == address2) { match = JNI_TRUE; @@ -651,7 +647,7 @@ if (addrP->family == AF_INET) { iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); if (iaObj) { - (*env)->SetIntField(env, iaObj, ni_iaaddressID, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr)); + setInetAddress_addr(env, iaObj, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr)); } ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); if (ibObj) { @@ -660,8 +656,7 @@ jobject ia2Obj = NULL; ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); if (ia2Obj) { - (*env)->SetIntField(env, ia2Obj, ni_iaaddressID, - htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr)); + setInetAddress_addr(env, ia2Obj, htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr)); (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj); (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask); }
--- a/src/solaris/native/java/net/PlainDatagramSocketImpl.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/solaris/native/java/net/PlainDatagramSocketImpl.c Wed Apr 17 02:53:02 2013 -0700 @@ -552,14 +552,13 @@ iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port); #ifdef AF_INET6 - family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? - AF_INET : AF_INET6; + family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; #else family = AF_INET; #endif if (family == AF_INET) { /* this API can't handle IPV6 addresses */ - int address = (*env)->GetIntField(env, iaObj, ia_addressID); - (*env)->SetIntField(env, addressObj, ia_addressID, address); + int address = getInetAddress_addr(env, iaObj); + setInetAddress_addr(env, addressObj, address); } return port; } @@ -1028,23 +1027,18 @@ */ static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject value) { static jfieldID ni_addrsID; - static jfieldID ia_addressID; struct in_addr in; jobjectArray addrArray; jsize len; jobject addr; int i; - if (ni_addrsID == NULL || ia_addressID == NULL) { + if (ni_addrsID == NULL ) { jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); CHECK_NULL(c); ni_addrsID = (*env)->GetFieldID(env, c, "addrs", "[Ljava/net/InetAddress;"); CHECK_NULL(ni_addrsID); - c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL(c); - ia_addressID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL(ia_addressID); } addrArray = (*env)->GetObjectField(env, value, ni_addrsID); @@ -1065,8 +1059,8 @@ */ for (i = 0; i < len; i++) { addr = (*env)->GetObjectArrayElement(env, addrArray, i); - if ((*env)->GetIntField(env, addr, ia_familyID) == IPv4) { - in.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID)); + if (getInetAddress_family(env, addr) == IPv4) { + in.s_addr = htonl(getInetAddress_addr(env, addr)); break; } } @@ -1116,17 +1110,9 @@ * Throw exception if failed. */ static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) { - static jfieldID ia_addressID; struct in_addr in; - if (ia_addressID == NULL) { - jclass c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL(c); - ia_addressID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL(ia_addressID); - } - - in.s_addr = htonl( (*env)->GetIntField(env, value, ia_addressID) ); + in.s_addr = htonl( getInetAddress_addr(env, value) ); if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&in, sizeof(in)) < 0) { @@ -1456,7 +1442,6 @@ if (isIPV4) { static jclass inet4_class; static jmethodID inet4_ctrID; - static jfieldID inet4_addrID; static jclass ni_class; static jmethodID ni_ctrID; @@ -1486,15 +1471,13 @@ CHECK_NULL_RETURN(c, NULL); inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); CHECK_NULL_RETURN(inet4_ctrID, NULL); - inet4_addrID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL_RETURN(inet4_addrID, NULL); inet4_class = (*env)->NewGlobalRef(env, c); CHECK_NULL_RETURN(inet4_class, NULL); } addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0); CHECK_NULL_RETURN(addr, NULL); - (*env)->SetIntField(env, addr, inet4_addrID, ntohl(in.s_addr)); + setInetAddress_addr(env, addr, ntohl(in.s_addr)); /* * For IP_MULTICAST_IF return InetAddress @@ -1942,7 +1925,7 @@ ipv6_join_leave = ipv6_available(); #ifdef __linux__ - if ((*env)->GetIntField(env, iaObj, ia_familyID) == IPv4) { + if (getInetAddress_family(env, iaObj) == IPv4) { ipv6_join_leave = JNI_FALSE; } #endif @@ -1989,7 +1972,7 @@ CHECK_NULL(ni_indexID); } - mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID)); + mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); mname.imr_address.s_addr = 0; mname.imr_ifindex = (*env)->GetIntField(env, niObj, ni_indexID); mname_len = sizeof(struct ip_mreqn); @@ -2007,11 +1990,11 @@ } addr = (*env)->GetObjectArrayElement(env, addrArray, 0); - mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID)); + mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); #ifdef __linux__ - mname.imr_address.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID)); + mname.imr_address.s_addr = htonl(getInetAddress_addr(env, addr)); #else - mname.imr_interface.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID)); + mname.imr_interface.s_addr = htonl(getInetAddress_addr(env, addr)); #endif mname_len = sizeof(struct ip_mreq); } @@ -2046,7 +2029,7 @@ return; } - mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID)); + mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); mname.imr_address.s_addr = 0 ; mname.imr_ifindex = index; mname_len = sizeof(struct ip_mreqn); @@ -2068,7 +2051,7 @@ #else mname.imr_interface.s_addr = in.s_addr; #endif - mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, ia_addressID)); + mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); mname_len = sizeof(struct ip_mreq); } } @@ -2133,10 +2116,10 @@ jbyte caddr[16]; jint family; jint address; - family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? AF_INET : AF_INET6; + family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; if (family == AF_INET) { /* will convert to IPv4-mapped address */ memset((char *) caddr, 0, 16); - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); caddr[10] = 0xff; caddr[11] = 0xff;
--- a/src/solaris/native/java/net/net_util_md.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/solaris/native/java/net/net_util_md.c Wed Apr 17 02:53:02 2013 -0700 @@ -777,7 +777,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, int *len, jboolean v4MappedAddress) { jint family; - family = (*env)->GetIntField(env, iaObj, ia_familyID); + family = getInetAddress_family(env, iaObj); #ifdef AF_INET6 /* needs work. 1. family 2. clean up him6 etc deallocate memory */ if (ipv6_available() && !(family == IPv4 && v4MappedAddress == JNI_FALSE)) { @@ -789,7 +789,7 @@ if (family == IPv4) { /* will convert to IPv4-mapped address */ memset((char *) caddr, 0, 16); - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); if (address == INADDR_ANY) { /* we would always prefer IPv6 wildcard address caddr[10] = 0xff; @@ -898,7 +898,7 @@ return -1; } memset((char *) him4, 0, sizeof(struct sockaddr_in)); - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); him4->sin_port = htons((short) port); him4->sin_addr.s_addr = (uint32_t) htonl(address); him4->sin_family = AF_INET;
--- a/src/windows/classes/java/lang/ProcessImpl.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/classes/java/lang/ProcessImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -145,6 +145,88 @@ } + // We guarantee the only command file execution for implicit [cmd.exe] run. + // http://technet.microsoft.com/en-us/library/bb490954.aspx + private static final char CMD_BAT_ESCAPE[] = {' ', '\t', '<', '>', '&', '|', '^'}; + private static final char WIN32_EXECUTABLE_ESCAPE[] = {' ', '\t', '<', '>'}; + + private static boolean isQuoted(boolean noQuotesInside, String arg, + String errorMessage) { + int lastPos = arg.length() - 1; + if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') { + // The argument has already been quoted. + if (noQuotesInside) { + if (arg.indexOf('"', 1) != lastPos) { + // There is ["] inside. + throw new IllegalArgumentException(errorMessage); + } + } + return true; + } + if (noQuotesInside) { + if (arg.indexOf('"') >= 0) { + // There is ["] inside. + throw new IllegalArgumentException(errorMessage); + } + } + return false; + } + + private static boolean needsEscaping(boolean isCmdFile, String arg) { + // Switch off MS heuristic for internal ["]. + // Please, use the explicit [cmd.exe] call + // if you need the internal ["]. + // Example: "cmd.exe", "/C", "Extended_MS_Syntax" + + // For [.exe] or [.com] file the unpaired/internal ["] + // in the argument is not a problem. + boolean argIsQuoted = isQuoted(isCmdFile, arg, + "Argument has embedded quote, use the explicit CMD.EXE call."); + + if (!argIsQuoted) { + char testEscape[] = isCmdFile + ? CMD_BAT_ESCAPE + : WIN32_EXECUTABLE_ESCAPE; + for (int i = 0; i < testEscape.length; ++i) { + if (arg.indexOf(testEscape[i]) >= 0) { + return true; + } + } + } + return false; + } + + private static String getExecutablePath(String path) + throws IOException + { + boolean pathIsQuoted = isQuoted(true, path, + "Executable name has embedded quote, split the arguments"); + + // Win32 CreateProcess requires path to be normalized + File fileToRun = new File(pathIsQuoted + ? path.substring(1, path.length() - 1) + : path); + + // From the [CreateProcess] function documentation: + // + // "If the file name does not contain an extension, .exe is appended. + // Therefore, if the file name extension is .com, this parameter + // must include the .com extension. If the file name ends in + // a period (.) with no extension, or if the file name contains a path, + // .exe is not appended." + // + // "If the file name !does not contain a directory path!, + // the system searches for the executable file in the following + // sequence:..." + // + // In practice ANY non-existent path is extended by [.exe] extension + // in the [CreateProcess] funcion with the only exception: + // the path ends by (.) + + return fileToRun.getPath(); + } + + private long handle = 0; private OutputStream stdin_stream; private InputStream stdout_stream; @@ -157,30 +239,47 @@ final boolean redirectErrorStream) throws IOException { - // Win32 CreateProcess requires cmd[0] to be normalized - cmd[0] = new File(cmd[0]).getPath(); + // The [executablePath] is not quoted for any case. + String executablePath = getExecutablePath(cmd[0]); + + // We need to extend the argument verification procedure + // to guarantee the only command file execution for implicit [cmd.exe] + // run. + String upPath = executablePath.toUpperCase(); + boolean isCmdFile = (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); StringBuilder cmdbuf = new StringBuilder(80); - for (int i = 0; i < cmd.length; i++) { - if (i > 0) { - cmdbuf.append(' '); - } + + // Quotation protects from interpretation of the [path] argument as + // start of longer path with spaces. Quotation has no influence to + // [.exe] extension heuristic. + cmdbuf.append('"'); + cmdbuf.append(executablePath); + cmdbuf.append('"'); + + for (int i = 1; i < cmd.length; i++) { + cmdbuf.append(' '); String s = cmd[i]; - if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0) { - if (s.charAt(0) != '"') { - cmdbuf.append('"'); - cmdbuf.append(s); - if (s.endsWith("\\")) { - cmdbuf.append("\\"); - } - cmdbuf.append('"'); - } else if (s.endsWith("\"")) { - /* The argument has already been quoted. */ - cmdbuf.append(s); - } else { - /* Unmatched quote for the argument. */ - throw new IllegalArgumentException(); + if (needsEscaping(isCmdFile, s)) { + cmdbuf.append('"'); + cmdbuf.append(s); + + // The code protects the [java.exe] and console command line + // parser, that interprets the [\"] combination as an escape + // sequence for the ["] char. + // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx + // + // If the argument is an FS path, doubling of the tail [\] + // char is not a problem for non-console applications. + // + // The [\"] sequence is not an escape sequence for the [cmd.exe] + // command line parser. The case of the [""] tail escape + // sequence could not be realized due to the argument validation + // procedure. + if (!isCmdFile && s.endsWith("\\")) { + cmdbuf.append('\\'); } + cmdbuf.append('"'); } else { cmdbuf.append(s); }
--- a/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -102,7 +102,7 @@ if ((fd != null && fd1 != null) && !connected) { return anyLocalBoundAddr; } - int family = connectedAddress == null ? -1 : connectedAddress.family; + int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily(); return socketLocalAddress(family); } else return super.getOption(optID);
--- a/src/windows/classes/sun/awt/windows/WFileDialogPeer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/classes/sun/awt/windows/WFileDialogPeer.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,7 @@ // unused methods. Overridden to disable this functionality as // it requires HWND which is not available for FileDialog - public void setAlwaysOnTop(boolean value) {} + public void updateAlwaysOnTopState() {} public void setDirectory(String dir) {} public void setFile(String file) {} public void setTitle(String title) {}
--- a/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/classes/sun/awt/windows/WPrintDialogPeer.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,7 +117,7 @@ // unused methods. Overridden to disable this functionality as // it requires HWND which is not available for FileDialog void initialize() {} - public void setAlwaysOnTop(boolean b) {} + public void updateAlwaysOnTopState() {} public void setResizable(boolean resizable) {} public void hide() {} public void enable() {}
--- a/src/windows/classes/sun/awt/windows/WWindowPeer.java Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/classes/sun/awt/windows/WWindowPeer.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,10 @@ } } + public void updateAlwaysOnTopState() { + setAlwaysOnTop(((Window)target).isAlwaysOnTop()); + } + public void updateFocusableWindowState() { setFocusableWindow(((Window)target).isFocusableWindow()); }
--- a/src/windows/native/java/net/Inet4AddressImpl.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/native/java/net/Inet4AddressImpl.c Wed Apr 17 02:53:02 2013 -0700 @@ -114,9 +114,6 @@ static jclass ni_iacls; static jclass ni_ia4cls; static jmethodID ni_ia4ctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iahostID; -static jfieldID ni_iafamilyID; static int initialized = 0; /* @@ -149,9 +146,6 @@ ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); initialized = 1; } @@ -208,8 +202,7 @@ ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(address)); + setInetAddress_addr(env, iaObj, ntohl(address)); (*env)->SetObjectArrayElement(env, ret, 0, iaObj); JNU_ReleaseStringPlatformChars(env, host, hostname); return ret; @@ -242,9 +235,8 @@ ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl((*addrp)->s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_addr(env, iaObj, ntohl((*addrp)->s_addr)); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, i, iaObj); addrp++; i++;
--- a/src/windows/native/java/net/Inet6AddressImpl.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/native/java/net/Inet6AddressImpl.c Wed Apr 17 02:53:02 2013 -0700 @@ -77,9 +77,6 @@ static jclass ni_ia6cls; static jmethodID ni_ia4ctrID; static jmethodID ni_ia6ctrID; -static jfieldID ni_iaaddressID; -static jfieldID ni_iahostID; -static jfieldID ni_iafamilyID; static jfieldID ni_ia6ipaddressID; static int initialized = 0; @@ -104,9 +101,6 @@ ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls); ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V"); ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V"); - ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); - ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); - ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B"); initialized = 1; } @@ -243,9 +237,8 @@ ret = NULL; goto cleanupAndReturn; } - (*env)->SetIntField(env, iaObj, ni_iaaddressID, - ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj); inetIndex ++; } else if (iterator->ai_family == AF_INET6) { @@ -269,7 +262,7 @@ (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); } (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress); - (*env)->SetObjectField(env, iaObj, ni_iahostID, host); + setInetAddress_hostName(env, iaObj, host); (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj); inet6Index ++; }
--- a/src/windows/native/java/net/NetworkInterface.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/native/java/net/NetworkInterface.c Wed Apr 17 02:53:02 2013 -0700 @@ -66,7 +66,6 @@ jfieldID ni_displayNameID; /* NetworkInterface.displayName */ jfieldID ni_childsID; /* NetworkInterface.childs */ jclass ni_iacls; /* InetAddress */ -jfieldID ni_iaAddr; /* InetAddress.address */ jclass ni_ia4cls; /* Inet4Address */ jmethodID ni_ia4Ctor; /* Inet4Address() */ @@ -480,7 +479,6 @@ ni_iacls = (*env)->FindClass(env, "java/net/InetAddress"); ni_iacls = (*env)->NewGlobalRef(env, ni_iacls); - ni_iaAddr = (*env)->GetFieldID(env, ni_iacls, "address", "I"); ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); @@ -568,7 +566,7 @@ } /* default ctor will set family to AF_INET */ - (*env)->SetIntField(env, iaObj, ni_iaAddr, ntohl(addrs->addr.him4.sin_addr.s_addr)); + setInetAddress_addr(env, iaObj, ntohl(addrs->addr.him4.sin_addr.s_addr)); if (addrs->mask != -1) { ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); if (ibObj == NULL) { @@ -581,8 +579,7 @@ free_netaddr(netaddrP); return NULL; } - (*env)->SetIntField(env, ia2Obj, ni_iaAddr, - ntohl(addrs->brdcast.him4.sin_addr.s_addr)); + setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.him4.sin_addr.s_addr)); (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj); (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask); (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj); @@ -736,7 +733,7 @@ (JNIEnv *env, jclass cls, jobject iaObj) { netif *ifList, *curr; - jint addr = (*env)->GetIntField(env, iaObj, ni_iaAddr); + jint addr = getInetAddress_addr(env, iaObj); jobject netifObj = NULL; // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
--- a/src/windows/native/java/net/NetworkInterface.h Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/native/java/net/NetworkInterface.h Wed Apr 17 02:53:02 2013 -0700 @@ -71,7 +71,6 @@ extern jfieldID ni_childsID; /* NetworkInterface.childs */ extern jclass ni_iacls; /* InetAddress */ -extern jfieldID ni_iaAddr; /* InetAddress.address */ extern jclass ni_ia4cls; /* Inet4Address */ extern jmethodID ni_ia4Ctor; /* Inet4Address() */
--- a/src/windows/native/java/net/NetworkInterface_winXP.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/native/java/net/NetworkInterface_winXP.c Wed Apr 17 02:53:02 2013 -0700 @@ -33,6 +33,7 @@ #include "jni_util.h" #include "NetworkInterface.h" +#include "net_util.h" /* * Windows implementation of the java.net.NetworkInterface native methods. @@ -477,7 +478,7 @@ } /* default ctor will set family to AF_INET */ - (*env)->SetIntField(env, iaObj, ni_iaAddr, ntohl(addrs->addr.him4.sin_addr.s_addr)); + setInetAddress_addr(env, iaObj, ntohl(addrs->addr.him4.sin_addr.s_addr)); ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); if (ibObj == NULL) { @@ -490,8 +491,7 @@ free_netaddr(netaddrP); return NULL; } - (*env)->SetIntField(env, ia2Obj, ni_iaAddr, - ntohl(addrs->brdcast.him4.sin_addr.s_addr)); + setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.him4.sin_addr.s_addr)); (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj); (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask); (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
--- a/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c Wed Apr 17 02:53:02 2013 -0700 @@ -432,7 +432,7 @@ int lcladdrlen; int address; - family = (*env)->GetIntField(env, addressObj, ia_familyID); + family = getInetAddress_family(env, addressObj); if (family == IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); @@ -452,7 +452,7 @@ JNU_ThrowNullPointerException(env, "argument address"); return; } else { - address = (*env)->GetIntField(env, addressObj, ia_addressID); + address = getInetAddress_addr(env, addressObj); } if (NET_InetAddressToSockaddr(env, addressObj, port, (struct sockaddr *)&lcladdr, &lcladdrlen, JNI_FALSE) != 0) { @@ -552,9 +552,9 @@ return; } - addr = (*env)->GetIntField(env, address, ia_addressID); + addr = getInetAddress_addr(env, address); - family = (*env)->GetIntField(env, address, ia_familyID); + family = getInetAddress_family(env, address); if (family == IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); @@ -670,7 +670,7 @@ return; } - family = (*env)->GetIntField(env, iaObj, ia_familyID); + family = getInetAddress_family(env, iaObj); if (family == IPv4) { fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); } else { @@ -714,7 +714,7 @@ if (!w2k_or_later) { /* avoid this check on Win 2K or better. Does not work with IPv6. * Check is not necessary on these OSes */ if (connected) { - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); } else { address = ntohl(rmtaddr.him4.sin_addr.s_addr); } @@ -823,7 +823,7 @@ if (IS_NULL(addressObj)) { JNU_ThrowNullPointerException(env, "Null address in peek()"); } else { - address = (*env)->GetIntField(env, addressObj, ia_addressID); + address = getInetAddress_addr(env, addressObj); /* We only handle IPv4 for now. Will support IPv6 once its in the os */ family = AF_INET; } @@ -905,9 +905,8 @@ JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 0); return 0; } - (*env)->SetIntField(env, addressObj, ia_addressID, - ntohl(remote_addr.sin_addr.s_addr)); - (*env)->SetIntField(env, addressObj, ia_familyID, IPv4); + setInetAddress_addr(env, addressObj, ntohl(remote_addr.sin_addr.s_addr)); + setInetAddress_family(env, addressObj, IPv4); /* return port */ return ntohs(remote_addr.sin_port); @@ -1574,21 +1573,16 @@ { jobjectArray addrArray; static jfieldID ni_addrsID=0; - static jfieldID ia_familyID=0; jsize len; jobject addr; int i; - if (ni_addrsID == NULL || ia_familyID == NULL) { + if (ni_addrsID == NULL ) { jclass c = (*env)->FindClass(env, "java/net/NetworkInterface"); CHECK_NULL_RETURN (c, -1); ni_addrsID = (*env)->GetFieldID(env, c, "addrs", "[Ljava/net/InetAddress;"); CHECK_NULL_RETURN (ni_addrsID, -1); - c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL_RETURN (c, -1); - ia_familyID = (*env)->GetFieldID(env, c, "family", "I"); - CHECK_NULL_RETURN (ia_familyID, -1); } addrArray = (*env)->GetObjectField(env, nif, ni_addrsID); @@ -1606,7 +1600,7 @@ for (i=0; i<len; i++) { int fam; addr = (*env)->GetObjectArrayElement(env, addrArray, i); - fam = (*env)->GetIntField(env, addr, ia_familyID); + fam = getInetAddress_family(env, addr); if (fam == family) { *iaddr = addr; return 0; @@ -1618,20 +1612,13 @@ static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr) { jobject addr; - static jfieldID ia_addressID; int ret = getInetAddrFromIf (env, IPv4, nif, &addr); if (ret == -1) { return -1; } - if (ia_addressID == 0) { - jclass c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL_RETURN (c, -1); - ia_addressID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL_RETURN (ia_addressID, -1); - } - iaddr->s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID)); + iaddr->s_addr = htonl(getInetAddress_addr(env, addr)); return 0; } @@ -1706,17 +1693,9 @@ } opt = java_net_SocketOptions_IP_MULTICAST_IF2; } else { - static jfieldID ia_addressID; struct in_addr in; - if (ia_addressID == NULL) { - jclass c = (*env)->FindClass(env,"java/net/InetAddress"); - CHECK_NULL(c); - ia_addressID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL(ia_addressID); - } - - in.s_addr = htonl((*env)->GetIntField(env, value, ia_addressID)); + in.s_addr = htonl(getInetAddress_addr(env, value)); if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&in, sizeof(in)) < 0) { @@ -1945,7 +1924,6 @@ if (isIPV4) { static jclass inet4_class; static jmethodID inet4_ctrID; - static jfieldID inet4_addrID; static jclass ni_class; static jmethodID ni_ctrID; @@ -1975,15 +1953,13 @@ CHECK_NULL_RETURN(c, NULL); inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V"); CHECK_NULL_RETURN(inet4_ctrID, NULL); - inet4_addrID = (*env)->GetFieldID(env, c, "address", "I"); - CHECK_NULL_RETURN(inet4_addrID, NULL); inet4_class = (*env)->NewGlobalRef(env, c); CHECK_NULL_RETURN(inet4_class, NULL); } addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0); CHECK_NULL_RETURN(addr, NULL); - (*env)->SetIntField(env, addr, inet4_addrID, ntohl(in.s_addr)); + setInetAddress_addr(env, addr, ntohl(in.s_addr)); /* * For IP_MULTICAST_IF return InetAddress
--- a/src/windows/native/java/net/TwoStacksPlainSocketImpl.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/native/java/net/TwoStacksPlainSocketImpl.c Wed Apr 17 02:53:02 2013 -0700 @@ -411,7 +411,7 @@ fdObj = (*env)->GetObjectField(env, this, psi_fdID); fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); - family = (*env)->GetIntField(env, iaObj, ia_familyID); + family = getInetAddress_family(env, iaObj); if (family == IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", @@ -724,9 +724,8 @@ return; } - (*env)->SetIntField(env, socketAddressObj, ia_addressID, - ntohl(him.him4.sin_addr.s_addr)); - (*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv4); + setInetAddress_addr(env, socketAddressObj, ntohl(him.him4.sin_addr.s_addr)); + setInetAddress_family(env, socketAddressObj, IPv4); (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); } else { jbyteArray addr; @@ -754,7 +753,7 @@ } addr = (*env)->GetObjectField (env, socketAddressObj, ia6_ipaddressID); (*env)->SetByteArrayRegion (env, addr, 0, 16, (const char *)&him.him6.sin6_addr); - (*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv6); + setInetAddress_family(env, socketAddressObj, IPv6); scope = him.him6.sin6_scope_id; (*env)->SetIntField(env, socketAddressObj, ia6_scopeidID, scope); if(scope>0) {
--- a/src/windows/native/java/net/net_util_md.c Tue Apr 16 05:32:39 2013 -0700 +++ b/src/windows/native/java/net/net_util_md.c Wed Apr 17 02:53:02 2013 -0700 @@ -804,7 +804,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, int *len, jboolean v4MappedAddress) { jint family, iafam; - iafam = (*env)->GetIntField(env, iaObj, ia_familyID); + iafam = getInetAddress_family(env, iaObj); family = (iafam == IPv4)? AF_INET : AF_INET6; if (ipv6_available() && !(family == AF_INET && v4MappedAddress == JNI_FALSE)) { struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; @@ -815,7 +815,7 @@ if (family == AF_INET) { /* will convert to IPv4-mapped address */ memset((char *) caddr, 0, 16); - address = (*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); if (address == INADDR_ANY) { /* we would always prefer IPv6 wildcard address caddr[10] = 0xff; @@ -854,7 +854,7 @@ return -1; } memset((char *) him4, 0, sizeof(struct sockaddr_in)); - address = (int)(*env)->GetIntField(env, iaObj, ia_addressID); + address = getInetAddress_addr(env, iaObj); him4->sin_port = htons((short) port); him4->sin_addr.s_addr = (u_long) htonl(address); him4->sin_family = AF_INET;
--- a/test/Makefile Tue Apr 16 05:32:39 2013 -0700 +++ b/test/Makefile Wed Apr 17 02:53:02 2013 -0700 @@ -478,7 +478,7 @@ # Stable agentvm testruns (minus items from PROBLEM_LIST) JDK_ALL_TARGETS += jdk_lang JDK_DEFAULT_TARGETS += jdk_lang -jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc vm) +jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc sun/reflect vm) $(call RunAgentvmBatch) # Stable othervm testruns (minus items from PROBLEM_LIST) @@ -513,8 +513,9 @@ javax/script \ java/sql javax/sql \ javax/smartcardio \ + javax/xml/jaxp \ javax/xml/soap \ - javax/xml/ws com/sun/internal/ws \ + javax/xml/ws com/sun/internal/ws com/sun/org/glassfish \ jdk/asm \ com/sun/org/apache/xerces \ com/sun/corba \
--- a/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java Tue Apr 16 05:32:39 2013 -0700 +++ b/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java Wed Apr 17 02:53:02 2013 -0700 @@ -31,7 +31,8 @@ * * @library ../../testlibrary * @build TestLibrary Dummy - * @run main/othervm/policy=security.policy ClassPathCodebase + * @run main/othervm/policy=security.policy + * -Djava.rmi.server.useCodebaseOnly=false ClassPathCodebase */ import java.io.*;
--- a/test/java/rmi/registry/readTest/readTest.sh Tue Apr 16 05:32:39 2013 -0700 +++ b/test/java/rmi/registry/readTest/readTest.sh Wed Apr 17 02:53:02 2013 -0700 @@ -61,7 +61,8 @@ #start rmiregistry without any local classes on classpath cd rmi_tmp # NOTE: This RMI Registry port must match TestLibrary.READTEST_REGISTRY_PORT -${TESTJAVA}${FS}bin${FS}rmiregistry ${TESTTOOLVMOPTS} 64005 > ..${FS}${RMIREG_OUT} 2>&1 & +${TESTJAVA}${FS}bin${FS}rmiregistry -J-Djava.rmi.server.useCodebaseOnly=false \ + ${TESTTOOLVMOPTS} 64005 > ..${FS}${RMIREG_OUT} 2>&1 & RMIREG_PID=$! # allow some time to start sleep 3
--- a/test/java/rmi/server/RMIClassLoader/downloadArrayClass/DownloadArrayClass.java Tue Apr 16 05:32:39 2013 -0700 +++ b/test/java/rmi/server/RMIClassLoader/downloadArrayClass/DownloadArrayClass.java Wed Apr 17 02:53:02 2013 -0700 @@ -64,6 +64,10 @@ TestLibrary.bomb(e); } + System.err.println("Setting codebase property to: " + remoteCodebase); + System.setProperty("java.rmi.server.codebase", + remoteCodebase.toString()); + /* * Load Foo from a non-RMI class loader so that it won't be already * loaded by an RMI class loader in this VM (for whatever that's
--- a/test/java/rmi/server/RMIClassLoader/downloadArrayClass/security.policy Tue Apr 16 05:32:39 2013 -0700 +++ b/test/java/rmi/server/RMIClassLoader/downloadArrayClass/security.policy Wed Apr 17 02:53:02 2013 -0700 @@ -7,6 +7,8 @@ }; grant { + permission java.util.PropertyPermission + "java.rmi.server.codebase", "read,write"; // permissions needed to move classes into separate codebase directories permission java.io.FilePermission
--- a/test/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java Tue Apr 16 05:32:39 2013 -0700 +++ b/test/java/rmi/server/RMIClassLoader/loadProxyClasses/LoadProxyClasses.java Wed Apr 17 02:53:02 2013 -0700 @@ -32,7 +32,8 @@ * @library ../../../testlibrary * @build TestLibrary FnnClass FnnUnmarshal NonpublicInterface * NonpublicInterface1 PublicInterface PublicInterface1 - * @run main/othervm/policy=security.policy LoadProxyClasses + * @run main/othervm/policy=security.policy + * -Djava.rmi.server.useCodebaseOnly=false LoadProxyClasses */ import java.rmi.server.RMIClassLoader;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8001040 + * @summary Tests proper parsing and defaulting of the + * "java.rmi.server.useCodebaseOnly" property. + * + * @run main/othervm UseCodebaseOnlyDefault true + * @run main/othervm -Djava.rmi.server.useCodebaseOnly=xyzzy UseCodebaseOnlyDefault true + * @run main/othervm -Djava.rmi.server.useCodebaseOnly UseCodebaseOnlyDefault true + * @run main/othervm -Djava.rmi.server.useCodebaseOnly=true UseCodebaseOnlyDefault true + * @run main/othervm -Djava.rmi.server.useCodebaseOnly=false UseCodebaseOnlyDefault false + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import sun.rmi.server.MarshalInputStream; + +/** + * usage: UseCodebaseOnlyDefault expected + * + * 'expected' is the expected value of useCodebaseOnly, which + * must be "true" or "false". + */ +public class UseCodebaseOnlyDefault { + static final String USAGE = "usage: UseCodebaseOnlyDefault boolean"; + static final String PROPNAME = "java.rmi.server.useCodebaseOnly"; + + /** + * Gets the actual useCodebaseOnly value by creating an instance + * of MarshalInputStream and reflecting on the useCodebaseOnly field. + */ + static boolean getActualValue() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject("foo"); + oos.close(); + + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + MarshalInputStream mis = new MarshalInputStream(bais); + + Field f = MarshalInputStream.class.getDeclaredField("useCodebaseOnly"); + f.setAccessible(true); + return f.getBoolean(mis); + } + + public static void main(String[] args) throws Exception { + if (args.length != 1) { + throw new IllegalArgumentException(USAGE); + } + + boolean expected; + if (args[0].equals("true")) { + expected = true; + } else if (args[0].equals("false")) { + expected = false; + } else { + throw new IllegalArgumentException(USAGE); + } + System.out.println("expected = " + expected); + + String prop = System.getProperty(PROPNAME); + System.out.print("Property " + PROPNAME); + if (prop == null) { + System.out.println(" is not set"); + } else { + System.out.println(" = '" + prop + "'"); + } + + boolean actual = getActualValue(); + System.out.println("actual = " + actual); + + if (expected != actual) + throw new AssertionError("actual does not match expected value"); + } +}
--- a/test/java/rmi/testlibrary/RMID.java Tue Apr 16 05:32:39 2013 -0700 +++ b/test/java/rmi/testlibrary/RMID.java Wed Apr 17 02:53:02 2013 -0700 @@ -108,6 +108,9 @@ if (!TestParams.testClasses.equals("")) { args += " -C-Dtest.classes=" + TestParams.testClasses; } + + args += " -C-Djava.rmi.server.useCodebaseOnly=false "; + args += " " + getCodeCoverageArgs(); return args; }
--- a/test/java/util/Currency/tablea1.txt Tue Apr 16 05:32:39 2013 -0700 +++ b/test/java/util/Currency/tablea1.txt Wed Apr 17 02:53:02 2013 -0700 @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 154 -# (As of 31 August 2012) +# Amendments up until ISO 4217 AMENDMENT NUMBER 155 +# (As of 11 April 2013) # # Version FILEVERSION=1 -DATAVERSION=154 +DATAVERSION=155 # ISO 4217 currency data AF AFN 971 2 @@ -256,7 +256,7 @@ TM TMT 934 2 TC USD 840 2 TV AUD 36 2 -UG UGX 800 2 +UG UGX 800 0 UA UAH 980 2 AE AED 784 2 GB GBP 826 2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/Map/Defaults.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8010122 8004518 + * @summary Test Map default methods + * @author Mike Duigou + * @run testng Defaults + */ +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.function.Supplier; + +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; +import static org.testng.Assert.fail; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertSame; + +public class Defaults { + + @Test(dataProvider = "Nulls Map<IntegerEnum,String>") + public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), "values should match"); + } + + @Test(dataProvider = "Map<IntegerEnum,String>") + public void testGetOrDefault(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1]), "expected key missing"); + assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match"); + assertFalse(map.containsKey(EXTRA_KEY), "expected absent key"); + assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default"); + assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default"); + } + + @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>") + public void testPutIfAbsentNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null"); + assertTrue(map.containsKey(null), "null key absent"); + assertSame(map.get(null), EXTRA_VALUE, "unexpected value"); + assertSame(map.putIfAbsent(null, null), EXTRA_VALUE, "previous not expected value"); + assertTrue(map.containsKey(null), "null key absent"); + assertSame(map.get(null), EXTRA_VALUE, "unexpected value"); + assertSame(map.remove(null), EXTRA_VALUE, "removed unexpected value"); + + assertFalse(map.containsKey(null), description + ": key present after remove"); + assertNull(map.putIfAbsent(null, null), "previous not null"); + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null"); + assertSame(map.get(null), EXTRA_VALUE, "value not expected"); + } + + @Test(dataProvider = "R/W Map<IntegerEnum,String>") + public void testPutIfAbsent(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1])); + Object expected = map.get(KEYS[1]); + assertTrue(null == expected || expected == VALUES[1]); + assertSame(map.putIfAbsent(KEYS[1], EXTRA_VALUE), expected); + assertSame(map.get(KEYS[1]), expected); + + assertFalse(map.containsKey(EXTRA_KEY)); + assertSame(map.putIfAbsent(EXTRA_KEY, EXTRA_VALUE), null); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); + } + + @Test(dataProvider = "Nulls Map<IntegerEnum,String>") + public void testForEach(String description, Map<IntegerEnum, String> map) { + IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()]; + + map.forEach((k, v) -> { + int idx = (null == k) ? 0 : k.ordinal(); // substitute for index. + assertNull(EACH_KEY[idx]); + EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison. + assertSame(v, map.get(k)); + }); + + assertEquals(KEYS, EACH_KEY); + } + + @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>") + public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertFalse(map.remove(null, EXTRA_VALUE), description); + assertTrue(map.containsKey(null)); + assertNull(map.get(null)); + assertTrue(map.remove(null, null)); + assertFalse(map.containsKey(null)); + assertNull(map.get(null)); + assertFalse(map.remove(null, null)); + } + + @Test(dataProvider = "R/W Map<IntegerEnum,String>") + public static void testRemove(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1])); + Object expected = map.get(KEYS[1]); + assertTrue(null == expected || expected == VALUES[1]); + assertFalse(map.remove(KEYS[1], EXTRA_VALUE), description); + assertSame(map.get(KEYS[1]), expected); + assertTrue(map.remove(KEYS[1], expected)); + assertNull(map.get(KEYS[1])); + assertFalse(map.remove(KEYS[1], expected)); + + assertFalse(map.containsKey(EXTRA_KEY)); + assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE)); + } + + @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>") + public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertSame(map.replace(null, EXTRA_VALUE), null); + assertSame(map.get(null), EXTRA_VALUE); + } + + @Test(dataProvider = "R/W Map<IntegerEnum,String>") + public void testReplaceKV(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1])); + Object expected = map.get(KEYS[1]); + assertTrue(null == expected || expected == VALUES[1]); + assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected); + assertSame(map.get(KEYS[1]), EXTRA_VALUE); + + assertFalse(map.containsKey(EXTRA_KEY)); + assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE)); + assertFalse(map.containsKey(EXTRA_KEY)); + assertNull(map.get(EXTRA_KEY)); + assertNull(map.put(EXTRA_KEY, EXTRA_VALUE)); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); + assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE); + assertSame(map.get(EXTRA_KEY), expected); + } + + @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>") + public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE)); + assertNull(map.get(null)); + assertTrue(map.replace(null, null, EXTRA_VALUE)); + assertSame(map.get(null), EXTRA_VALUE); + assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE)); + assertSame(map.get(null), EXTRA_VALUE); + } + + @Test(dataProvider = "R/W Map<IntegerEnum,String>") + public void testReplaceKVV(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1])); + Object expected = map.get(KEYS[1]); + assertTrue(null == expected || expected == VALUES[1]); + assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE)); + assertSame(map.get(KEYS[1]), expected); + assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE)); + assertSame(map.get(KEYS[1]), EXTRA_VALUE); + assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE)); + assertSame(map.get(KEYS[1]), EXTRA_VALUE); + + assertFalse(map.containsKey(EXTRA_KEY)); + assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE)); + assertFalse(map.containsKey(EXTRA_KEY)); + assertNull(map.get(EXTRA_KEY)); + assertNull(map.put(EXTRA_KEY, EXTRA_VALUE)); + assertTrue(map.containsKey(EXTRA_KEY)); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); + assertTrue(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE)); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); + } + + @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>") + public void testComputeIfAbsentNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, description); + assertSame(map.get(null), EXTRA_VALUE, description); + } + + @Test(dataProvider = "R/W Map<IntegerEnum,String>") + public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1])); + Object expected = map.get(KEYS[1]); + assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected)); + expected = (null == expected) ? EXTRA_VALUE : expected; + assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description); + assertSame(map.get(KEYS[1]), expected, description); + + assertFalse(map.containsKey(EXTRA_KEY)); + assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); + } + + @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>") + public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null)); + assertNull(map.get(null)); + assertSame(map.computeIfPresent(null, (k, v) -> { + fail(); + return EXTRA_VALUE; + }), null, description); + assertTrue(map.containsKey(null)); + assertSame(map.get(null), null, description); + } + + @Test(dataProvider = "R/W Map<IntegerEnum,String>") + public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1])); + Object value = map.get(KEYS[1]); + assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); + Object expected = (null == value) ? null : EXTRA_VALUE; + assertSame(map.computeIfPresent(KEYS[1], (k, v) -> { + assertSame(v, value); + return EXTRA_VALUE; + }), expected, description); + assertSame(map.get(KEYS[1]), expected, description); + + assertFalse(map.containsKey(EXTRA_KEY)); + assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> { + fail(); + return EXTRA_VALUE; + }), null); + assertFalse(map.containsKey(EXTRA_KEY)); + assertSame(map.get(EXTRA_KEY), null); + } + + @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>") + public void testComputeNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertSame(map.compute(null, (k, v) -> { + assertSame(k, null); + assertNull(v); + return EXTRA_VALUE; + }), EXTRA_VALUE, description); + assertTrue(map.containsKey(null)); + assertSame(map.get(null), EXTRA_VALUE, description); + assertSame(map.remove(null), EXTRA_VALUE, "removed value not expected"); + assertFalse(map.containsKey(null), "null key present"); + assertSame(map.compute(null, (k, v) -> { + assertSame(k, null); + assertNull(v); + return null; + }), null, description); + } + + @Test(dataProvider = "R/W Map<IntegerEnum,String>") + public void testCompute(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1])); + Object value = map.get(KEYS[1]); + assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); + assertSame(map.compute(KEYS[1], (k, v) -> { + assertSame(k, KEYS[1]); + assertSame(v, value); + return EXTRA_VALUE; + }), EXTRA_VALUE, description); + assertSame(map.get(KEYS[1]), EXTRA_VALUE, description); + assertNull(map.compute(KEYS[1], (k, v) -> { + assertSame(v, EXTRA_VALUE); + return null; + }), description); + assertFalse(map.containsKey(KEYS[1])); + + assertFalse(map.containsKey(EXTRA_KEY)); + assertSame(map.compute(EXTRA_KEY, (k, v) -> { + assertNull(v); + return EXTRA_VALUE; + }), EXTRA_VALUE); + assertTrue(map.containsKey(EXTRA_KEY)); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); + } + + + @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>") + public void testMergeNulls(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(null), "null key absent"); + assertNull(map.get(null), "value not null"); + assertSame(map.merge(null, EXTRA_VALUE, (v, vv) -> { + assertNull(v); + assertSame(vv, EXTRA_VALUE); + return vv; + }), EXTRA_VALUE, description); + assertTrue(map.containsKey(null)); + assertSame(map.get(null), EXTRA_VALUE, description); + } + + @Test(dataProvider = "R/W Map<IntegerEnum,String>") + public void testMerge(String description, Map<IntegerEnum, String> map) { + assertTrue(map.containsKey(KEYS[1])); + Object value = map.get(KEYS[1]); + assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); + assertSame(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> { + assertSame(v, value); + assertSame(vv, EXTRA_VALUE); + return vv; + }), EXTRA_VALUE, description); + assertSame(map.get(KEYS[1]), EXTRA_VALUE, description); + assertNull(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> { + assertSame(v, EXTRA_VALUE); + assertSame(vv, EXTRA_VALUE); + return null; + }), description); + assertFalse(map.containsKey(KEYS[1])); + + assertFalse(map.containsKey(EXTRA_KEY)); + assertSame(map.merge(EXTRA_KEY, EXTRA_VALUE, (v, vv) -> { + assertNull(v); + assertSame(vv, EXTRA_VALUE); + return EXTRA_VALUE; + }), EXTRA_VALUE); + assertTrue(map.containsKey(EXTRA_KEY)); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); + } + + enum IntegerEnum { + + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, + e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, + e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, + e30, e31, e32, e33, e34, e35, e36, e37, e38, e39, + e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, + e50, e51, e52, e53, e54, e55, e56, e57, e58, e59, + e60, e61, e62, e63, e64, e65, e66, e67, e68, e69, + e70, e71, e72, e73, e74, e75, e76, e77, e78, e79, + e80, e81, e82, e83, e84, e85, e86, e87, e88, e89, + e90, e91, e92, e93, e94, e95, e96, e97, e98, e99, + EXTRA_KEY; + public static final int SIZE = values().length; + }; + private static final int TEST_SIZE = IntegerEnum.SIZE - 1; + /** + * Realized keys ensure that there is always a hard ref to all test objects. + */ + private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE]; + /** + * Realized values ensure that there is always a hard ref to all test + * objects. + */ + private static final String[] VALUES = new String[TEST_SIZE]; + + static { + IntegerEnum[] keys = IntegerEnum.values(); + for (int each = 0; each < TEST_SIZE; each++) { + KEYS[each] = keys[each]; + VALUES[each] = String.valueOf(each); + } + } + private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY; + private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE); + + @DataProvider(name = "Map<IntegerEnum,String>", parallel = true) + public static Iterator<Object[]> allNullsMapProvider() { + return makeAllMaps().iterator(); + } + + @DataProvider(name = "Nulls Map<IntegerEnum,String>", parallel = true) + public static Iterator<Object[]> allMapProvider() { + return makeRWMaps(true).iterator(); + } + + @DataProvider(name = "R/W Map<IntegerEnum,String>", parallel = true) + public static Iterator<Object[]> rwMapProvider() { + return makeRWMapsNoNulls().iterator(); + } + + @DataProvider(name = "R/W Nulls Map<IntegerEnum,String>", parallel = true) + public static Iterator<Object[]> rwNullsMapProvider() { + return makeRWMaps(true).iterator(); + } + + private static Collection<Object[]> makeAllMapsNoNulls() { + Collection<Object[]> all = new ArrayList<>(); + + all.addAll(makeRWMaps(false)); + all.addAll(makeRWNoNullsMaps()); + all.addAll(makeROMaps(false)); + + return all; + } + + private static Collection<Object[]> makeRWMapsNoNulls() { + Collection<Object[]> all = new ArrayList<>(); + + all.addAll(makeRWMaps(false)); + all.addAll(makeRWNoNullsMaps()); + + return all; + } + + private static Collection<Object[]> makeAllMaps() { + Collection<Object[]> all = new ArrayList<>(); + + all.addAll(makeROMaps(false)); + all.addAll(makeRWMaps(false)); + all.addAll(makeRWNoNullsMaps()); + all.addAll(makeRWMaps(true)); + all.addAll(makeROMaps(true)); + + return all; + } + + private static Collection<Object[]> makeAllRWMaps() { + Collection<Object[]> all = new ArrayList<>(); + + all.addAll(makeRWMaps(false)); + all.addAll(makeRWNoNullsMaps()); + all.addAll(makeRWMaps(true)); + + return all; + } + + private static Collection<Object[]> makeRWMaps(boolean nulls) { + return Arrays.asList( + new Object[]{"HashMap", makeMap(HashMap::new, nulls)}, + new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nulls)}, + new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nulls)}, + new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nulls)}, + new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nulls), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nulls))}, + new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nulls)}); + } + + private static Collection<Object[]> makeRWNoNullsMaps() { + return Arrays.asList( + // null hostile + new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false)}, + new Object[]{"Hashtable", makeMap(Hashtable::new, false)}, + new Object[]{"TreeMap", makeMap(TreeMap::new, false)}, + new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false)}, + new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false)}, + new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false))}, + new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false)}); + } + + private static Collection<Object[]> makeROMaps(boolean nulls) { + return Arrays.asList(new Object[][]{ + new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls))} + }); + } + + private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nulls) { + Map<IntegerEnum, String> result = supplier.get(); + + for (int each = 0; each < TEST_SIZE; each++) { + if (nulls) { + result.put((each == 0) ? null : KEYS[each], null); + } else { + result.put(KEYS[each], VALUES[each]); + } + } + + return result; + } + + public interface Thrower<T extends Throwable> { + + public void run() throws T; + } + + public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) { + assertThrows(thrower, throwable, null); + } + + public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) { + Throwable result; + try { + thrower.run(); + result = null; + } catch (Throwable caught) { + result = caught; + } + + assertInstance(result, throwable, + (null != message) + ? message + : "Failed to throw " + throwable.getCanonicalName()); + } + + public static <T> void assertInstance(T actual, Class<? extends T> expected) { + assertInstance(expected.isInstance(actual), null); + } + + public static <T> void assertInstance(T actual, Class<? extends T> expected, String message) { + assertTrue(expected.isInstance(actual), message); + } + + /** + * A simple mutable map implementation that provides only default + * implementations of all methods. ie. none of the Map interface default + * methods have overridden implementations. + * + * @param <K> Type of keys + * @param <V> Type of values + */ + public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K, V> { + + protected final M map; + + public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); } + + protected ExtendsAbstractMap(M map) { this.map = map; } + + public Set<Map.Entry<K, V>> entrySet() { + return new AbstractSet<Map.Entry<K, V>>() { + public int size() { + return map.size(); + } + + public Iterator<Map.Entry<K,V>> iterator() { + final Iterator<Map.Entry<K,V>> source = map.entrySet().iterator(); + return new Iterator<Map.Entry<K,V>>() { + public boolean hasNext() { return source.hasNext(); } + public Map.Entry<K,V> next() { return source.next(); } + public void remove() { source.remove(); } + }; + } + + public boolean add(Map.Entry<K,V> e) { + return map.entrySet().add(e); + } + }; + } + + public V put(K key, V value) { + return map.put(key, value); + } + } + + /** + * A simple mutable concurrent map implementation that provides only default + * implementations of all methods. ie. none of the ConcurrentMap interface + * default methods have overridden implementations. + * + * @param <K> Type of keys + * @param <V> Type of values + */ + public static class ImplementsConcurrentMap<K, V> extends ExtendsAbstractMap<ConcurrentMap<K,V>, K, V> implements ConcurrentMap<K,V> { + public ImplementsConcurrentMap() { super(new ConcurrentHashMap<K,V>()); } + + // ConcurrentMap reabstracts these methods + + public V replace(K k, V v) { return map.replace(k, v); }; + + public boolean replace(K k, V v, V vv) { return map.replace(k, v, vv); }; + + public boolean remove(Object k, Object v) { return map.remove(k, v); } + + public V putIfAbsent(K k, V v) { return map.putIfAbsent(k, v); } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.tools.classfile.*; +import com.sun.tools.jdeps.ClassFileReader; +import static com.sun.tools.classfile.ConstantPool.*; +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; + +/* + * @test + * @bug 8010117 + * @summary Verify if CallerSensitive methods are annotated with + * sun.reflect.CallerSensitive annotation + * @build CallerSensitiveFinder MethodFinder + * @run main/othervm/timeout=900 -mx600m CallerSensitiveFinder + */ +public class CallerSensitiveFinder extends MethodFinder { + private static int numThreads = 3; + private static boolean verbose = false; + public static void main(String[] args) throws Exception { + List<Path> classes = new ArrayList<>(); + String testclasses = System.getProperty("test.classes", "."); + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-v")) { + verbose = true; + } else { + Path p = Paths.get(testclasses, arg); + if (!p.toFile().exists()) { + throw new IllegalArgumentException(arg + " does not exist"); + } + classes.add(p); + } + } + if (classes.isEmpty()) { + classes.addAll(PlatformClassPath.getJREClasses()); + } + final String method = "sun/reflect/Reflection.getCallerClass"; + CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method); + + List<String> errors = csfinder.run(classes); + if (!errors.isEmpty()) { + throw new RuntimeException(errors.size() + + " caller-sensitive methods are missing @CallerSensitive annotation"); + } + } + + private final List<String> csMethodsMissingAnnotation = new ArrayList<>(); + public CallerSensitiveFinder(String... methods) { + super(methods); + } + + public List<String> run(List<Path> classes) throws IOException, InterruptedException, + ExecutionException, ConstantPoolException + { + ExecutorService pool = Executors.newFixedThreadPool(numThreads); + for (Path path : classes) { + ClassFileReader reader = ClassFileReader.newInstance(path.toFile()); + for (ClassFile cf : reader.getClassFiles()) { + String classFileName = cf.getName(); + // for each ClassFile + // parse constant pool to find matching method refs + // parse each method (caller) + // - visit and find method references matching the given method name + pool.submit(getTask(cf)); + } + } + waitForCompletion(); + pool.shutdown(); + return csMethodsMissingAnnotation; + } + + private static final String CALLER_SENSITIVE_ANNOTATION = "Lsun/reflect/CallerSensitive;"; + private static boolean isCallerSensitive(Method m, ConstantPool cp) + throws ConstantPoolException + { + RuntimeAnnotations_attribute attr = + (RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations); + int index = 0; + if (attr != null) { + for (int i = 0; i < attr.annotations.length; i++) { + Annotation ann = attr.annotations[i]; + String annType = cp.getUTF8Value(ann.type_index); + if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) { + return true; + } + } + } + return false; + } + + public void referenceFound(ClassFile cf, Method m, Set<Integer> refs) + throws ConstantPoolException + { + String name = String.format("%s#%s %s", cf.getName(), + m.getName(cf.constant_pool), + m.descriptor.getValue(cf.constant_pool)); + if (!CallerSensitiveFinder.isCallerSensitive(m, cf.constant_pool)) { + csMethodsMissingAnnotation.add(name); + System.err.println("Missing @CallerSensitive: " + name); + } else { + if (verbose) { + System.out.format("@CS %s%n", name); + } + } + } + + private final List<FutureTask<String>> tasks = new ArrayList<FutureTask<String>>(); + private FutureTask<String> getTask(final ClassFile cf) { + FutureTask<String> task = new FutureTask<String>(new Callable<String>() { + public String call() throws Exception { + return parse(cf); + } + }); + tasks.add(task); + return task; + } + + private void waitForCompletion() throws InterruptedException, ExecutionException { + for (FutureTask<String> t : tasks) { + String s = t.get(); + } + System.out.println("Parsed " + tasks.size() + " classfiles"); + } + + static class PlatformClassPath { + static List<Path> getJREClasses() throws IOException { + List<Path> result = new ArrayList<Path>(); + Path home = Paths.get(System.getProperty("java.home")); + + if (home.endsWith("jre")) { + // jar files in <javahome>/jre/lib + // skip <javahome>/lib + result.addAll(addJarFiles(home.resolve("lib"))); + } else if (home.resolve("lib").toFile().exists()) { + // either a JRE or a jdk build image + File classes = home.resolve("classes").toFile(); + if (classes.exists() && classes.isDirectory()) { + // jdk build outputdir + result.add(classes.toPath()); + } + // add other JAR files + result.addAll(addJarFiles(home.resolve("lib"))); + } else { + throw new RuntimeException("\"" + home + "\" not a JDK home"); + } + return result; + } + + static List<Path> addJarFiles(final Path root) throws IOException { + final List<Path> result = new ArrayList<Path>(); + final Path ext = root.resolve("ext"); + Files.walkFileTree(root, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + throws IOException { + if (dir.equals(root) || dir.equals(ext)) { + return FileVisitResult.CONTINUE; + } else { + // skip other cobundled JAR files + return FileVisitResult.SKIP_SUBTREE; + } + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + File f = file.toFile(); + String fn = f.getName(); + // parse alt-rt.jar as well + if (fn.endsWith(".jar") && !fn.equals("jfxrt.jar")) { + result.add(file); + } + return FileVisitResult.CONTINUE; + } + }); + return result; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/CallerSensitive/MethodFinder.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.*; +import com.sun.tools.classfile.*; +import static com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.Instruction.TypeKind; + +/** + * MethodFinder utility class to find references to the given methods. + */ +public abstract class MethodFinder { + final List<String> methods; + public MethodFinder(String... methods) { + this.methods = Arrays.asList(methods); + } + + /** + * A callback method will be invoked when a method referencing + * any of the lookup methods. + * + * @param cf ClassFile + * @param m Method + * @param refs Set of constant pool indices that reference the methods + * matching the given lookup method names + */ + public abstract void referenceFound(ClassFile cf, Method m, Set<Integer> refs) + throws ConstantPoolException; + + public String parse(ClassFile cf) throws ConstantPoolException { + List<Integer> cprefs = new ArrayList<Integer>(); + int index = 1; + for (ConstantPool.CPInfo cpInfo : cf.constant_pool.entries()) { + if (cpInfo.accept(cpVisitor, null)) { + cprefs.add(index); + } + index += cpInfo.size(); + } + + if (!cprefs.isEmpty()) { + for (Method m : cf.methods) { + Set<Integer> refs = new HashSet<Integer>(); + Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); + if (c_attr != null) { + for (Instruction instr : c_attr.getInstructions()) { + int idx = instr.accept(codeVisitor, cprefs); + if (idx > 0) { + refs.add(idx); + } + } + } + if (refs.size() > 0) { + referenceFound(cf, m, refs); + } + } + } + return cprefs.isEmpty() ? "" : cf.getName(); + } + + private ConstantPool.Visitor<Boolean,Void> cpVisitor = + new ConstantPool.Visitor<Boolean,Void>() + { + private boolean matches(CPRefInfo info) { + try { + CONSTANT_NameAndType_info nat = info.getNameAndTypeInfo(); + return matches(info.getClassName(), nat.getName(), nat.getType()); + } catch (ConstantPoolException ex) { + return false; + } + } + + private boolean matches(String cn, String name, String type) { + return methods.contains(cn + "." + name); + } + + public Boolean visitClass(CONSTANT_Class_info info, Void p) { + return false; + } + + public Boolean visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + return matches(info); + } + + public Boolean visitMethodref(CONSTANT_Methodref_info info, Void p) { + return matches(info); + } + + public Boolean visitDouble(CONSTANT_Double_info info, Void p) { + return false; + } + + public Boolean visitFieldref(CONSTANT_Fieldref_info info, Void p) { + return false; + } + + public Boolean visitFloat(CONSTANT_Float_info info, Void p) { + return false; + } + + public Boolean visitInteger(CONSTANT_Integer_info info, Void p) { + return false; + } + + public Boolean visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) { + return false; + } + + public Boolean visitLong(CONSTANT_Long_info info, Void p) { + return false; + } + + public Boolean visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + return false; + } + + public Boolean visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) { + return false; + } + + public Boolean visitMethodType(CONSTANT_MethodType_info info, Void p) { + return false; + } + + public Boolean visitString(CONSTANT_String_info info, Void p) { + return false; + } + + public Boolean visitUtf8(CONSTANT_Utf8_info info, Void p) { + return false; + } + }; + + private Instruction.KindVisitor<Integer, List<Integer>> codeVisitor = + new Instruction.KindVisitor<Integer, List<Integer>>() + { + public Integer visitNoOperands(Instruction instr, List<Integer> p) { + return 0; + } + + public Integer visitArrayType(Instruction instr, TypeKind kind, List<Integer> p) { + return 0; + } + + public Integer visitBranch(Instruction instr, int offset, List<Integer> p) { + return 0; + } + + public Integer visitConstantPoolRef(Instruction instr, int index, List<Integer> p) { + return p.contains(index) ? index : 0; + } + + public Integer visitConstantPoolRefAndValue(Instruction instr, int index, int value, List<Integer> p) { + return p.contains(index) ? index : 0; + } + + public Integer visitLocal(Instruction instr, int index, List<Integer> p) { + return 0; + } + + public Integer visitLocalAndValue(Instruction instr, int index, int value, List<Integer> p) { + return 0; + } + + public Integer visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, List<Integer> p) { + return 0; + } + + public Integer visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, List<Integer> p) { + return 0; + } + + public Integer visitValue(Instruction instr, int value, List<Integer> p) { + return 0; + } + + public Integer visitUnknown(Instruction instr, List<Integer> p) { + return 0; + } + }; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * @bug 8010117 + * @summary Test CallerSensitiveFinder to find missing annotation + * @compile -XDignore.symbol.file MissingCallerSensitive.java + * @build CallerSensitiveFinder MethodFinder + * @run main MissingCallerSensitive + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +public class MissingCallerSensitive { + public static void main(String[] args) throws Exception { + String testclasses = System.getProperty("test.classes", "."); + List<Path> classes = new ArrayList<>(); + classes.add(Paths.get(testclasses, "MissingCallerSensitive.class")); + + final String method = "sun/reflect/Reflection.getCallerClass"; + CallerSensitiveFinder csfinder = new CallerSensitiveFinder(method); + List<String> errors = csfinder.run(classes); + if (errors.size() != 1) { + throw new RuntimeException("Unexpected number of methods found: " + errors.size()); + } + String m = errors.get(0); + if (!m.startsWith("MissingCallerSensitive#missingCallerSensitiveAnnotation")) { + throw new RuntimeException("Unexpected method missing annotation: " + m); + } + } + + @sun.reflect.CallerSensitive + public ClassLoader getCallerLoader() { + Class<?> c = sun.reflect.Reflection.getCallerClass(); + return c.getClassLoader(); + } + + public ClassLoader missingCallerSensitiveAnnotation() { + Class<?> c = sun.reflect.Reflection.getCallerClass(); + return c.getClassLoader(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/Reflection/GetCallerClass.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package boot; + +public class GetCallerClass { + @sun.reflect.CallerSensitive + public ClassLoader getCallerLoader() { + Class<?> c = sun.reflect.Reflection.getCallerClass(); + return c.getClassLoader(); + } + + public ClassLoader missingCallerSensitiveAnnotation() { + Class<?> c = sun.reflect.Reflection.getCallerClass(); + return c.getClassLoader(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/Reflection/GetCallerClassTest.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import boot.GetCallerClass; +import java.lang.reflect.*; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + +public class GetCallerClassTest { + private final GetCallerClass gcc; // boot.GetCallerClass is in bootclasspath + GetCallerClassTest() { + this.gcc = new GetCallerClass(); + } + + public static void main(String[] args) throws Exception { + GetCallerClassTest gcct = new GetCallerClassTest(); + // ensure methods are annotated with @CallerSensitive + ensureAnnotationPresent(boot.GetCallerClass.class, "getCallerLoader", true); + ensureAnnotationPresent(GetCallerClassTest.class, "testNonSystemMethod", false); + // call Reflection.getCallerClass from bootclasspath with and without @CS + gcct.testCallerSensitiveMethods(); + // call Reflection.getCallerClass from classpath with @CS + gcct.testNonSystemMethod(); + } + + private static void ensureAnnotationPresent(Class<?> c, String name, boolean cs) + throws NoSuchMethodException + { + Method m = c.getDeclaredMethod(name); + if (!m.isAnnotationPresent(CallerSensitive.class)) { + throw new RuntimeException("@CallerSensitive not present in method " + m); + } + if (Reflection.isCallerSensitive(m) != cs) { + throw new RuntimeException("Unexpected: isCallerSensitive returns " + + Reflection.isCallerSensitive(m)); + } + } + + private void testCallerSensitiveMethods() { + try { + ClassLoader cl = gcc.getCallerLoader(); + if (cl != GetCallerClassTest.class.getClassLoader()) { + throw new RuntimeException("mismatched class loader"); + } + gcc.missingCallerSensitiveAnnotation(); + throw new RuntimeException("getCallerLoader not marked with @CallerSensitive"); + } catch (InternalError e) { + StackTraceElement[] stackTrace = e.getStackTrace(); + checkStackTrace(stackTrace, e); + if (!stackTrace[1].getClassName().equals(GetCallerClass.class.getName()) || + !stackTrace[1].getMethodName().equals("missingCallerSensitiveAnnotation")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + if (!stackTrace[2].getClassName().equals(GetCallerClassTest.class.getName()) || + !stackTrace[2].getMethodName().equals("testCallerSensitiveMethods")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + System.out.println("Expected error: " + e.getMessage()); + } + } + + @CallerSensitive + private void testNonSystemMethod() { + try { + Class<?> c = Reflection.getCallerClass(); + throw new RuntimeException("@CallerSensitive testNonSystemMethods not supported"); + } catch (InternalError e) { + StackTraceElement[] stackTrace = e.getStackTrace(); + checkStackTrace(stackTrace, e); + if (!stackTrace[1].getClassName().equals(GetCallerClassTest.class.getName()) || + !stackTrace[1].getMethodName().equals("testNonSystemMethod")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + if (!stackTrace[2].getClassName().equals(GetCallerClassTest.class.getName()) || + !stackTrace[2].getMethodName().equals("main")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + System.out.println("Expected error: " + e.getMessage()); + } + } + + private void checkStackTrace(StackTraceElement[] stackTrace, Error e) { + if (stackTrace.length < 3) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + + if (!stackTrace[0].getClassName().equals("sun.reflect.Reflection") || + !stackTrace[0].getMethodName().equals("getCallerClass")) { + throw new RuntimeException("Unexpected error: " + e.getMessage(), e); + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/reflect/Reflection/GetCallerClassTest.sh Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,68 @@ +# +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code 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 +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 8010117 +# @summary Test if the VM enforces sun.reflect.Reflection.getCallerClass +# be called by methods annotated with sun.reflect.CallerSensitive +# +# @run shell GetCallerClassTest.sh + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTSRC=${TESTSRC}" +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTJAVA=${TESTJAVA}" +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +BCP=${TESTCLASSES}/bcp +rm -rf ${BCP} +mkdir ${BCP} + +# Compile GetCallerClass in bootclasspath +${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \ + -XDignore.symbol.file \ + -d ${BCP} ${TESTSRC}/GetCallerClass.java || exit 1 + +${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \ + -XDignore.symbol.file -Xbootclasspath/a:${BCP} \ + -d ${TESTCLASSES} ${TESTSRC}/GetCallerClassTest.java || exit 2 + +${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbootclasspath/a:${BCP} \ + -cp ${TESTCLASSES} GetCallerClassTest || exit 3
--- a/test/sun/security/krb5/MicroTime.java Tue Apr 16 05:32:39 2013 -0700 +++ b/test/sun/security/krb5/MicroTime.java Wed Apr 17 02:53:02 2013 -0700 @@ -22,7 +22,7 @@ */ /* * @test - * @bug 6882687 + * @bug 6882687 8011124 * @summary KerberosTime too imprecise */ @@ -32,11 +32,11 @@ public static void main(String[] args) throws Exception { // We count how many different KerberosTime values // can be acquired within one second. - KerberosTime t1 = new KerberosTime(true); + KerberosTime t1 = KerberosTime.now(); KerberosTime last = t1; int count = 0; while (true) { - KerberosTime t2 = new KerberosTime(true); + KerberosTime t2 = KerberosTime.now(); if (t2.getTime() - t1.getTime() > 1000) break; if (!last.equals(t2)) { last = t2;